Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8db52ef168 | |||
| 38ca250242 | |||
| f4542cd0b8 | |||
| d1e779bbcc | |||
| acfbb4c54e |
@@ -77,7 +77,8 @@ export const syncOaDepartment = (
|
|||||||
size = 20,
|
size = 20,
|
||||||
signal,
|
signal,
|
||||||
incremental = false,
|
incremental = false,
|
||||||
modifiedSince
|
modifiedSince,
|
||||||
|
companyOaId
|
||||||
) => {
|
) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/dept/sync-oa-department',
|
url: '/blade-system/dept/sync-oa-department',
|
||||||
@@ -87,6 +88,7 @@ export const syncOaDepartment = (
|
|||||||
size,
|
size,
|
||||||
incremental: !!incremental,
|
incremental: !!incremental,
|
||||||
modifiedSince: modifiedSince || undefined,
|
modifiedSince: modifiedSince || undefined,
|
||||||
|
companyOaId: companyOaId || undefined,
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
signal,
|
signal,
|
||||||
|
|||||||
@@ -97,7 +97,8 @@ export const config = {
|
|||||||
action: 'startChange',
|
action: 'startChange',
|
||||||
label: '变更',
|
label: '变更',
|
||||||
statusProp: 'approvalStatus',
|
statusProp: 'approvalStatus',
|
||||||
status: ['approved'],
|
// 立项通过、变更通过后均可再次发起变更
|
||||||
|
status: ['approved', 'change_approved'],
|
||||||
permission: 'project_apply_change',
|
permission: 'project_apply_change',
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@@ -224,7 +224,7 @@
|
|||||||
placeholder="请选择"
|
placeholder="请选择"
|
||||||
filterable
|
filterable
|
||||||
clearable
|
clearable
|
||||||
:disabled="isBasicInfoReadonly"
|
:disabled="dialogReadonly"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
<el-form-item label="平台公司" prop="undertakeDeptId">
|
<el-form-item label="平台公司" prop="undertakeDeptId">
|
||||||
@@ -236,7 +236,7 @@
|
|||||||
collapse-tags-tooltip
|
collapse-tags-tooltip
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
:disabled="isBasicInfoReadonly"
|
:disabled="dialogReadonly"
|
||||||
@change="handleUndertakeDeptChange"
|
@change="handleUndertakeDeptChange"
|
||||||
>
|
>
|
||||||
<el-option
|
<el-option
|
||||||
@@ -2493,7 +2493,8 @@ export default {
|
|||||||
loadDeptOptions() {
|
loadDeptOptions() {
|
||||||
getDeptTree().then(res => {
|
getDeptTree().then(res => {
|
||||||
const deptTree = res.data.data || [];
|
const deptTree = res.data.data || [];
|
||||||
const businessDeptTree = ['add', 'edit', 'majorSupplement'].includes(this.dialogType)
|
// 新增/编辑/重大补录/项目变更均可选择业务部门,排除外部组织
|
||||||
|
const businessDeptTree = ['add', 'edit', 'majorSupplement', 'change'].includes(this.dialogType)
|
||||||
? this.excludeExternalOrganization(deptTree)
|
? this.excludeExternalOrganization(deptTree)
|
||||||
: deptTree;
|
: deptTree;
|
||||||
this.deptOptions = this.flattenDept(businessDeptTree);
|
this.deptOptions = this.flattenDept(businessDeptTree);
|
||||||
|
|||||||
@@ -1278,10 +1278,13 @@ export default {
|
|||||||
delete snapshot._externalKey;
|
delete snapshot._externalKey;
|
||||||
delete snapshot.feeItems;
|
delete snapshot.feeItems;
|
||||||
snapshot.feeItemsJson = row.feeItemsJson || JSON.stringify(row.feeItems || {});
|
snapshot.feeItemsJson = row.feeItemsJson || JSON.stringify(row.feeItems || {});
|
||||||
|
snapshot.actualDepartureTime = this.normalizeExternalDateTime(row.actualDepartureTime);
|
||||||
|
snapshot.actualCompletionTime = this.normalizeExternalDateTime(row.actualCompletionTime);
|
||||||
return snapshot;
|
return snapshot;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
serializeExternalRows() {
|
serializeExternalRows() {
|
||||||
|
const duplicateIds = new Set(this.duplicateRows.map(row => String(row.id)));
|
||||||
return this.externalDetails.map(row => {
|
return this.externalDetails.map(row => {
|
||||||
const snapshot = { ...row };
|
const snapshot = { ...row };
|
||||||
delete snapshot._sourceRows;
|
delete snapshot._sourceRows;
|
||||||
@@ -1290,6 +1293,7 @@ export default {
|
|||||||
snapshot.feeItemsJson = row.feeItemsJson || JSON.stringify(row.feeItems || {});
|
snapshot.feeItemsJson = row.feeItemsJson || JSON.stringify(row.feeItems || {});
|
||||||
snapshot.actualDepartureTime = this.normalizeExternalDateTime(row.actualDepartureTime);
|
snapshot.actualDepartureTime = this.normalizeExternalDateTime(row.actualDepartureTime);
|
||||||
snapshot.actualCompletionTime = this.normalizeExternalDateTime(row.actualCompletionTime);
|
snapshot.actualCompletionTime = this.normalizeExternalDateTime(row.actualCompletionTime);
|
||||||
|
snapshot.suspectedDuplicate = duplicateIds.has(String(row.id));
|
||||||
return snapshot;
|
return snapshot;
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
@@ -1336,6 +1340,11 @@ export default {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
async handleComplete() {
|
async handleComplete() {
|
||||||
|
const unmatchedInternal = this.internalDetails.filter(item => item.matchResult !== 'matched').length;
|
||||||
|
const unmatchedExternal = this.externalDetails.filter(item => item.matchStatus !== 'matched').length;
|
||||||
|
if (this.duplicateRows.length || unmatchedInternal || unmatchedExternal) {
|
||||||
|
return this.$message.warning('所有内外部账单明细必须一一匹配且不存在疑似重复');
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
Number(this.form.differenceCount || 0) !== 0 ||
|
Number(this.form.differenceCount || 0) !== 0 ||
|
||||||
Number(this.form.differenceQuantity || 0) !== 0 ||
|
Number(this.form.differenceQuantity || 0) !== 0 ||
|
||||||
@@ -1694,8 +1703,11 @@ export default {
|
|||||||
},
|
},
|
||||||
normalizeExternalDateTime(value) {
|
normalizeExternalDateTime(value) {
|
||||||
if (!value) return null;
|
if (!value) return null;
|
||||||
const text = String(value);
|
const text = String(value).trim();
|
||||||
return text.length === 10 ? `${text}T00:00:00` : text;
|
if (!text) return null;
|
||||||
|
const date = this.$dayjs(text);
|
||||||
|
if (date.isValid()) return date.format('YYYY-MM-DD HH:mm:ss');
|
||||||
|
return text.length === 10 ? `${text} 00:00:00` : text.replace('T', ' ');
|
||||||
},
|
},
|
||||||
refreshLocalStats() {
|
refreshLocalStats() {
|
||||||
const internalQuantity = this.internalDetails.reduce(
|
const internalQuantity = this.internalDetails.reduce(
|
||||||
|
|||||||
+101
-35
@@ -153,7 +153,12 @@
|
|||||||
/>
|
/>
|
||||||
<div class="oa-sync-meta" v-if="oaSyncStage === 'clear'">当前阶段:{{ oaSyncStageLabel }}</div>
|
<div class="oa-sync-meta" v-if="oaSyncStage === 'clear'">当前阶段:{{ oaSyncStageLabel }}</div>
|
||||||
<div class="oa-sync-meta" v-else>
|
<div class="oa-sync-meta" v-else>
|
||||||
当前阶段:{{ oaSyncStageLabel }},第 {{ oaSyncProgress.current || 0 }} / {{ oaSyncTotalPage }} 页
|
当前阶段:{{ oaSyncStageLabel }}
|
||||||
|
<template v-if="oaSyncStage === 'department' && oaSyncProgress.companyTotal">
|
||||||
|
,公司 {{ oaSyncProgress.companyIndex || 0 }} / {{ oaSyncProgress.companyTotal }}
|
||||||
|
<template v-if="oaSyncProgress.companyOaId">(oaId={{ oaSyncProgress.companyOaId }})</template>
|
||||||
|
</template>
|
||||||
|
,第 {{ oaSyncProgress.current || 0 }} / {{ oaSyncTotalPage }} 页
|
||||||
</div>
|
</div>
|
||||||
<div class="oa-sync-stats">
|
<div class="oa-sync-stats">
|
||||||
<div class="oa-sync-stat">
|
<div class="oa-sync-stat">
|
||||||
@@ -257,6 +262,9 @@ export default {
|
|||||||
synced: 0,
|
synced: 0,
|
||||||
skipped: 0,
|
skipped: 0,
|
||||||
dumpFilePath: '',
|
dumpFilePath: '',
|
||||||
|
companyOaId: '',
|
||||||
|
companyIndex: 0,
|
||||||
|
companyTotal: 0,
|
||||||
},
|
},
|
||||||
parentId: 0,
|
parentId: 0,
|
||||||
page: {
|
page: {
|
||||||
@@ -290,7 +298,9 @@ export default {
|
|||||||
{
|
{
|
||||||
label: '组织名称',
|
label: '组织名称',
|
||||||
prop: 'deptName',
|
prop: 'deptName',
|
||||||
minWidth: 160,
|
minWidth: 320,
|
||||||
|
align: 'left',
|
||||||
|
headerAlign: 'left',
|
||||||
order: 80,
|
order: 80,
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
@@ -642,12 +652,18 @@ export default {
|
|||||||
}
|
}
|
||||||
const totalPage = this.oaSyncTotalPage;
|
const totalPage = this.oaSyncTotalPage;
|
||||||
const current = Number(this.oaSyncProgress.current) || 0;
|
const current = Number(this.oaSyncProgress.current) || 0;
|
||||||
const stageBase = this.oaSyncStage === 'department' ? 50 : 0;
|
if (this.oaSyncStage === 'department') {
|
||||||
if (totalPage <= 0) {
|
const companyTotal = Math.max(1, Number(this.oaSyncProgress.companyTotal) || 1);
|
||||||
return stageBase;
|
const companyIndex = Math.max(1, Number(this.oaSyncProgress.companyIndex) || 1);
|
||||||
|
const companyBase = ((companyIndex - 1) / companyTotal) * 50;
|
||||||
|
const pageRatio = totalPage > 0 ? Math.min(1, current / totalPage) : 0;
|
||||||
|
const companyPagePercent = (pageRatio * 50) / companyTotal;
|
||||||
|
return Math.min(99, Math.round(50 + companyBase + companyPagePercent));
|
||||||
}
|
}
|
||||||
const stagePercent = Math.min(50, Math.round((current / totalPage) * 50));
|
if (totalPage <= 0) {
|
||||||
return Math.min(99, stageBase + stagePercent);
|
return 0;
|
||||||
|
}
|
||||||
|
return Math.min(49, Math.round((current / totalPage) * 50));
|
||||||
},
|
},
|
||||||
oaSyncProgressStatus() {
|
oaSyncProgressStatus() {
|
||||||
if (this.oaSyncStatus === 'done') {
|
if (this.oaSyncStatus === 'done') {
|
||||||
@@ -661,25 +677,7 @@ export default {
|
|||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleOaOrgFullSync() {
|
handleOaOrgFullSync() {
|
||||||
this.$confirm(
|
this.startOaOrgSync({ clearNonTop: false, incremental: false });
|
||||||
'全量同步将拉取 OA 公司/部门(仅保留二级公司 oaId=2、135 及其子公司与部门);已存在且 OA 更新时间一致的记录会跳过。是否清除后同步?选择“是”将保留顶级「外部组织」与集团锚点(id=1/GWWL),删除其余组织后再同步;选择“否”则直接全量同步。',
|
|
||||||
'全量同步',
|
|
||||||
{
|
|
||||||
confirmButtonText: '是',
|
|
||||||
cancelButtonText: '否',
|
|
||||||
distinguishCancelAndClose: true,
|
|
||||||
closeOnClickModal: false,
|
|
||||||
type: 'warning',
|
|
||||||
}
|
|
||||||
)
|
|
||||||
.then(() => {
|
|
||||||
this.startOaOrgSync({ clearNonTop: true, incremental: false });
|
|
||||||
})
|
|
||||||
.catch(action => {
|
|
||||||
if (action === 'cancel') {
|
|
||||||
this.startOaOrgSync({ clearNonTop: false, incremental: false });
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
handleOaOrgIncrementalSync() {
|
handleOaOrgIncrementalSync() {
|
||||||
this.$confirm(
|
this.$confirm(
|
||||||
@@ -714,6 +712,9 @@ export default {
|
|||||||
synced: 0,
|
synced: 0,
|
||||||
skipped: 0,
|
skipped: 0,
|
||||||
dumpFilePath: '',
|
dumpFilePath: '',
|
||||||
|
companyOaId: '',
|
||||||
|
companyIndex: 0,
|
||||||
|
companyTotal: 0,
|
||||||
};
|
};
|
||||||
this.runOaOrgSyncPages();
|
this.runOaOrgSyncPages();
|
||||||
},
|
},
|
||||||
@@ -725,6 +726,25 @@ export default {
|
|||||||
error?.name === 'AbortError'
|
error?.name === 'AbortError'
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
applyOaOrgSyncPage(page, current, size) {
|
||||||
|
this.oaSyncProgress.current = page.current || current;
|
||||||
|
this.oaSyncProgress.size = page.size || size;
|
||||||
|
this.oaSyncProgress.total = page.total || 0;
|
||||||
|
this.oaSyncProgress.synced += page.syncedCount || 0;
|
||||||
|
this.oaSyncProgress.skipped += page.skippedCount || 0;
|
||||||
|
if (page.dumpFilePath) {
|
||||||
|
this.oaSyncProgress.dumpFilePath = page.dumpFilePath;
|
||||||
|
}
|
||||||
|
if (page.companyOaId != null) {
|
||||||
|
this.oaSyncProgress.companyOaId = page.companyOaId || '';
|
||||||
|
}
|
||||||
|
if (page.companyIndex != null) {
|
||||||
|
this.oaSyncProgress.companyIndex = page.companyIndex || 0;
|
||||||
|
}
|
||||||
|
if (page.companyTotal != null) {
|
||||||
|
this.oaSyncProgress.companyTotal = page.companyTotal || 0;
|
||||||
|
}
|
||||||
|
},
|
||||||
async runOaOrgSyncStage(syncApi) {
|
async runOaOrgSyncStage(syncApi) {
|
||||||
const size = 20;
|
const size = 20;
|
||||||
const incremental = this.oaSyncMode === 'incremental';
|
const incremental = this.oaSyncMode === 'incremental';
|
||||||
@@ -742,20 +762,57 @@ export default {
|
|||||||
if (!modifiedSince && page.modifiedSince) {
|
if (!modifiedSince && page.modifiedSince) {
|
||||||
modifiedSince = page.modifiedSince;
|
modifiedSince = page.modifiedSince;
|
||||||
}
|
}
|
||||||
this.oaSyncProgress.current = page.current || current;
|
this.applyOaOrgSyncPage(page, current, size);
|
||||||
this.oaSyncProgress.size = page.size || size;
|
|
||||||
this.oaSyncProgress.total = page.total || 0;
|
|
||||||
this.oaSyncProgress.synced += page.syncedCount || 0;
|
|
||||||
this.oaSyncProgress.skipped += page.skippedCount || 0;
|
|
||||||
if (page.dumpFilePath) {
|
|
||||||
this.oaSyncProgress.dumpFilePath = page.dumpFilePath;
|
|
||||||
}
|
|
||||||
if (page.finished) {
|
if (page.finished) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
current += 1;
|
current += 1;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
/**
|
||||||
|
* 部门阶段:公司同步完成后,按公司 oaId 轮询;当前公司部门拉完后切换下一公司并重置页码
|
||||||
|
*/
|
||||||
|
async runOaOrgDepartmentSyncStage() {
|
||||||
|
const size = 20;
|
||||||
|
const incremental = this.oaSyncMode === 'incremental';
|
||||||
|
let current = 1;
|
||||||
|
let modifiedSince = '';
|
||||||
|
let companyOaId = '';
|
||||||
|
while (!this.oaSyncCancelled) {
|
||||||
|
const res = await syncOaDepartment(
|
||||||
|
current,
|
||||||
|
size,
|
||||||
|
this.oaSyncController?.signal,
|
||||||
|
incremental,
|
||||||
|
modifiedSince,
|
||||||
|
companyOaId
|
||||||
|
);
|
||||||
|
const page = res?.data?.data || {};
|
||||||
|
if (!modifiedSince && page.modifiedSince) {
|
||||||
|
modifiedSince = page.modifiedSince;
|
||||||
|
}
|
||||||
|
if (page.companyOaId) {
|
||||||
|
companyOaId = page.companyOaId;
|
||||||
|
}
|
||||||
|
this.applyOaOrgSyncPage(page, current, size);
|
||||||
|
if (page.finished) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (page.companyFinished && page.nextCompanyOaId) {
|
||||||
|
companyOaId = page.nextCompanyOaId;
|
||||||
|
current = 1;
|
||||||
|
this.oaSyncProgress.current = 0;
|
||||||
|
this.oaSyncProgress.total = 0;
|
||||||
|
// 单公司部门拉完并重建层级后刷新树,便于中途核对挂载结果
|
||||||
|
this.parentId = 0;
|
||||||
|
this.data = [];
|
||||||
|
this.$refs.crud?.refreshTable?.();
|
||||||
|
this.onLoad(this.page, this.query);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
current += 1;
|
||||||
|
}
|
||||||
|
},
|
||||||
async runOaOrgSyncPages() {
|
async runOaOrgSyncPages() {
|
||||||
try {
|
try {
|
||||||
if (this.oaSyncClearNonTop) {
|
if (this.oaSyncClearNonTop) {
|
||||||
@@ -775,7 +832,10 @@ export default {
|
|||||||
this.oaSyncStage = 'department';
|
this.oaSyncStage = 'department';
|
||||||
this.oaSyncProgress.current = 0;
|
this.oaSyncProgress.current = 0;
|
||||||
this.oaSyncProgress.total = 0;
|
this.oaSyncProgress.total = 0;
|
||||||
await this.runOaOrgSyncStage(syncOaDepartment);
|
this.oaSyncProgress.companyOaId = '';
|
||||||
|
this.oaSyncProgress.companyIndex = 0;
|
||||||
|
this.oaSyncProgress.companyTotal = 0;
|
||||||
|
await this.runOaOrgDepartmentSyncStage();
|
||||||
if (this.oaSyncCancelled) {
|
if (this.oaSyncCancelled) {
|
||||||
this.oaSyncStatus = 'cancelled';
|
this.oaSyncStatus = 'cancelled';
|
||||||
return;
|
return;
|
||||||
@@ -1460,6 +1520,12 @@ export default {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
/* 覆盖全站表格居中:树形组织名称需左对齐,展开后缩进才可读 */
|
||||||
|
:deep(.el-table th.el-table__cell.is-left .cell),
|
||||||
|
:deep(.el-table td.el-table__cell.is-left .cell) {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.carrier-search-form {
|
.carrier-search-form {
|
||||||
padding: 12px 12px 4px;
|
padding: 12px 12px 4px;
|
||||||
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04);
|
||||||
|
|||||||
Reference in New Issue
Block a user