diff --git a/src/api/system/dept.js b/src/api/system/dept.js
index 37b1aba..5a489e0 100644
--- a/src/api/system/dept.js
+++ b/src/api/system/dept.js
@@ -57,26 +57,36 @@ export const clearNonTopDept = signal => {
});
};
-export const syncOaCompany = (current = 1, size = 20, signal) => {
+export const syncOaCompany = (current = 1, size = 20, signal, incremental = false, modifiedSince) => {
return request({
url: '/blade-system/dept/sync-oa-company',
method: 'post',
params: {
current,
size,
+ incremental: !!incremental,
+ modifiedSince: modifiedSince || undefined,
},
timeout: 60000,
signal,
});
};
-export const syncOaDepartment = (current = 1, size = 20, signal) => {
+export const syncOaDepartment = (
+ current = 1,
+ size = 20,
+ signal,
+ incremental = false,
+ modifiedSince
+) => {
return request({
url: '/blade-system/dept/sync-oa-department',
method: 'post',
params: {
current,
size,
+ incremental: !!incremental,
+ modifiedSince: modifiedSince || undefined,
},
timeout: 60000,
signal,
diff --git a/src/api/system/user.js b/src/api/system/user.js
index 4e1c8de..ea4484c 100644
--- a/src/api/system/user.js
+++ b/src/api/system/user.js
@@ -31,13 +31,15 @@ export const add = row => {
});
};
-export const syncIamAccounts = (current = 1, size = 50, signal) => {
+export const syncIamAccounts = (current = 1, size = 50, signal, incremental = false, modifiedSince) => {
return request({
url: '/blade-system/user/sync-iam-accounts',
method: 'post',
params: {
current,
size,
+ incremental: !!incremental,
+ modifiedSince: modifiedSince || undefined,
},
timeout: 60000,
signal,
@@ -52,6 +54,17 @@ export const update = row => {
});
};
+export const changeStatus = (id, status) => {
+ return request({
+ url: '/blade-system/user/change-status',
+ method: 'post',
+ params: {
+ id,
+ status,
+ },
+ });
+};
+
export const updatePlatform = (userId, userType, userExt) => {
return request({
url: '/blade-system/user/update-platform',
diff --git a/src/option/system/user.js b/src/option/system/user.js
index 786fa5e..78401f8 100644
--- a/src/option/system/user.js
+++ b/src/option/system/user.js
@@ -27,7 +27,8 @@ export const userOption = safe => {
index: true,
selection: true,
addBtn: false,
- viewBtn: true,
+ viewBtn: false,
+ menuWidth: 160,
dialogType: 'dialog',
dialogWidth: '90%',
labelPosition: 'right',
@@ -37,6 +38,7 @@ export const userOption = safe => {
{
label: '账号名',
prop: 'account',
+ slot: true,
search: true,
searchOrder: 2,
searchPlaceholder: '支持模糊搜索',
@@ -63,7 +65,8 @@ export const userOption = safe => {
label: '所属部门',
prop: 'deptName',
slot: true,
- overHidden: true,
+ minWidth: 200,
+ overHidden: false,
display: false,
},
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
diff --git a/src/views/business/components/contract-attachment-section.vue b/src/views/business/components/contract-attachment-section.vue
index 7302908..e843d8e 100644
--- a/src/views/business/components/contract-attachment-section.vue
+++ b/src/views/business/components/contract-attachment-section.vue
@@ -16,7 +16,7 @@
class="contract-manage-form__attachment-table"
@selection-change="selected = $event"
>
-
+
@@ -726,7 +726,15 @@ export default {
downloadFileByUrl(url, attachmentName(row));
},
batchDownload() {
- (this.selected.length ? this.selected : this.rows || []).forEach(this.download);
+ const sourceRows = this.selected.length ? this.selected : this.rows || [];
+ const downloadableRows = sourceRows.filter(row => attachmentUrl(row));
+ if (!downloadableRows.length) {
+ this.$message.warning(this.selected.length ? '所选附件暂无可下载地址' : '暂无可下载附件');
+ return;
+ }
+ downloadableRows.forEach((row, index) => {
+ window.setTimeout(() => this.download(row), index * 400);
+ });
},
formatSize(size) {
const value = Number(size);
diff --git a/src/views/business/components/waybill-import-dialog.vue b/src/views/business/components/waybill-import-dialog.vue
index acffefa..4a49050 100644
--- a/src/views/business/components/waybill-import-dialog.vue
+++ b/src/views/business/components/waybill-import-dialog.vue
@@ -1666,6 +1666,7 @@ const downloadTemplate = async () => {
ElMessage.error('模板下载失败');
}
};
+const isValidMobile = value => /^\d{11}$/.test(String(value || '').trim());
const validateImportRows = () => {
if (!rows.value.length) {
ElMessage.warning('请上传至少一条运单明细');
@@ -1677,6 +1678,11 @@ const validateImportRows = () => {
ElMessage.warning(`第${index + 1}行${missingField.label}不能为空`);
return false;
}
+ const driverPhone = String(row.driverPhone ?? '').trim();
+ if (driverPhone && !isValidMobile(driverPhone)) {
+ ElMessage.warning(`第${index + 1}行司机/船长手机号格式不正确,应为11位数字`);
+ return false;
+ }
}
return true;
};
diff --git a/src/views/business/contract-manage.vue b/src/views/business/contract-manage.vue
index f6a7e2d..6bc51f7 100644
--- a/src/views/business/contract-manage.vue
+++ b/src/views/business/contract-manage.vue
@@ -1022,7 +1022,7 @@
v-model="detailBillingPlanBox"
:value="detailBillingPlanForm"
:index="detailBillingPlanIndex"
- :settlement-currency="detail.settlementCurrency || form.settlementCurrency"
+ :settlement-currency="detailRow.settlementCurrency || form.settlementCurrency"
readonly
/>
diff --git a/src/views/system/dept.vue b/src/views/system/dept.vue
index 0390616..5b0f951 100644
--- a/src/views/system/dept.vue
+++ b/src/views/system/dept.vue
@@ -35,8 +35,16 @@
plain
:loading="oaSyncLoading"
v-if="isAdministrator"
- @click="handleOaOrgSync"
- >自动同步组织
+ @click="handleOaOrgFullSync"
+ >全量同步
+
+ 增量同步
@@ -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) {
diff --git a/src/views/system/user.vue b/src/views/system/user.vue
index 9c09563..25207e9 100644
--- a/src/views/system/user.vue
+++ b/src/views/system/user.vue
@@ -51,72 +51,31 @@
审 核
+ @click="handleOaPersonFullSync"
+ >全量同步
同步人员
-
- 通 过
-
- 拒 绝
+ @click="handleOaPersonIncrementalSync"
+ >增量同步
返 回
+ v-if="isAdministrator && !auditMode"
+ @click="handleImport"
+ >导入
角色配置
-
-
-
- 数据管理
-
-
-
-
-
- 导入数据
-
-
-
- 导出数据
-
-
-
-
+ @click="handleExport"
+ >导出
+
锁定管理
-
+
+ {{ row.account }}
+
+
查看
-
- 编辑
+ >修改
+
+
+ {{ Number(row.status) === 1 ? '停用' : '启用' }}
- handleDropdownCommand(command, row, index)">
- 更多
-
-
-
- {{ row.isLeader === 1 ? '取消主管' : '设置主管' }}
-
-
- 角色配置
-
-
- 认证日志
-
-
- 锁定账号
-
-
- 密码重置
-
-
- 修改密码
-
-
- 删除用户
-
-
-
-
{{ row.roleName }}
@@ -191,7 +126,7 @@
- {{ userDialogMode === 'add' ? '新增用户' : '编辑用户' }}
+ {{ userDialogTitle }}
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
-
- 仅所属组织全部组织自定义
- 包含下级仅本级
+
+
+ 仅所属组织全部组织自定义
+ 包含下级仅本级
@@ -260,18 +197,28 @@
- 删除
+ 删除
- 包含新增的客商
-
+ 包含新增的客商
+
-
+
+
+
+
@@ -442,6 +389,7 @@ import {
remove,
update,
add,
+ changeStatus,
syncIamAccounts,
grant,
resetPassword,
@@ -494,6 +442,7 @@ export default {
oaSyncRunning: false,
oaSyncCancelled: false,
oaSyncStatus: 'running',
+ oaSyncMode: 'full',
oaSyncController: null,
oaSyncProgress: {
current: 0,
@@ -570,16 +519,17 @@ export default {
computed: {
...mapGetters(['userInfo', 'permission', 'isAdministrator']),
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;
},
oaSyncTotalPage() {
const total = Number(this.oaSyncProgress.total) || 0;
@@ -642,6 +592,18 @@ export default {
this.$refs.userFormRef?.validateField('deptId');
},
},
+ isUserViewMode() {
+ return this.userDialogMode === 'view';
+ },
+ userDialogTitle() {
+ if (this.userDialogMode === 'add') {
+ return '新增用户';
+ }
+ if (this.userDialogMode === 'view') {
+ return '用户详情';
+ }
+ return '编辑用户';
+ },
permissionList() {
return {
addBtn: this.validData(this.permission.user_add, false),
@@ -714,28 +676,35 @@ export default {
this.showResetPassword(res.data.data);
});
},
- handleDataManageCommand(command) {
- if (command === 'import') {
- this.handleImport();
- } else if (command === 'export') {
- this.handleExport();
- }
- },
- handleIamSync() {
- this.$confirm('确定从OA同步人员及组织信息?', '提示', {
+ handleOaPersonFullSync() {
+ this.$confirm('全量同步将拉取 OA 全部人员及组织;已存在且 OA 更新时间一致的记录会跳过。是否继续?', '全量同步', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
}).then(() => {
- this.startOaSync();
+ this.startOaSync(false);
});
},
- startOaSync() {
+ handleOaPersonIncrementalSync() {
+ this.$confirm(
+ '增量同步仅拉取本地最大 OA 更新时间之后有变更的人员;不存在的新增,已存在且更新时间不一致的修改,一致的跳过。是否继续?',
+ '增量同步',
+ {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'info',
+ }
+ ).then(() => {
+ this.startOaSync(true);
+ });
+ },
+ startOaSync(incremental = false) {
this.iamSyncLoading = true;
this.oaSyncVisible = true;
this.oaSyncRunning = true;
this.oaSyncCancelled = false;
this.oaSyncStatus = 'running';
+ this.oaSyncMode = incremental ? 'incremental' : 'full';
this.oaSyncController = new AbortController();
this.oaSyncProgress = {
current: 0,
@@ -756,11 +725,22 @@ export default {
},
async runOaSyncPages() {
const size = 50;
+ const incremental = this.oaSyncMode === 'incremental';
let current = 1;
+ let modifiedSince = '';
try {
while (!this.oaSyncCancelled) {
- const res = await syncIamAccounts(current, size, this.oaSyncController?.signal);
+ const res = await syncIamAccounts(
+ 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;
@@ -892,11 +872,33 @@ export default {
.filter(id => String(id) !== String(roleId));
},
handleDataScopeCheck(_, checked) {
+ if (this.isUserViewMode) {
+ return;
+ }
this.form.dataScopeDeptIds = checked.checkedKeys;
},
handleCustomerSelection(rows) {
+ if (this.isUserViewMode) {
+ return;
+ }
this.form.customerIds = rows.map(row => row.id);
},
+ isCustomerSelectable() {
+ return !this.isUserViewMode;
+ },
+ normalizeSexDisplay(sex) {
+ if (sex === -1 || sex === '-1' || sex === '' || sex === null || sex === undefined) {
+ return undefined;
+ }
+ return Number(sex);
+ },
+ normalizeSexSubmit(sex, clearInvalid = false) {
+ const value = Number(sex);
+ if (value === 1 || value === 2 || value === 3) {
+ return value;
+ }
+ return clearInvalid ? -1 : null;
+ },
formatDeptNames(deptName) {
if (!deptName) {
return [];
@@ -906,6 +908,20 @@ export default {
.map(item => item.trim())
.filter(Boolean);
},
+ handleStatus(row) {
+ const nextStatus = Number(row.status) === 1 ? 0 : 1;
+ const actionName = nextStatus === 1 ? '启用' : '停用';
+ this.$confirm(`确定${actionName}账号【${row.account}】?`, {
+ confirmButtonText: '确定',
+ cancelButtonText: '取消',
+ type: 'warning',
+ })
+ .then(() => changeStatus(row.id, nextStatus))
+ .then(() => {
+ this.onLoad(this.page);
+ this.$message({ type: 'success', message: '操作成功!' });
+ });
+ },
openUserDialog(mode, row = {}) {
this.userDialogMode = mode;
if (mode === 'add') {
@@ -915,7 +931,7 @@ export default {
realName: '',
phone: '',
email: '',
- sex: 3,
+ sex: undefined,
postId: '',
deptId: [],
code: '',
@@ -946,6 +962,7 @@ export default {
personCategory: user.personCategory || 1,
dataScopeRange: user.dataScopeRange || 1,
dataLevelRange: user.dataLevelRange || 1,
+ sex: this.normalizeSexDisplay(user.sex),
};
this.sensitiveManager.saveInitialData(this.form);
this.userDialog = true;
@@ -967,6 +984,7 @@ export default {
postId: func.join(this.form.postId),
roleId: func.join(this.form.roleId),
leaderId: func.join(this.form.leaderId),
+ sex: this.normalizeSexSubmit(this.form.sex, this.userDialogMode !== 'add'),
};
if (this.userDialogMode !== 'add') {
delete row.password;
@@ -987,6 +1005,7 @@ export default {
row.roleId = func.join(row.roleId);
row.postId = func.join(row.postId);
row.leaderId = func.join(row.leaderId);
+ row.sex = this.normalizeSexSubmit(row.sex);
add(row).then(
() => {
this.initFlag = false;
@@ -1008,6 +1027,7 @@ export default {
row.roleId = func.join(row.roleId);
row.postId = func.join(row.postId);
row.leaderId = func.join(row.leaderId);
+ row.sex = this.normalizeSexSubmit(row.sex, true);
// 获取需要提交的数据
const submitData = this.sensitiveManager.getSubmitData(row);
update(submitData).then(
@@ -1334,9 +1354,7 @@ export default {
if (this.form.hasOwnProperty('leaderId')) {
this.form.leaderId = func.split(this.form.leaderId);
}
- if (this.form.sex === -1) {
- this.form.sex = '';
- }
+ this.form.sex = this.normalizeSexDisplay(this.form.sex);
// 保存初始脱敏数据
this.sensitiveManager.saveInitialData(this.form);
});
diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue
index a6c980a..9be977f 100644
--- a/src/views/vehicle/customer-archive.vue
+++ b/src/views/vehicle/customer-archive.vue
@@ -339,7 +339,7 @@
-
+
@@ -1552,6 +1551,8 @@ import ChangeRecordDetailDialog from '@/components/change-record-detail-dialog/m
const customerArchiveListRoute = '/vehicle/customer-archive';
const customerArchiveFormRoute = '/vehicle/customer-archive/form';
const customerArchiveListRefreshKey = 'customer-archive-list-refresh';
+/** 客商所属组织固定为顶层组织 */
+const FIXED_OWNER_DEPT_NAME = '桂物物流集团';
const createTimeRangeMap = {
createTimeRange: ['createTimeStart', 'createTimeEnd'],
@@ -1788,15 +1789,6 @@ export default {
{ required: true, message: '请输入详细地址', trigger: 'blur' },
{ max: 255, message: '详细地址最多255个字符', trigger: 'blur' },
],
- businessScope: [
- {
- required: true,
- type: 'array',
- min: 1,
- message: '请选择经营范围',
- trigger: 'change',
- },
- ],
remark: [{ max: 500, message: '备注最多500个字符', trigger: 'blur' }],
},
contactRules: {
@@ -3043,17 +3035,34 @@ export default {
});
return result;
},
- setDefaultTopLevelDept() {
- const deptIds = Array.isArray(this.archiveForm.deptId)
- ? this.archiveForm.deptId
- : this.archiveForm.deptId
- ? [this.archiveForm.deptId]
- : [];
- const firstTopLevelDept = this.deptTree[0];
- if (!this.isArchivePage || this.$route.query.id || deptIds.length || !firstTopLevelDept) {
+ findTopLevelDeptByName(name) {
+ const targetName = String(name || '').trim();
+ if (!targetName) {
+ return null;
+ }
+ return (
+ (this.deptTree || []).find(item => {
+ const label = String(item.label || item.title || item.deptName || item.name || '').trim();
+ return label === targetName;
+ }) || null
+ );
+ },
+ /**
+ * 客商所属组织固定为顶层「桂物物流集团」,表单不可编辑。
+ */
+ applyFixedOwnerDept() {
+ if (!this.isArchivePage || this.readonly) {
return;
}
- this.onDeptChange([firstTopLevelDept.value]);
+ const fixedDept =
+ this.findTopLevelDeptByName(FIXED_OWNER_DEPT_NAME) || (this.deptTree || [])[0] || null;
+ if (!fixedDept) {
+ return;
+ }
+ this.onDeptChange([fixedDept.value]);
+ },
+ setDefaultTopLevelDept() {
+ this.applyFixedOwnerDept();
},
onDeptChange(value) {
// 级联单选:value 为根到选中节点的 ID 路径,取末级作为客商所属组织
@@ -4104,6 +4113,7 @@ export default {
this.ocrQualificationUploadFiles = [];
this.selectedQualificationFiles = [];
if (this.isPublicViewPage) this.ensurePublicViewOptions(this.archiveForm);
+ this.applyFixedOwnerDept();
this.archiveBox = true;
this.loadChangeRecords();
if (this.reviewMode) this.openReviewScore();
@@ -4120,6 +4130,7 @@ export default {
this.qualificationUploadFiles = [];
this.ocrQualificationUploadFiles = [];
this.selectedQualificationFiles = [];
+ this.applyFixedOwnerDept();
this.archiveBox = true;
},
resetArchive() {
@@ -4162,6 +4173,8 @@ export default {
return true;
},
normalizeArchive() {
+ // 提交前再次固定所属组织,防止被绕过
+ this.applyFixedOwnerDept();
const archive = JSON.parse(JSON.stringify(this.archiveForm));
if (archive.businessTermType === '长期') {
archive.businessEndDate = null;