+94
-21
@@ -35,8 +35,16 @@
|
||||
plain
|
||||
:loading="oaSyncLoading"
|
||||
v-if="isAdministrator"
|
||||
@click="handleOaOrgSync"
|
||||
>自动同步组织
|
||||
@click="handleOaOrgFullSync"
|
||||
>全量同步
|
||||
</el-button>
|
||||
<el-button
|
||||
type="primary"
|
||||
plain
|
||||
:loading="oaSyncLoading"
|
||||
v-if="isAdministrator"
|
||||
@click="handleOaOrgIncrementalSync"
|
||||
>增量同步
|
||||
</el-button>
|
||||
</template>
|
||||
<template #menu="scope">
|
||||
@@ -191,10 +199,12 @@ const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
||||
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
||||
/**
|
||||
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
||||
* 与业务字典 organization_type 及历史别名对齐;优先仍以数字 dictKey 为准
|
||||
*/
|
||||
const ORGANIZATION_TYPE_CODE_BY_LABEL = {
|
||||
集团: 1,
|
||||
一级集团: 1,
|
||||
公司: 2,
|
||||
事业部: 2,
|
||||
二级事业部: 2,
|
||||
部门: 3,
|
||||
@@ -234,6 +244,7 @@ export default {
|
||||
oaSyncCancelled: false,
|
||||
oaSyncStatus: 'running',
|
||||
oaSyncStage: 'company',
|
||||
oaSyncMode: 'full',
|
||||
oaSyncClearNonTop: false,
|
||||
oaSyncController: null,
|
||||
oaSyncProgress: {
|
||||
@@ -278,6 +289,7 @@ export default {
|
||||
minWidth: 160,
|
||||
order: 80,
|
||||
search: true,
|
||||
searchOrder: 2,
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
@@ -389,6 +401,8 @@ export default {
|
||||
prop: 'shortName',
|
||||
minWidth: 140,
|
||||
order: 60,
|
||||
search: true,
|
||||
searchOrder: 1,
|
||||
},
|
||||
{
|
||||
label: '助记码',
|
||||
@@ -462,15 +476,33 @@ export default {
|
||||
{
|
||||
label: '排序',
|
||||
prop: 'sort',
|
||||
type: 'number',
|
||||
type: 'input',
|
||||
align: 'right',
|
||||
width: 80,
|
||||
order: 30,
|
||||
change: ({ value }) => {
|
||||
if (value === undefined || value === null || value === '') {
|
||||
return;
|
||||
}
|
||||
const digits = String(value).replace(/\D/g, '');
|
||||
if (String(value) !== digits) {
|
||||
this.form.sort = digits;
|
||||
}
|
||||
},
|
||||
rules: [
|
||||
{
|
||||
required: true,
|
||||
message: '请输入排序',
|
||||
trigger: 'blur',
|
||||
validator: (rule, value, callback) => {
|
||||
if (value === '' || value === undefined || value === null) {
|
||||
callback();
|
||||
return;
|
||||
}
|
||||
if (!/^\d+$/.test(String(value).trim())) {
|
||||
callback(new Error('排序只能输入数字'));
|
||||
return;
|
||||
}
|
||||
callback();
|
||||
},
|
||||
trigger: ['blur', 'change'],
|
||||
},
|
||||
],
|
||||
},
|
||||
@@ -509,12 +541,10 @@ export default {
|
||||
value: 'tenantId',
|
||||
},
|
||||
hide: true,
|
||||
search: website.tenantMode,
|
||||
},
|
||||
{
|
||||
label: '机构全称',
|
||||
prop: 'fullName',
|
||||
search: true,
|
||||
hide: true,
|
||||
addDisplay: false,
|
||||
editDisplay: false,
|
||||
@@ -568,16 +598,17 @@ export default {
|
||||
return ids.join(',');
|
||||
},
|
||||
oaSyncDialogTitle() {
|
||||
const modeLabel = this.oaSyncMode === 'incremental' ? '增量同步' : '全量同步';
|
||||
if (this.oaSyncStatus === 'done') {
|
||||
return '同步完成';
|
||||
return `${modeLabel}完成`;
|
||||
}
|
||||
if (this.oaSyncStatus === 'cancelled') {
|
||||
return '已取消同步';
|
||||
return `已取消${modeLabel}`;
|
||||
}
|
||||
if (this.oaSyncStatus === 'error') {
|
||||
return '同步失败';
|
||||
return `${modeLabel}失败`;
|
||||
}
|
||||
return '自动同步组织';
|
||||
return modeLabel;
|
||||
},
|
||||
oaSyncStageLabel() {
|
||||
if (this.oaSyncStage === 'clear') {
|
||||
@@ -617,10 +648,10 @@ export default {
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
handleOaOrgSync() {
|
||||
handleOaOrgFullSync() {
|
||||
this.$confirm(
|
||||
'是否清除非顶级组织?选择“是”将先删除顶级以外的组织后再同步;选择“否”则直接同步。',
|
||||
'提示',
|
||||
'全量同步将拉取 OA 全部公司/部门;已存在且 OA 更新时间一致的记录会跳过。是否清除非顶级组织?选择“是”将先删除顶级以外的组织后再同步;选择“否”则直接全量同步。',
|
||||
'全量同步',
|
||||
{
|
||||
confirmButtonText: '是',
|
||||
cancelButtonText: '否',
|
||||
@@ -630,20 +661,37 @@ export default {
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.startOaOrgSync(true);
|
||||
this.startOaOrgSync({ clearNonTop: true, incremental: false });
|
||||
})
|
||||
.catch(action => {
|
||||
if (action === 'cancel') {
|
||||
this.startOaOrgSync(false);
|
||||
this.startOaOrgSync({ clearNonTop: false, incremental: false });
|
||||
}
|
||||
});
|
||||
},
|
||||
startOaOrgSync(clearNonTop) {
|
||||
handleOaOrgIncrementalSync() {
|
||||
this.$confirm(
|
||||
'增量同步仅拉取本地最大 OA 更新时间之后有变更的组织;不存在的新增,已存在且更新时间不一致的修改,一致的跳过。是否继续?',
|
||||
'增量同步',
|
||||
{
|
||||
confirmButtonText: '确定',
|
||||
cancelButtonText: '取消',
|
||||
closeOnClickModal: false,
|
||||
type: 'info',
|
||||
}
|
||||
)
|
||||
.then(() => {
|
||||
this.startOaOrgSync({ clearNonTop: false, incremental: true });
|
||||
})
|
||||
.catch(() => {});
|
||||
},
|
||||
startOaOrgSync({ clearNonTop = false, incremental = false } = {}) {
|
||||
this.oaSyncLoading = true;
|
||||
this.oaSyncVisible = true;
|
||||
this.oaSyncRunning = true;
|
||||
this.oaSyncCancelled = false;
|
||||
this.oaSyncStatus = 'running';
|
||||
this.oaSyncMode = incremental ? 'incremental' : 'full';
|
||||
this.oaSyncClearNonTop = !!clearNonTop;
|
||||
this.oaSyncStage = clearNonTop ? 'clear' : 'company';
|
||||
this.oaSyncController = new AbortController();
|
||||
@@ -666,10 +714,21 @@ export default {
|
||||
},
|
||||
async runOaOrgSyncStage(syncApi) {
|
||||
const size = 20;
|
||||
const incremental = this.oaSyncMode === 'incremental';
|
||||
let current = 1;
|
||||
let modifiedSince = '';
|
||||
while (!this.oaSyncCancelled) {
|
||||
const res = await syncApi(current, size, this.oaSyncController?.signal);
|
||||
const res = await syncApi(
|
||||
current,
|
||||
size,
|
||||
this.oaSyncController?.signal,
|
||||
incremental,
|
||||
modifiedSince
|
||||
);
|
||||
const page = res?.data?.data || {};
|
||||
if (!modifiedSince && page.modifiedSince) {
|
||||
modifiedSince = page.modifiedSince;
|
||||
}
|
||||
this.oaSyncProgress.current = page.current || current;
|
||||
this.oaSyncProgress.size = page.size || size;
|
||||
this.oaSyncProgress.total = page.total || 0;
|
||||
@@ -806,7 +865,7 @@ export default {
|
||||
},
|
||||
/**
|
||||
* 业务字典项转下拉选项。后端 deptCategory 为 Integer,value 必须始终为数字。
|
||||
* 优先用数字 dictKey;若 dictKey 配成中文,则按名称映射已知编码。
|
||||
* 优先用数字 dictKey;其次按名称映射;再回退 sort,避免字典项被静默丢弃。
|
||||
*/
|
||||
normalizeOrganizationTypeOption(item) {
|
||||
const label = item?.dictValue ?? item?.label;
|
||||
@@ -833,10 +892,19 @@ export default {
|
||||
value: codeByLabel,
|
||||
};
|
||||
}
|
||||
// 未命中名称映射时,用排序号兜底,保证与业务字典项一致展示
|
||||
const sortNumber = Number(item?.sort);
|
||||
if (!Number.isNaN(sortNumber) && sortNumber >= 1) {
|
||||
return {
|
||||
label: labelText,
|
||||
value: sortNumber,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
},
|
||||
/**
|
||||
* 提交前将组织类型规范为 Integer;空状态字段去掉,避免 "" 反序列化失败。
|
||||
* 提交前将组织类型规范为 Integer;空状态/排序字段去掉,避免 "" 反序列化失败。
|
||||
* 排序为空时由后端默认填充 1。
|
||||
*/
|
||||
prepareDeptSubmitRow(row) {
|
||||
const category = this.resolveDeptCategoryValue(row.deptCategory);
|
||||
@@ -849,6 +917,11 @@ export default {
|
||||
} else {
|
||||
row.status = Number(row.status);
|
||||
}
|
||||
if (row.sort === '' || row.sort === null || row.sort === undefined) {
|
||||
delete row.sort;
|
||||
} else {
|
||||
row.sort = Number(String(row.sort).trim());
|
||||
}
|
||||
return true;
|
||||
},
|
||||
resolveDeptCategoryValue(value) {
|
||||
|
||||
Reference in New Issue
Block a user