+12
-2
@@ -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({
|
return request({
|
||||||
url: '/blade-system/dept/sync-oa-company',
|
url: '/blade-system/dept/sync-oa-company',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: {
|
params: {
|
||||||
current,
|
current,
|
||||||
size,
|
size,
|
||||||
|
incremental: !!incremental,
|
||||||
|
modifiedSince: modifiedSince || undefined,
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
signal,
|
signal,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
export const syncOaDepartment = (current = 1, size = 20, signal) => {
|
export const syncOaDepartment = (
|
||||||
|
current = 1,
|
||||||
|
size = 20,
|
||||||
|
signal,
|
||||||
|
incremental = false,
|
||||||
|
modifiedSince
|
||||||
|
) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/dept/sync-oa-department',
|
url: '/blade-system/dept/sync-oa-department',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: {
|
params: {
|
||||||
current,
|
current,
|
||||||
size,
|
size,
|
||||||
|
incremental: !!incremental,
|
||||||
|
modifiedSince: modifiedSince || undefined,
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
signal,
|
signal,
|
||||||
|
|||||||
+14
-1
@@ -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({
|
return request({
|
||||||
url: '/blade-system/user/sync-iam-accounts',
|
url: '/blade-system/user/sync-iam-accounts',
|
||||||
method: 'post',
|
method: 'post',
|
||||||
params: {
|
params: {
|
||||||
current,
|
current,
|
||||||
size,
|
size,
|
||||||
|
incremental: !!incremental,
|
||||||
|
modifiedSince: modifiedSince || undefined,
|
||||||
},
|
},
|
||||||
timeout: 60000,
|
timeout: 60000,
|
||||||
signal,
|
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) => {
|
export const updatePlatform = (userId, userType, userExt) => {
|
||||||
return request({
|
return request({
|
||||||
url: '/blade-system/user/update-platform',
|
url: '/blade-system/user/update-platform',
|
||||||
|
|||||||
@@ -27,7 +27,8 @@ export const userOption = safe => {
|
|||||||
index: true,
|
index: true,
|
||||||
selection: true,
|
selection: true,
|
||||||
addBtn: false,
|
addBtn: false,
|
||||||
viewBtn: true,
|
viewBtn: false,
|
||||||
|
menuWidth: 160,
|
||||||
dialogType: 'dialog',
|
dialogType: 'dialog',
|
||||||
dialogWidth: '90%',
|
dialogWidth: '90%',
|
||||||
labelPosition: 'right',
|
labelPosition: 'right',
|
||||||
@@ -37,6 +38,7 @@ export const userOption = safe => {
|
|||||||
{
|
{
|
||||||
label: '账号名',
|
label: '账号名',
|
||||||
prop: 'account',
|
prop: 'account',
|
||||||
|
slot: true,
|
||||||
search: true,
|
search: true,
|
||||||
searchOrder: 2,
|
searchOrder: 2,
|
||||||
searchPlaceholder: '支持模糊搜索',
|
searchPlaceholder: '支持模糊搜索',
|
||||||
@@ -63,7 +65,8 @@ export const userOption = safe => {
|
|||||||
label: '所属部门',
|
label: '所属部门',
|
||||||
prop: 'deptName',
|
prop: 'deptName',
|
||||||
slot: true,
|
slot: true,
|
||||||
overHidden: true,
|
minWidth: 200,
|
||||||
|
overHidden: false,
|
||||||
display: false,
|
display: false,
|
||||||
},
|
},
|
||||||
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
|
{ label: '岗位', prop: 'postName', overHidden: true, display: false },
|
||||||
|
|||||||
@@ -16,7 +16,7 @@
|
|||||||
class="contract-manage-form__attachment-table"
|
class="contract-manage-form__attachment-table"
|
||||||
@selection-change="selected = $event"
|
@selection-change="selected = $event"
|
||||||
>
|
>
|
||||||
<el-table-column v-if="!readonly" type="selection" width="55" align="center" />
|
<el-table-column type="selection" width="55" align="center" />
|
||||||
<el-table-column type="index" label="序号" width="70" align="center" />
|
<el-table-column type="index" label="序号" width="70" align="center" />
|
||||||
<el-table-column v-if="attachmentType" label="附件类型" min-width="160" align="center">
|
<el-table-column v-if="attachmentType" label="附件类型" min-width="160" align="center">
|
||||||
<template #default="{ row, $index }">
|
<template #default="{ row, $index }">
|
||||||
@@ -726,7 +726,15 @@ export default {
|
|||||||
downloadFileByUrl(url, attachmentName(row));
|
downloadFileByUrl(url, attachmentName(row));
|
||||||
},
|
},
|
||||||
batchDownload() {
|
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) {
|
formatSize(size) {
|
||||||
const value = Number(size);
|
const value = Number(size);
|
||||||
|
|||||||
@@ -1666,6 +1666,7 @@ const downloadTemplate = async () => {
|
|||||||
ElMessage.error('模板下载失败');
|
ElMessage.error('模板下载失败');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
const isValidMobile = value => /^\d{11}$/.test(String(value || '').trim());
|
||||||
const validateImportRows = () => {
|
const validateImportRows = () => {
|
||||||
if (!rows.value.length) {
|
if (!rows.value.length) {
|
||||||
ElMessage.warning('请上传至少一条运单明细');
|
ElMessage.warning('请上传至少一条运单明细');
|
||||||
@@ -1677,6 +1678,11 @@ const validateImportRows = () => {
|
|||||||
ElMessage.warning(`第${index + 1}行${missingField.label}不能为空`);
|
ElMessage.warning(`第${index + 1}行${missingField.label}不能为空`);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
const driverPhone = String(row.driverPhone ?? '').trim();
|
||||||
|
if (driverPhone && !isValidMobile(driverPhone)) {
|
||||||
|
ElMessage.warning(`第${index + 1}行司机/船长手机号格式不正确,应为11位数字`);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1022,7 +1022,7 @@
|
|||||||
v-model="detailBillingPlanBox"
|
v-model="detailBillingPlanBox"
|
||||||
:value="detailBillingPlanForm"
|
:value="detailBillingPlanForm"
|
||||||
:index="detailBillingPlanIndex"
|
:index="detailBillingPlanIndex"
|
||||||
:settlement-currency="detail.settlementCurrency || form.settlementCurrency"
|
:settlement-currency="detailRow.settlementCurrency || form.settlementCurrency"
|
||||||
readonly
|
readonly
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
|||||||
+94
-21
@@ -35,8 +35,16 @@
|
|||||||
plain
|
plain
|
||||||
:loading="oaSyncLoading"
|
:loading="oaSyncLoading"
|
||||||
v-if="isAdministrator"
|
v-if="isAdministrator"
|
||||||
@click="handleOaOrgSync"
|
@click="handleOaOrgFullSync"
|
||||||
>自动同步组织
|
>全量同步
|
||||||
|
</el-button>
|
||||||
|
<el-button
|
||||||
|
type="primary"
|
||||||
|
plain
|
||||||
|
:loading="oaSyncLoading"
|
||||||
|
v-if="isAdministrator"
|
||||||
|
@click="handleOaOrgIncrementalSync"
|
||||||
|
>增量同步
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="scope">
|
<template #menu="scope">
|
||||||
@@ -191,10 +199,12 @@ const escapeRegExp = value => value.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|||||||
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
const ORGANIZATION_TYPE_DICT_CODE = 'organization_type';
|
||||||
/**
|
/**
|
||||||
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
* 组织类型名称 → 字典数字键(兼容 dictKey 配成中文的情况)
|
||||||
|
* 与业务字典 organization_type 及历史别名对齐;优先仍以数字 dictKey 为准
|
||||||
*/
|
*/
|
||||||
const ORGANIZATION_TYPE_CODE_BY_LABEL = {
|
const ORGANIZATION_TYPE_CODE_BY_LABEL = {
|
||||||
集团: 1,
|
集团: 1,
|
||||||
一级集团: 1,
|
一级集团: 1,
|
||||||
|
公司: 2,
|
||||||
事业部: 2,
|
事业部: 2,
|
||||||
二级事业部: 2,
|
二级事业部: 2,
|
||||||
部门: 3,
|
部门: 3,
|
||||||
@@ -234,6 +244,7 @@ export default {
|
|||||||
oaSyncCancelled: false,
|
oaSyncCancelled: false,
|
||||||
oaSyncStatus: 'running',
|
oaSyncStatus: 'running',
|
||||||
oaSyncStage: 'company',
|
oaSyncStage: 'company',
|
||||||
|
oaSyncMode: 'full',
|
||||||
oaSyncClearNonTop: false,
|
oaSyncClearNonTop: false,
|
||||||
oaSyncController: null,
|
oaSyncController: null,
|
||||||
oaSyncProgress: {
|
oaSyncProgress: {
|
||||||
@@ -278,6 +289,7 @@ export default {
|
|||||||
minWidth: 160,
|
minWidth: 160,
|
||||||
order: 80,
|
order: 80,
|
||||||
search: true,
|
search: true,
|
||||||
|
searchOrder: 2,
|
||||||
rules: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
required: true,
|
||||||
@@ -389,6 +401,8 @@ export default {
|
|||||||
prop: 'shortName',
|
prop: 'shortName',
|
||||||
minWidth: 140,
|
minWidth: 140,
|
||||||
order: 60,
|
order: 60,
|
||||||
|
search: true,
|
||||||
|
searchOrder: 1,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '助记码',
|
label: '助记码',
|
||||||
@@ -462,15 +476,33 @@ export default {
|
|||||||
{
|
{
|
||||||
label: '排序',
|
label: '排序',
|
||||||
prop: 'sort',
|
prop: 'sort',
|
||||||
type: 'number',
|
type: 'input',
|
||||||
align: 'right',
|
align: 'right',
|
||||||
width: 80,
|
width: 80,
|
||||||
order: 30,
|
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: [
|
rules: [
|
||||||
{
|
{
|
||||||
required: true,
|
validator: (rule, value, callback) => {
|
||||||
message: '请输入排序',
|
if (value === '' || value === undefined || value === null) {
|
||||||
trigger: 'blur',
|
callback();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!/^\d+$/.test(String(value).trim())) {
|
||||||
|
callback(new Error('排序只能输入数字'));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
callback();
|
||||||
|
},
|
||||||
|
trigger: ['blur', 'change'],
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
@@ -509,12 +541,10 @@ export default {
|
|||||||
value: 'tenantId',
|
value: 'tenantId',
|
||||||
},
|
},
|
||||||
hide: true,
|
hide: true,
|
||||||
search: website.tenantMode,
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: '机构全称',
|
label: '机构全称',
|
||||||
prop: 'fullName',
|
prop: 'fullName',
|
||||||
search: true,
|
|
||||||
hide: true,
|
hide: true,
|
||||||
addDisplay: false,
|
addDisplay: false,
|
||||||
editDisplay: false,
|
editDisplay: false,
|
||||||
@@ -568,16 +598,17 @@ export default {
|
|||||||
return ids.join(',');
|
return ids.join(',');
|
||||||
},
|
},
|
||||||
oaSyncDialogTitle() {
|
oaSyncDialogTitle() {
|
||||||
|
const modeLabel = this.oaSyncMode === 'incremental' ? '增量同步' : '全量同步';
|
||||||
if (this.oaSyncStatus === 'done') {
|
if (this.oaSyncStatus === 'done') {
|
||||||
return '同步完成';
|
return `${modeLabel}完成`;
|
||||||
}
|
}
|
||||||
if (this.oaSyncStatus === 'cancelled') {
|
if (this.oaSyncStatus === 'cancelled') {
|
||||||
return '已取消同步';
|
return `已取消${modeLabel}`;
|
||||||
}
|
}
|
||||||
if (this.oaSyncStatus === 'error') {
|
if (this.oaSyncStatus === 'error') {
|
||||||
return '同步失败';
|
return `${modeLabel}失败`;
|
||||||
}
|
}
|
||||||
return '自动同步组织';
|
return modeLabel;
|
||||||
},
|
},
|
||||||
oaSyncStageLabel() {
|
oaSyncStageLabel() {
|
||||||
if (this.oaSyncStage === 'clear') {
|
if (this.oaSyncStage === 'clear') {
|
||||||
@@ -617,10 +648,10 @@ export default {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
handleOaOrgSync() {
|
handleOaOrgFullSync() {
|
||||||
this.$confirm(
|
this.$confirm(
|
||||||
'是否清除非顶级组织?选择“是”将先删除顶级以外的组织后再同步;选择“否”则直接同步。',
|
'全量同步将拉取 OA 全部公司/部门;已存在且 OA 更新时间一致的记录会跳过。是否清除非顶级组织?选择“是”将先删除顶级以外的组织后再同步;选择“否”则直接全量同步。',
|
||||||
'提示',
|
'全量同步',
|
||||||
{
|
{
|
||||||
confirmButtonText: '是',
|
confirmButtonText: '是',
|
||||||
cancelButtonText: '否',
|
cancelButtonText: '否',
|
||||||
@@ -630,20 +661,37 @@ export default {
|
|||||||
}
|
}
|
||||||
)
|
)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
this.startOaOrgSync(true);
|
this.startOaOrgSync({ clearNonTop: true, incremental: false });
|
||||||
})
|
})
|
||||||
.catch(action => {
|
.catch(action => {
|
||||||
if (action === 'cancel') {
|
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.oaSyncLoading = true;
|
||||||
this.oaSyncVisible = true;
|
this.oaSyncVisible = true;
|
||||||
this.oaSyncRunning = true;
|
this.oaSyncRunning = true;
|
||||||
this.oaSyncCancelled = false;
|
this.oaSyncCancelled = false;
|
||||||
this.oaSyncStatus = 'running';
|
this.oaSyncStatus = 'running';
|
||||||
|
this.oaSyncMode = incremental ? 'incremental' : 'full';
|
||||||
this.oaSyncClearNonTop = !!clearNonTop;
|
this.oaSyncClearNonTop = !!clearNonTop;
|
||||||
this.oaSyncStage = clearNonTop ? 'clear' : 'company';
|
this.oaSyncStage = clearNonTop ? 'clear' : 'company';
|
||||||
this.oaSyncController = new AbortController();
|
this.oaSyncController = new AbortController();
|
||||||
@@ -666,10 +714,21 @@ export default {
|
|||||||
},
|
},
|
||||||
async runOaOrgSyncStage(syncApi) {
|
async runOaOrgSyncStage(syncApi) {
|
||||||
const size = 20;
|
const size = 20;
|
||||||
|
const incremental = this.oaSyncMode === 'incremental';
|
||||||
let current = 1;
|
let current = 1;
|
||||||
|
let modifiedSince = '';
|
||||||
while (!this.oaSyncCancelled) {
|
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 || {};
|
const page = res?.data?.data || {};
|
||||||
|
if (!modifiedSince && page.modifiedSince) {
|
||||||
|
modifiedSince = page.modifiedSince;
|
||||||
|
}
|
||||||
this.oaSyncProgress.current = page.current || current;
|
this.oaSyncProgress.current = page.current || current;
|
||||||
this.oaSyncProgress.size = page.size || size;
|
this.oaSyncProgress.size = page.size || size;
|
||||||
this.oaSyncProgress.total = page.total || 0;
|
this.oaSyncProgress.total = page.total || 0;
|
||||||
@@ -806,7 +865,7 @@ export default {
|
|||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 业务字典项转下拉选项。后端 deptCategory 为 Integer,value 必须始终为数字。
|
* 业务字典项转下拉选项。后端 deptCategory 为 Integer,value 必须始终为数字。
|
||||||
* 优先用数字 dictKey;若 dictKey 配成中文,则按名称映射已知编码。
|
* 优先用数字 dictKey;其次按名称映射;再回退 sort,避免字典项被静默丢弃。
|
||||||
*/
|
*/
|
||||||
normalizeOrganizationTypeOption(item) {
|
normalizeOrganizationTypeOption(item) {
|
||||||
const label = item?.dictValue ?? item?.label;
|
const label = item?.dictValue ?? item?.label;
|
||||||
@@ -833,10 +892,19 @@ export default {
|
|||||||
value: codeByLabel,
|
value: codeByLabel,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
// 未命中名称映射时,用排序号兜底,保证与业务字典项一致展示
|
||||||
|
const sortNumber = Number(item?.sort);
|
||||||
|
if (!Number.isNaN(sortNumber) && sortNumber >= 1) {
|
||||||
|
return {
|
||||||
|
label: labelText,
|
||||||
|
value: sortNumber,
|
||||||
|
};
|
||||||
|
}
|
||||||
return null;
|
return null;
|
||||||
},
|
},
|
||||||
/**
|
/**
|
||||||
* 提交前将组织类型规范为 Integer;空状态字段去掉,避免 "" 反序列化失败。
|
* 提交前将组织类型规范为 Integer;空状态/排序字段去掉,避免 "" 反序列化失败。
|
||||||
|
* 排序为空时由后端默认填充 1。
|
||||||
*/
|
*/
|
||||||
prepareDeptSubmitRow(row) {
|
prepareDeptSubmitRow(row) {
|
||||||
const category = this.resolveDeptCategoryValue(row.deptCategory);
|
const category = this.resolveDeptCategoryValue(row.deptCategory);
|
||||||
@@ -849,6 +917,11 @@ export default {
|
|||||||
} else {
|
} else {
|
||||||
row.status = Number(row.status);
|
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;
|
return true;
|
||||||
},
|
},
|
||||||
resolveDeptCategoryValue(value) {
|
resolveDeptCategoryValue(value) {
|
||||||
|
|||||||
+145
-127
@@ -51,72 +51,31 @@
|
|||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
icon="el-icon-operation"
|
:loading="iamSyncLoading"
|
||||||
v-if="isAdministrator && !auditMode"
|
v-if="isAdministrator && !auditMode"
|
||||||
@click="handleAudit"
|
@click="handleOaPersonFullSync"
|
||||||
>审 核
|
>全量同步
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
plain
|
||||||
:loading="iamSyncLoading"
|
:loading="iamSyncLoading"
|
||||||
v-if="isAdministrator && !auditMode"
|
v-if="isAdministrator && !auditMode"
|
||||||
@click="handleIamSync"
|
@click="handleOaPersonIncrementalSync"
|
||||||
>同步人员
|
>增量同步
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
type="success"
|
|
||||||
plain
|
|
||||||
icon="el-icon-check"
|
|
||||||
v-if="isAdministrator && auditMode"
|
|
||||||
@click="handleAuditPass"
|
|
||||||
>通 过
|
|
||||||
</el-button>
|
|
||||||
<el-button
|
|
||||||
type="danger"
|
|
||||||
plain
|
|
||||||
icon="el-icon-close"
|
|
||||||
v-if="isAdministrator && auditMode"
|
|
||||||
@click="handleAuditRefuse"
|
|
||||||
>拒 绝
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="primary"
|
type="primary"
|
||||||
plain
|
v-if="isAdministrator && !auditMode"
|
||||||
icon="el-icon-refresh-left"
|
@click="handleImport"
|
||||||
v-if="isAdministrator && auditMode"
|
>导入
|
||||||
@click="handleAuditBack"
|
|
||||||
>返 回
|
|
||||||
</el-button>
|
</el-button>
|
||||||
<el-button
|
<el-button
|
||||||
type="info"
|
type="primary"
|
||||||
plain
|
|
||||||
v-if="permission.user_role && !auditMode"
|
|
||||||
icon="el-icon-user"
|
|
||||||
@click="handleGrant"
|
|
||||||
>角色配置
|
|
||||||
</el-button>
|
|
||||||
<el-dropdown
|
|
||||||
v-if="isAdministrator && !auditMode"
|
v-if="isAdministrator && !auditMode"
|
||||||
@command="handleDataManageCommand"
|
@click="handleExport"
|
||||||
style="margin-left: 10px"
|
>导出
|
||||||
>
|
</el-button>
|
||||||
<el-button type="primary" plain icon="el-icon-files">
|
|
||||||
数据管理<i class="el-icon-arrow-down el-icon--right"></i>
|
|
||||||
</el-button>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item command="import">
|
|
||||||
<el-icon><upload /></el-icon>
|
|
||||||
导入数据
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="export">
|
|
||||||
<el-icon><download /></el-icon>
|
|
||||||
导出数据
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
</template>
|
||||||
<template #menu-right>
|
<template #menu-right>
|
||||||
<el-button
|
<el-button
|
||||||
@@ -132,47 +91,23 @@
|
|||||||
>锁定管理
|
>锁定管理
|
||||||
</el-button>
|
</el-button>
|
||||||
</template>
|
</template>
|
||||||
<template #menu="{ row, index, size }">
|
<template #account="{ row }">
|
||||||
|
<el-link type="primary" @click.stop="openUserDialog('view', row)">{{ row.account }}</el-link>
|
||||||
|
</template>
|
||||||
|
<template #menu="{ row }">
|
||||||
<el-link
|
<el-link
|
||||||
type="primary"
|
type="primary"
|
||||||
v-if="this.permission.user_view"
|
v-if="permission.user_edit && !auditMode"
|
||||||
@click.stop="$refs.crud.rowView(row, index)"
|
|
||||||
>查看
|
|
||||||
</el-link>
|
|
||||||
<el-link
|
|
||||||
type="primary"
|
|
||||||
v-if="this.permission.user_edit"
|
|
||||||
@click.stop="openUserDialog('edit', row)"
|
@click.stop="openUserDialog('edit', row)"
|
||||||
>编辑
|
>修改
|
||||||
|
</el-link>
|
||||||
|
<el-link
|
||||||
|
type="primary"
|
||||||
|
v-if="permission.user_edit && !auditMode"
|
||||||
|
@click.stop="handleStatus(row)"
|
||||||
|
>
|
||||||
|
{{ Number(row.status) === 1 ? '停用' : '启用' }}
|
||||||
</el-link>
|
</el-link>
|
||||||
<el-dropdown @command="command => handleDropdownCommand(command, row, index)">
|
|
||||||
<el-link type="primary">更多 </el-link>
|
|
||||||
<template #dropdown>
|
|
||||||
<el-dropdown-menu>
|
|
||||||
<el-dropdown-item command="setLeader" v-if="isAdministrator">
|
|
||||||
{{ row.isLeader === 1 ? '取消主管' : '设置主管' }}
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="grantRole" v-if="permission.user_role">
|
|
||||||
角色配置
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="authLog" v-if="isAdministrator">
|
|
||||||
认证日志
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="lockUser" v-if="isAdministrator">
|
|
||||||
锁定账号
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="resetPassword" v-if="permission.user_reset">
|
|
||||||
密码重置
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="setPassword" v-if="permission.user_reset">
|
|
||||||
修改密码
|
|
||||||
</el-dropdown-item>
|
|
||||||
<el-dropdown-item command="delete" v-if="this.permission.user_delete">
|
|
||||||
删除用户
|
|
||||||
</el-dropdown-item>
|
|
||||||
</el-dropdown-menu>
|
|
||||||
</template>
|
|
||||||
</el-dropdown>
|
|
||||||
</template>
|
</template>
|
||||||
<template #roleName="{ row }">
|
<template #roleName="{ row }">
|
||||||
<el-tag>{{ row.roleName }}</el-tag>
|
<el-tag>{{ row.roleName }}</el-tag>
|
||||||
@@ -191,7 +126,7 @@
|
|||||||
|
|
||||||
<el-dialog
|
<el-dialog
|
||||||
v-model="userDialog"
|
v-model="userDialog"
|
||||||
:title="userDialogMode === 'add' ? '新增用户' : '编辑用户'"
|
:title="userDialogTitle"
|
||||||
width="90%"
|
width="90%"
|
||||||
top="5vh"
|
top="5vh"
|
||||||
append-to-body
|
append-to-body
|
||||||
@@ -199,12 +134,12 @@
|
|||||||
class="user-edit-dialog dialog-form--carded"
|
class="user-edit-dialog dialog-form--carded"
|
||||||
>
|
>
|
||||||
<template #header>
|
<template #header>
|
||||||
<span class="dialog-title">{{ userDialogMode === 'add' ? '新增用户' : '编辑用户' }}</span>
|
<span class="dialog-title">{{ userDialogTitle }}</span>
|
||||||
</template>
|
</template>
|
||||||
<section-card title="用户信息">
|
<section-card title="用户信息">
|
||||||
<el-form ref="userFormRef" :model="form" :rules="userRules" label-position="right" label-width="calc(6em + 24px)">
|
<el-form ref="userFormRef" :model="form" :rules="isUserViewMode ? {} : userRules" label-position="right" label-width="calc(6em + 24px)">
|
||||||
<el-row :gutter="18">
|
<el-row :gutter="18">
|
||||||
<el-col :span="6"><el-form-item label="账号名" prop="account"><el-input v-model="form.account" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="账号名" prop="account"><el-input v-model="form.account" :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col v-if="userDialogMode === 'add'" :span="6">
|
<el-col v-if="userDialogMode === 'add'" :span="6">
|
||||||
<el-form-item label="登录密码" prop="password">
|
<el-form-item label="登录密码" prop="password">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -216,17 +151,18 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6"><el-form-item label="姓名" prop="realName"><el-input v-model="form.realName" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="姓名" prop="realName"><el-input v-model="form.realName" :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="手机号" prop="phone"><el-input v-model="form.phone" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="手机号" prop="phone"><el-input v-model="form.phone" :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="邮箱"><el-input v-model="form.email" :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="性别"><el-select v-model="form.sex" :disabled="isUserViewMode" clearable placeholder="请选择"><el-option label="男" :value="1" /><el-option label="女" :value="2" /><el-option label="未知" :value="3" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="岗位" prop="postId"><el-tree-select v-model="form.postId" :data="postList" :props="{ label: 'postName', value: 'id' }" check-strictly :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="所属组织" prop="deptId">
|
<el-form-item label="所属组织" prop="deptId">
|
||||||
<el-cascader
|
<el-cascader
|
||||||
v-model="deptCascaderValue"
|
v-model="deptCascaderValue"
|
||||||
:options="permissionDeptTree"
|
:options="permissionDeptTree"
|
||||||
:props="deptCascaderProps"
|
:props="deptCascaderProps"
|
||||||
|
:disabled="isUserViewMode"
|
||||||
clearable
|
clearable
|
||||||
filterable
|
filterable
|
||||||
collapse-tags
|
collapse-tags
|
||||||
@@ -235,10 +171,10 @@
|
|||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" /></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="工号"><el-input v-model="form.code" :disabled="isUserViewMode" /></el-form-item></el-col>
|
||||||
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
|
<el-col :span="6"><el-form-item label="人员类别"><el-select v-model="form.personCategory" :disabled="isUserViewMode"><el-option label="内部员工" :value="1" /><el-option label="承运商" :value="2" /></el-select></el-form-item></el-col>
|
||||||
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
|
<el-col :span="18"><el-form-item label="数据权限范围"><el-radio-group v-model="form.dataScopeRange" :disabled="isUserViewMode"><el-radio :value="1">仅所属组织</el-radio><el-radio :value="2">全部组织</el-radio><el-radio :value="3">自定义</el-radio></el-radio-group></el-form-item></el-col>
|
||||||
<el-col :span="18"><el-form-item label="数据层级范围"><el-radio-group v-model="form.dataLevelRange"><el-radio :value="1">包含下级</el-radio><el-radio :value="2">仅本级</el-radio></el-radio-group></el-form-item></el-col>
|
<el-col :span="18"><el-form-item label="数据层级范围"><el-radio-group v-model="form.dataLevelRange" :disabled="isUserViewMode"><el-radio :value="1">包含下级</el-radio><el-radio :value="2">仅本级</el-radio></el-radio-group></el-form-item></el-col>
|
||||||
<el-col :span="24">
|
<el-col :span="24">
|
||||||
<el-form-item label="备注">
|
<el-form-item label="备注">
|
||||||
<el-input
|
<el-input
|
||||||
@@ -247,6 +183,7 @@
|
|||||||
:rows="2"
|
:rows="2"
|
||||||
maxlength="200"
|
maxlength="200"
|
||||||
show-word-limit
|
show-word-limit
|
||||||
|
:disabled="isUserViewMode"
|
||||||
style="width: 100%"
|
style="width: 100%"
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
@@ -260,18 +197,28 @@
|
|||||||
<el-table-column type="index" label="序号" width="70" />
|
<el-table-column type="index" label="序号" width="70" />
|
||||||
<el-table-column prop="id" label="角色编号" />
|
<el-table-column prop="id" label="角色编号" />
|
||||||
<el-table-column prop="title" label="角色名称" />
|
<el-table-column prop="title" label="角色名称" />
|
||||||
<el-table-column label="操作" width="90"><template #default="{ row }"><el-link type="danger" @click="removeFormRole(row.id)">删除</el-link></template></el-table-column>
|
<el-table-column v-if="!isUserViewMode" label="操作" width="90"><template #default="{ row }"><el-link type="danger" @click="removeFormRole(row.id)">删除</el-link></template></el-table-column>
|
||||||
</el-table>
|
</el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane v-if="form.dataScopeRange === 3" label="数据权限">
|
<el-tab-pane v-if="form.dataScopeRange === 3" label="数据权限">
|
||||||
<el-tree :data="permissionDeptTree" show-checkbox node-key="id" :default-checked-keys="form.dataScopeDeptIds || []" :props="{ label: 'title', children: 'children' }" @check="handleDataScopeCheck" />
|
<el-tree :data="permissionDeptTree" show-checkbox node-key="id" :default-checked-keys="form.dataScopeDeptIds || []" :props="{ label: 'title', children: 'children' }" @check="handleDataScopeCheck" />
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
<el-tab-pane label="客商权限">
|
<el-tab-pane label="客商权限">
|
||||||
<div class="permission-toolbar customer-toolbar"><el-checkbox v-model="form.includeNewCustomer" :true-value="1" :false-value="0">包含新增的客商</el-checkbox></div>
|
<div class="permission-toolbar customer-toolbar"><el-checkbox v-model="form.includeNewCustomer" :true-value="1" :false-value="0" :disabled="isUserViewMode">包含新增的客商</el-checkbox></div>
|
||||||
<el-table ref="customerTable" :data="customerList" border @selection-change="handleCustomerSelection"><el-table-column type="selection" width="55" /><el-table-column prop="customerCode" label="客商编码" /><el-table-column prop="fullName" label="客商名称" /></el-table>
|
<el-table ref="customerTable" :data="customerList" border @selection-change="handleCustomerSelection"><el-table-column type="selection" width="55" :selectable="isCustomerSelectable" /><el-table-column prop="customerCode" label="客商编码" /><el-table-column prop="fullName" label="客商名称" /></el-table>
|
||||||
</el-tab-pane>
|
</el-tab-pane>
|
||||||
</el-tabs>
|
</el-tabs>
|
||||||
<template #footer><span class="dialog-footer"><el-button type="primary" @click="submitUserForm">保存</el-button><el-button @click="userDialog = false">取消</el-button><el-button v-if="userDialogMode === 'edit'" @click="resetDialogPassword">重置密码</el-button><el-button @click="handleAddRole">添加角色</el-button></span></template>
|
<template #footer>
|
||||||
|
<span v-if="isUserViewMode" class="dialog-footer">
|
||||||
|
<el-button @click="userDialog = false">关闭</el-button>
|
||||||
|
</span>
|
||||||
|
<span v-else class="dialog-footer">
|
||||||
|
<el-button type="primary" @click="submitUserForm">保存</el-button>
|
||||||
|
<el-button @click="userDialog = false">取消</el-button>
|
||||||
|
<el-button v-if="userDialogMode === 'edit'" @click="resetDialogPassword">重置密码</el-button>
|
||||||
|
<el-button @click="handleAddRole">添加角色</el-button>
|
||||||
|
</span>
|
||||||
|
</template>
|
||||||
</el-dialog>
|
</el-dialog>
|
||||||
|
|
||||||
<!-- 用户角色配置 -->
|
<!-- 用户角色配置 -->
|
||||||
@@ -442,6 +389,7 @@ import {
|
|||||||
remove,
|
remove,
|
||||||
update,
|
update,
|
||||||
add,
|
add,
|
||||||
|
changeStatus,
|
||||||
syncIamAccounts,
|
syncIamAccounts,
|
||||||
grant,
|
grant,
|
||||||
resetPassword,
|
resetPassword,
|
||||||
@@ -494,6 +442,7 @@ export default {
|
|||||||
oaSyncRunning: false,
|
oaSyncRunning: false,
|
||||||
oaSyncCancelled: false,
|
oaSyncCancelled: false,
|
||||||
oaSyncStatus: 'running',
|
oaSyncStatus: 'running',
|
||||||
|
oaSyncMode: 'full',
|
||||||
oaSyncController: null,
|
oaSyncController: null,
|
||||||
oaSyncProgress: {
|
oaSyncProgress: {
|
||||||
current: 0,
|
current: 0,
|
||||||
@@ -570,16 +519,17 @@ export default {
|
|||||||
computed: {
|
computed: {
|
||||||
...mapGetters(['userInfo', 'permission', 'isAdministrator']),
|
...mapGetters(['userInfo', 'permission', 'isAdministrator']),
|
||||||
oaSyncDialogTitle() {
|
oaSyncDialogTitle() {
|
||||||
|
const modeLabel = this.oaSyncMode === 'incremental' ? '增量同步' : '全量同步';
|
||||||
if (this.oaSyncStatus === 'done') {
|
if (this.oaSyncStatus === 'done') {
|
||||||
return '同步完成';
|
return `${modeLabel}完成`;
|
||||||
}
|
}
|
||||||
if (this.oaSyncStatus === 'cancelled') {
|
if (this.oaSyncStatus === 'cancelled') {
|
||||||
return '已取消同步';
|
return `已取消${modeLabel}`;
|
||||||
}
|
}
|
||||||
if (this.oaSyncStatus === 'error') {
|
if (this.oaSyncStatus === 'error') {
|
||||||
return '同步失败';
|
return `${modeLabel}失败`;
|
||||||
}
|
}
|
||||||
return '同步人员';
|
return modeLabel;
|
||||||
},
|
},
|
||||||
oaSyncTotalPage() {
|
oaSyncTotalPage() {
|
||||||
const total = Number(this.oaSyncProgress.total) || 0;
|
const total = Number(this.oaSyncProgress.total) || 0;
|
||||||
@@ -642,6 +592,18 @@ export default {
|
|||||||
this.$refs.userFormRef?.validateField('deptId');
|
this.$refs.userFormRef?.validateField('deptId');
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
isUserViewMode() {
|
||||||
|
return this.userDialogMode === 'view';
|
||||||
|
},
|
||||||
|
userDialogTitle() {
|
||||||
|
if (this.userDialogMode === 'add') {
|
||||||
|
return '新增用户';
|
||||||
|
}
|
||||||
|
if (this.userDialogMode === 'view') {
|
||||||
|
return '用户详情';
|
||||||
|
}
|
||||||
|
return '编辑用户';
|
||||||
|
},
|
||||||
permissionList() {
|
permissionList() {
|
||||||
return {
|
return {
|
||||||
addBtn: this.validData(this.permission.user_add, false),
|
addBtn: this.validData(this.permission.user_add, false),
|
||||||
@@ -714,28 +676,35 @@ export default {
|
|||||||
this.showResetPassword(res.data.data);
|
this.showResetPassword(res.data.data);
|
||||||
});
|
});
|
||||||
},
|
},
|
||||||
handleDataManageCommand(command) {
|
handleOaPersonFullSync() {
|
||||||
if (command === 'import') {
|
this.$confirm('全量同步将拉取 OA 全部人员及组织;已存在且 OA 更新时间一致的记录会跳过。是否继续?', '全量同步', {
|
||||||
this.handleImport();
|
|
||||||
} else if (command === 'export') {
|
|
||||||
this.handleExport();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
handleIamSync() {
|
|
||||||
this.$confirm('确定从OA同步人员及组织信息?', '提示', {
|
|
||||||
confirmButtonText: '确定',
|
confirmButtonText: '确定',
|
||||||
cancelButtonText: '取消',
|
cancelButtonText: '取消',
|
||||||
type: 'warning',
|
type: 'warning',
|
||||||
}).then(() => {
|
}).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.iamSyncLoading = true;
|
||||||
this.oaSyncVisible = true;
|
this.oaSyncVisible = true;
|
||||||
this.oaSyncRunning = true;
|
this.oaSyncRunning = true;
|
||||||
this.oaSyncCancelled = false;
|
this.oaSyncCancelled = false;
|
||||||
this.oaSyncStatus = 'running';
|
this.oaSyncStatus = 'running';
|
||||||
|
this.oaSyncMode = incremental ? 'incremental' : 'full';
|
||||||
this.oaSyncController = new AbortController();
|
this.oaSyncController = new AbortController();
|
||||||
this.oaSyncProgress = {
|
this.oaSyncProgress = {
|
||||||
current: 0,
|
current: 0,
|
||||||
@@ -756,11 +725,22 @@ export default {
|
|||||||
},
|
},
|
||||||
async runOaSyncPages() {
|
async runOaSyncPages() {
|
||||||
const size = 50;
|
const size = 50;
|
||||||
|
const incremental = this.oaSyncMode === 'incremental';
|
||||||
let current = 1;
|
let current = 1;
|
||||||
|
let modifiedSince = '';
|
||||||
try {
|
try {
|
||||||
while (!this.oaSyncCancelled) {
|
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 || {};
|
const page = res?.data?.data || {};
|
||||||
|
if (!modifiedSince && page.modifiedSince) {
|
||||||
|
modifiedSince = page.modifiedSince;
|
||||||
|
}
|
||||||
this.oaSyncProgress.current = page.current || current;
|
this.oaSyncProgress.current = page.current || current;
|
||||||
this.oaSyncProgress.size = page.size || size;
|
this.oaSyncProgress.size = page.size || size;
|
||||||
this.oaSyncProgress.total = page.total || 0;
|
this.oaSyncProgress.total = page.total || 0;
|
||||||
@@ -892,11 +872,33 @@ export default {
|
|||||||
.filter(id => String(id) !== String(roleId));
|
.filter(id => String(id) !== String(roleId));
|
||||||
},
|
},
|
||||||
handleDataScopeCheck(_, checked) {
|
handleDataScopeCheck(_, checked) {
|
||||||
|
if (this.isUserViewMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.form.dataScopeDeptIds = checked.checkedKeys;
|
this.form.dataScopeDeptIds = checked.checkedKeys;
|
||||||
},
|
},
|
||||||
handleCustomerSelection(rows) {
|
handleCustomerSelection(rows) {
|
||||||
|
if (this.isUserViewMode) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.form.customerIds = rows.map(row => row.id);
|
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) {
|
formatDeptNames(deptName) {
|
||||||
if (!deptName) {
|
if (!deptName) {
|
||||||
return [];
|
return [];
|
||||||
@@ -906,6 +908,20 @@ export default {
|
|||||||
.map(item => item.trim())
|
.map(item => item.trim())
|
||||||
.filter(Boolean);
|
.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 = {}) {
|
openUserDialog(mode, row = {}) {
|
||||||
this.userDialogMode = mode;
|
this.userDialogMode = mode;
|
||||||
if (mode === 'add') {
|
if (mode === 'add') {
|
||||||
@@ -915,7 +931,7 @@ export default {
|
|||||||
realName: '',
|
realName: '',
|
||||||
phone: '',
|
phone: '',
|
||||||
email: '',
|
email: '',
|
||||||
sex: 3,
|
sex: undefined,
|
||||||
postId: '',
|
postId: '',
|
||||||
deptId: [],
|
deptId: [],
|
||||||
code: '',
|
code: '',
|
||||||
@@ -946,6 +962,7 @@ export default {
|
|||||||
personCategory: user.personCategory || 1,
|
personCategory: user.personCategory || 1,
|
||||||
dataScopeRange: user.dataScopeRange || 1,
|
dataScopeRange: user.dataScopeRange || 1,
|
||||||
dataLevelRange: user.dataLevelRange || 1,
|
dataLevelRange: user.dataLevelRange || 1,
|
||||||
|
sex: this.normalizeSexDisplay(user.sex),
|
||||||
};
|
};
|
||||||
this.sensitiveManager.saveInitialData(this.form);
|
this.sensitiveManager.saveInitialData(this.form);
|
||||||
this.userDialog = true;
|
this.userDialog = true;
|
||||||
@@ -967,6 +984,7 @@ export default {
|
|||||||
postId: func.join(this.form.postId),
|
postId: func.join(this.form.postId),
|
||||||
roleId: func.join(this.form.roleId),
|
roleId: func.join(this.form.roleId),
|
||||||
leaderId: func.join(this.form.leaderId),
|
leaderId: func.join(this.form.leaderId),
|
||||||
|
sex: this.normalizeSexSubmit(this.form.sex, this.userDialogMode !== 'add'),
|
||||||
};
|
};
|
||||||
if (this.userDialogMode !== 'add') {
|
if (this.userDialogMode !== 'add') {
|
||||||
delete row.password;
|
delete row.password;
|
||||||
@@ -987,6 +1005,7 @@ export default {
|
|||||||
row.roleId = func.join(row.roleId);
|
row.roleId = func.join(row.roleId);
|
||||||
row.postId = func.join(row.postId);
|
row.postId = func.join(row.postId);
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
|
row.sex = this.normalizeSexSubmit(row.sex);
|
||||||
add(row).then(
|
add(row).then(
|
||||||
() => {
|
() => {
|
||||||
this.initFlag = false;
|
this.initFlag = false;
|
||||||
@@ -1008,6 +1027,7 @@ export default {
|
|||||||
row.roleId = func.join(row.roleId);
|
row.roleId = func.join(row.roleId);
|
||||||
row.postId = func.join(row.postId);
|
row.postId = func.join(row.postId);
|
||||||
row.leaderId = func.join(row.leaderId);
|
row.leaderId = func.join(row.leaderId);
|
||||||
|
row.sex = this.normalizeSexSubmit(row.sex, true);
|
||||||
// 获取需要提交的数据
|
// 获取需要提交的数据
|
||||||
const submitData = this.sensitiveManager.getSubmitData(row);
|
const submitData = this.sensitiveManager.getSubmitData(row);
|
||||||
update(submitData).then(
|
update(submitData).then(
|
||||||
@@ -1334,9 +1354,7 @@ export default {
|
|||||||
if (this.form.hasOwnProperty('leaderId')) {
|
if (this.form.hasOwnProperty('leaderId')) {
|
||||||
this.form.leaderId = func.split(this.form.leaderId);
|
this.form.leaderId = func.split(this.form.leaderId);
|
||||||
}
|
}
|
||||||
if (this.form.sex === -1) {
|
this.form.sex = this.normalizeSexDisplay(this.form.sex);
|
||||||
this.form.sex = '';
|
|
||||||
}
|
|
||||||
// 保存初始脱敏数据
|
// 保存初始脱敏数据
|
||||||
this.sensitiveManager.saveInitialData(this.form);
|
this.sensitiveManager.saveInitialData(this.form);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -339,7 +339,7 @@
|
|||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
<el-col :span="6">
|
<el-col :span="6">
|
||||||
<el-form-item label="经营范围" prop="businessScope" required>
|
<el-form-item label="经营范围" prop="businessScope">
|
||||||
<el-select v-model="archiveForm.businessScope" multiple filterable clearable>
|
<el-select v-model="archiveForm.businessScope" multiple filterable clearable>
|
||||||
<el-option
|
<el-option
|
||||||
v-for="item in businessScopeOptions"
|
v-for="item in businessScopeOptions"
|
||||||
@@ -460,9 +460,8 @@
|
|||||||
v-model="deptCascaderValue"
|
v-model="deptCascaderValue"
|
||||||
:options="deptTree"
|
:options="deptTree"
|
||||||
:props="deptCascaderProps"
|
:props="deptCascaderProps"
|
||||||
clearable
|
disabled
|
||||||
filterable
|
placeholder="桂物物流集团"
|
||||||
placeholder="请选择 所属组织"
|
|
||||||
/>
|
/>
|
||||||
</el-form-item>
|
</el-form-item>
|
||||||
</el-col>
|
</el-col>
|
||||||
@@ -1552,6 +1551,8 @@ import ChangeRecordDetailDialog from '@/components/change-record-detail-dialog/m
|
|||||||
const customerArchiveListRoute = '/vehicle/customer-archive';
|
const customerArchiveListRoute = '/vehicle/customer-archive';
|
||||||
const customerArchiveFormRoute = '/vehicle/customer-archive/form';
|
const customerArchiveFormRoute = '/vehicle/customer-archive/form';
|
||||||
const customerArchiveListRefreshKey = 'customer-archive-list-refresh';
|
const customerArchiveListRefreshKey = 'customer-archive-list-refresh';
|
||||||
|
/** 客商所属组织固定为顶层组织 */
|
||||||
|
const FIXED_OWNER_DEPT_NAME = '桂物物流集团';
|
||||||
|
|
||||||
const createTimeRangeMap = {
|
const createTimeRangeMap = {
|
||||||
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
createTimeRange: ['createTimeStart', 'createTimeEnd'],
|
||||||
@@ -1788,15 +1789,6 @@ export default {
|
|||||||
{ required: true, message: '请输入详细地址', trigger: 'blur' },
|
{ required: true, message: '请输入详细地址', trigger: 'blur' },
|
||||||
{ max: 255, message: '详细地址最多255个字符', 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' }],
|
remark: [{ max: 500, message: '备注最多500个字符', trigger: 'blur' }],
|
||||||
},
|
},
|
||||||
contactRules: {
|
contactRules: {
|
||||||
@@ -3043,17 +3035,34 @@ export default {
|
|||||||
});
|
});
|
||||||
return result;
|
return result;
|
||||||
},
|
},
|
||||||
setDefaultTopLevelDept() {
|
findTopLevelDeptByName(name) {
|
||||||
const deptIds = Array.isArray(this.archiveForm.deptId)
|
const targetName = String(name || '').trim();
|
||||||
? this.archiveForm.deptId
|
if (!targetName) {
|
||||||
: this.archiveForm.deptId
|
return null;
|
||||||
? [this.archiveForm.deptId]
|
}
|
||||||
: [];
|
return (
|
||||||
const firstTopLevelDept = this.deptTree[0];
|
(this.deptTree || []).find(item => {
|
||||||
if (!this.isArchivePage || this.$route.query.id || deptIds.length || !firstTopLevelDept) {
|
const label = String(item.label || item.title || item.deptName || item.name || '').trim();
|
||||||
|
return label === targetName;
|
||||||
|
}) || null
|
||||||
|
);
|
||||||
|
},
|
||||||
|
/**
|
||||||
|
* 客商所属组织固定为顶层「桂物物流集团」,表单不可编辑。
|
||||||
|
*/
|
||||||
|
applyFixedOwnerDept() {
|
||||||
|
if (!this.isArchivePage || this.readonly) {
|
||||||
return;
|
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) {
|
onDeptChange(value) {
|
||||||
// 级联单选:value 为根到选中节点的 ID 路径,取末级作为客商所属组织
|
// 级联单选:value 为根到选中节点的 ID 路径,取末级作为客商所属组织
|
||||||
@@ -4104,6 +4113,7 @@ export default {
|
|||||||
this.ocrQualificationUploadFiles = [];
|
this.ocrQualificationUploadFiles = [];
|
||||||
this.selectedQualificationFiles = [];
|
this.selectedQualificationFiles = [];
|
||||||
if (this.isPublicViewPage) this.ensurePublicViewOptions(this.archiveForm);
|
if (this.isPublicViewPage) this.ensurePublicViewOptions(this.archiveForm);
|
||||||
|
this.applyFixedOwnerDept();
|
||||||
this.archiveBox = true;
|
this.archiveBox = true;
|
||||||
this.loadChangeRecords();
|
this.loadChangeRecords();
|
||||||
if (this.reviewMode) this.openReviewScore();
|
if (this.reviewMode) this.openReviewScore();
|
||||||
@@ -4120,6 +4130,7 @@ export default {
|
|||||||
this.qualificationUploadFiles = [];
|
this.qualificationUploadFiles = [];
|
||||||
this.ocrQualificationUploadFiles = [];
|
this.ocrQualificationUploadFiles = [];
|
||||||
this.selectedQualificationFiles = [];
|
this.selectedQualificationFiles = [];
|
||||||
|
this.applyFixedOwnerDept();
|
||||||
this.archiveBox = true;
|
this.archiveBox = true;
|
||||||
},
|
},
|
||||||
resetArchive() {
|
resetArchive() {
|
||||||
@@ -4162,6 +4173,8 @@ export default {
|
|||||||
return true;
|
return true;
|
||||||
},
|
},
|
||||||
normalizeArchive() {
|
normalizeArchive() {
|
||||||
|
// 提交前再次固定所属组织,防止被绕过
|
||||||
|
this.applyFixedOwnerDept();
|
||||||
const archive = JSON.parse(JSON.stringify(this.archiveForm));
|
const archive = JSON.parse(JSON.stringify(this.archiveForm));
|
||||||
if (archive.businessTermType === '长期') {
|
if (archive.businessTermType === '长期') {
|
||||||
archive.businessEndDate = null;
|
archive.businessEndDate = null;
|
||||||
|
|||||||
Reference in New Issue
Block a user