+
当前阶段:{{ oaSyncStageLabel }}
+
当前阶段:{{ oaSyncStageLabel }},第 {{ oaSyncProgress.current || 0 }} / {{ oaSyncTotalPage }} 页
@@ -177,6 +178,7 @@ import {
getDeptTree,
syncOaCompany,
syncOaDepartment,
+ clearNonTopDept,
} from '@/api/system/dept';
import { getLeaderList } from '@/api/system/user';
import { getList as getCustomerArchiveList } from '@/api/vehicle/customer-archive';
@@ -215,6 +217,7 @@ export default {
oaSyncCancelled: false,
oaSyncStatus: 'running',
oaSyncStage: 'company',
+ oaSyncClearNonTop: false,
oaSyncController: null,
oaSyncProgress: {
current: 0,
@@ -287,8 +290,9 @@ export default {
return;
}
const parentId = this.normalizeParentId(this.form?.parentId);
+ // 顶级组织不选择上级时,编码不依赖上级编码
if (!parentId) {
- callback(new Error('请先选择上级组织'));
+ callback();
return;
}
if (!this.parentDept || String(this.parentDept.id) !== String(parentId)) {
@@ -429,13 +433,6 @@ export default {
props: {
label: 'title',
},
- rules: [
- {
- required: true,
- message: '请选择上级组织',
- trigger: 'click',
- },
- ],
},
{
label: '所属租户',
@@ -520,6 +517,9 @@ export default {
return '自动同步组织';
},
oaSyncStageLabel() {
+ if (this.oaSyncStage === 'clear') {
+ return '清除非顶级组织';
+ }
return this.oaSyncStage === 'department' ? '同步部门' : '同步公司';
},
oaSyncTotalPage() {
@@ -555,21 +555,34 @@ export default {
},
methods: {
handleOaOrgSync() {
- this.$confirm('确定从OA先同步公司、再同步部门?', '提示', {
- confirmButtonText: '确定',
- cancelButtonText: '取消',
- type: 'warning',
- }).then(() => {
- this.startOaOrgSync();
- });
+ this.$confirm(
+ '是否清除非顶级组织?选择“是”将先删除顶级以外的组织后再同步;选择“否”则直接同步。',
+ '提示',
+ {
+ confirmButtonText: '是',
+ cancelButtonText: '否',
+ distinguishCancelAndClose: true,
+ closeOnClickModal: false,
+ type: 'warning',
+ }
+ )
+ .then(() => {
+ this.startOaOrgSync(true);
+ })
+ .catch(action => {
+ if (action === 'cancel') {
+ this.startOaOrgSync(false);
+ }
+ });
},
- startOaOrgSync() {
+ startOaOrgSync(clearNonTop) {
this.oaSyncLoading = true;
this.oaSyncVisible = true;
this.oaSyncRunning = true;
this.oaSyncCancelled = false;
this.oaSyncStatus = 'running';
- this.oaSyncStage = 'company';
+ this.oaSyncClearNonTop = !!clearNonTop;
+ this.oaSyncStage = clearNonTop ? 'clear' : 'company';
this.oaSyncController = new AbortController();
this.oaSyncProgress = {
current: 0,
@@ -607,6 +620,14 @@ export default {
},
async runOaOrgSyncPages() {
try {
+ if (this.oaSyncClearNonTop) {
+ this.oaSyncStage = 'clear';
+ await clearNonTopDept(this.oaSyncController?.signal);
+ if (this.oaSyncCancelled) {
+ this.oaSyncStatus = 'cancelled';
+ return;
+ }
+ }
this.oaSyncStage = 'company';
await this.runOaOrgSyncStage(syncOaCompany);
if (this.oaSyncCancelled) {
@@ -821,6 +842,11 @@ export default {
.filter(Boolean);
return result.length ? result.join('、') : '-';
},
+ normalizeTopParent(row) {
+ if (!this.normalizeParentId(row?.parentId)) {
+ row.parentId = 0;
+ }
+ },
isRootDept(row) {
return row && (row.parentId === 0 || String(row.parentId) === '0');
},
@@ -836,6 +862,7 @@ export default {
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
row.deptCode = String(row.deptCode || '').trim();
row.leaderId = func.join(row.leaderId);
+ this.normalizeTopParent(row);
if (Number(row.deptCategory) === 6 && !row.carrierCustomerId) {
this.$message.warning('请选择承运商');
loading();
@@ -865,6 +892,7 @@ export default {
row.tenantId = row.tenantId || this.userInfo.tenantId || website.tenantId;
row.deptCode = String(row.deptCode || '').trim();
row.leaderId = func.join(row.leaderId);
+ this.normalizeTopParent(row);
if (Number(row.deptCategory) === 6 && !row.carrierCustomerId) {
this.$message.warning('请选择承运商');
loading();
diff --git a/src/views/system/user.vue b/src/views/system/user.vue
index 107f5be..6d400fb 100644
--- a/src/views/system/user.vue
+++ b/src/views/system/user.vue
@@ -205,7 +205,7 @@
type="password"
show-password
autocomplete="new-password"
- placeholder="请输入登录密码"
+ placeholder="大于8位,含字母、数字、特殊字符.!@#$%^&*"
/>
@@ -332,7 +332,12 @@
-
+
@@ -424,6 +429,7 @@ import { mapGetters } from 'vuex';
import { h } from 'vue';
import { getToken } from '@/utils/auth';
import { downloadXls } from '@/utils/util';
+import { validateLoginPassword } from '@/utils/validate';
import NProgress from 'nprogress';
import 'nprogress/nprogress.css';
import func from '@/utils/func';
@@ -487,8 +493,7 @@ export default {
passwordForm: {},
passwordRules: {
password: [
- { required: true, message: '请输入新密码', trigger: 'blur' },
- { min: 6, max: 32, message: '密码长度在6到32个字符', trigger: 'blur' },
+ { required: true, validator: validateLoginPassword, trigger: 'blur' },
],
password2: [
{ required: true, message: '请再次输入新密码', trigger: 'blur' },
@@ -497,6 +502,7 @@ export default {
},
userRules: {
account: [{ required: true, message: '请输入账号名', trigger: 'blur' }],
+ password: [{ required: true, validator: validateLoginPassword, trigger: 'blur' }],
realName: [{ required: true, message: '请输入姓名', trigger: 'blur' }],
phone: [{ required: true, message: '请输入手机号', trigger: 'blur' }],
deptId: [{ required: true, message: '请选择所属组织', trigger: 'change' }],
diff --git a/src/views/system/userinfo.vue b/src/views/system/userinfo.vue
index a0d55f8..002ff50 100644
--- a/src/views/system/userinfo.vue
+++ b/src/views/system/userinfo.vue
@@ -91,7 +91,7 @@
@@ -143,6 +143,7 @@
import { getUserInfo, updateInfo, updatePassword } from '@/api/system/user';
import md5 from 'js-md5';
import { sensitive } from '@/utils/sensitive';
+import { isValidLoginPassword, LOGIN_PASSWORD_RULE_MESSAGE } from '@/utils/validate';
import {
Plus,
Bell,
@@ -259,6 +260,18 @@ export default {
},
// 提交密码修改
submitPassword() {
+ if (!this.passwordForm.newPassword || !this.passwordForm.newPassword1) {
+ this.$message.warning('请输入新密码和确认密码');
+ return;
+ }
+ if (this.passwordForm.newPassword !== this.passwordForm.newPassword1) {
+ this.$message.warning('两次输入的新密码不一致');
+ return;
+ }
+ if (!isValidLoginPassword(this.passwordForm.newPassword)) {
+ this.$message.warning(LOGIN_PASSWORD_RULE_MESSAGE);
+ return;
+ }
this.loading = true;
updatePassword(
md5(this.passwordForm.oldPassword),
diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue
index e6e507d..4c9baed 100644
--- a/src/views/vehicle/customer-archive.vue
+++ b/src/views/vehicle/customer-archive.vue
@@ -624,6 +624,7 @@
+
+
+
+
@@ -1500,7 +1504,7 @@ import {
getDetail as getCreditScoreQuantificationDetail,
} from '@/api/vehicle/credit-score-quantification';
import { getDictionary } from '@/api/system/dictbiz';
-import { processDelete, processSubmit } from '@/api/system/business-process';
+import { submitMkApprovalFlow } from '@/utils/mk-approval';
import { getDeptTree } from '@/api/system/dept';
import { getLazyTree } from '@/api/base/region';
import { exportBlob } from '@/api/common';
@@ -1539,6 +1543,12 @@ export default {
OpenFileViewer,
PdfPreview,
},
+ props: {
+ embeddedPublicId: {
+ type: [String, Number],
+ default: '',
+ },
+ },
data() {
const nonNegativeLabelMap = {
invoiceTaxRate: '开票税点',
@@ -1779,6 +1789,7 @@ export default {
accountName: [{ required: true, message: '请输入收款单位名称', trigger: 'blur' }],
accountHolderName: [{ required: true, message: '请输入开户人姓名', trigger: 'blur' }],
bankName: [{ required: true, message: '请输入开户行', trigger: 'blur' }],
+ cnapsCode: [{ required: true, message: '请输入联行号', trigger: 'blur' }],
bankAccount: [{ required: true, message: '请输入收款账号', trigger: 'blur' }],
remark: [{ max: 200, message: '备注最多200个字符', trigger: 'blur' }],
},
@@ -1994,7 +2005,7 @@ export default {
created() {
if (this.isPublicViewPage) {
this.readonly = true;
- const id = this.$route.query.id;
+ const id = this.embeddedPublicId || this.$route.query.id;
if (!id) {
this.archiveBox = true;
this.$message.error('缺少客商ID');
@@ -2029,7 +2040,9 @@ export default {
);
},
isPublicViewPage() {
- return this.$route.path === '/vehicle/customer-archive/public-view';
+ return (
+ this.$route.path === '/vehicle/customer-archive/public-view' || !!this.embeddedPublicId
+ );
},
archiveContainer() {
return 'div';
@@ -2695,6 +2708,7 @@ export default {
accountName: '',
accountHolderName: '',
bankName: '',
+ cnapsCode: '',
bankAccount: '',
registeredPhone: '',
registeredAddress: '',
@@ -4079,7 +4093,7 @@ export default {
.filter(item => item.contactName || item.contactPhone);
archive.receiptAccounts = (archive.receiptAccounts || [])
.map(item => this.normalizeReceipt(item))
- .filter(item => item.accountName || item.accountHolderName || item.bankAccount);
+ .filter(item => item.accountName || item.accountHolderName || item.bankAccount || item.cnapsCode);
archive.invoices = (archive.invoices || [])
.map(item => {
const invoice = this.normalizeInvoice(item);
@@ -4165,40 +4179,15 @@ export default {
});
},
/**
- * 列表 / 新增 / 编辑提交共用:提交 MK 审核流并更新客商审批状态
+ * 列表 / 新增 / 编辑提交共用:开启 MK 时提交审核流,并更新客商审批状态
*/
submitCustomerApproval(id, fullName = '', approvalStatus = '') {
- return this.submitMkApprovalFlow(id, fullName, approvalStatus).then(() => submitApproval(id));
- },
- /**
- * 提交 MK 审核流:templateCode 取业务字典 mk_template 中「提交客商审核流」的键值
- * 提交人手机号由后端从用户表读取真实值(前端接口会脱敏)
- * MK 驳回后再提交时,先删除旧流程再创建新流程
- */
- async submitMkApprovalFlow(formInstanceId, subjectName = '', approvalStatus = '') {
- if (approvalStatus === 'rejected') {
- await processDelete({ formInstanceId: String(formInstanceId) });
- }
- const templateCode = await this.resolveMkTemplateCode('提交客商审核流');
- const subject = subjectName
- ? `客商准入审批:${subjectName}`
- : `客商准入审批:${formInstanceId}`;
- return processSubmit({
- templateCode,
- formInstanceId: String(formInstanceId),
- subject,
- });
- },
- async resolveMkTemplateCode(dictName = '提交客商审核流') {
- const res = await getDictionary({ code: 'mk_template' });
- const list = res?.data?.data || [];
- const matched = list.find(item => String(item.dictValue || '').trim() === dictName);
- const templateCode = matched?.dictKey;
- if (!templateCode) {
- this.$message.warning(`未配置业务字典 mk_template「${dictName}」,无法提交审核流`);
- return Promise.reject(new Error(`未配置业务字典 mk_template「${dictName}」`));
- }
- return String(templateCode);
+ return submitMkApprovalFlow({
+ bizType: 'customer-archive',
+ formInstanceId: id,
+ subjectName: fullName,
+ approvalStatus,
+ }).then(() => submitApproval(id));
},
addScore() {
this.scoreRecordIndex = -1;
@@ -5309,6 +5298,16 @@ export default {
.invoice-form {
max-width: none;
+
+ :deep(.el-input),
+ :deep(.el-cascader),
+ :deep(.el-select) {
+ width: 100%;
+ }
+
+ :deep(.el-cascader .el-input) {
+ width: 100%;
+ }
}
.invoice-contact-table {
diff --git a/src/views/vehicle/maintenance-plan.vue b/src/views/vehicle/maintenance-plan.vue
index 79cc1b8..5a83a9f 100644
--- a/src/views/vehicle/maintenance-plan.vue
+++ b/src/views/vehicle/maintenance-plan.vue
@@ -564,8 +564,8 @@ export default {
this.addressMapPickerVisible = true;
}
},
- handleAddressMapConfirm(address) {
- this.form.address = address;
+ handleAddressMapConfirm(payload) {
+ this.form.address = typeof payload === 'string' ? payload : payload?.address || '';
},
hasPermission(code) {
return this.isAdmin || this.validData(this.permission[code], false);
diff --git a/src/views/vehicle/maintenance-record.vue b/src/views/vehicle/maintenance-record.vue
index 77dd905..506adae 100644
--- a/src/views/vehicle/maintenance-record.vue
+++ b/src/views/vehicle/maintenance-record.vue
@@ -545,8 +545,8 @@ export default {
this.addressMapPickerVisible = true;
}
},
- handleAddressMapConfirm(address) {
- this.form.address = address;
+ handleAddressMapConfirm(payload) {
+ this.form.address = typeof payload === 'string' ? payload : payload?.address || '';
},
hasPermission(code) {
return this.isAdmin || this.validData(this.permission[code], false);
diff --git a/src/views/vehicle/violation-record.vue b/src/views/vehicle/violation-record.vue
index bc50708..bb3d1e6 100644
--- a/src/views/vehicle/violation-record.vue
+++ b/src/views/vehicle/violation-record.vue
@@ -288,8 +288,8 @@ export default {
this.locationMapPickerVisible = true;
}
},
- handleLocationMapConfirm(address) {
- this.form.location = address;
+ handleLocationMapConfirm(payload) {
+ this.form.location = typeof payload === 'string' ? payload : payload?.address || '';
},
hasPermission(code) {
return this.isAdmin || this.validData(this.permission[code], false);