From d7969c191a8e557edfcec9a7a9e57983d3689274 Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Thu, 22 Oct 2026 12:56:50 +0800 Subject: [PATCH] =?UTF-8?q?:sparkles:=20=E5=AE=A2=E5=95=86=E6=A1=A3?= =?UTF-8?q?=E6=A1=88=E8=A1=A8=E5=8D=95=E9=87=8D=E6=9E=84=EF=BC=8C=E5=90=88?= =?UTF-8?q?=E5=90=8C=E6=B5=81=E6=B0=B4=E5=8F=B7-1=E5=88=97=E8=A1=A8?= =?UTF-8?q?=E6=98=BE=E7=A4=BA=E4=B8=BA=E7=A9=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Cursor --- src/views/system/dept.vue | 3 + src/views/vehicle/customer-archive.vue | 333 +++++++++++++++---------- 2 files changed, 206 insertions(+), 130 deletions(-) diff --git a/src/views/system/dept.vue b/src/views/system/dept.vue index 157a1be..a22b6f3 100644 --- a/src/views/system/dept.vue +++ b/src/views/system/dept.vue @@ -425,6 +425,9 @@ export default { minWidth: 140, order: 61, placeholder: '如 1', + // -1 为空占位,列表展示为空 + formatter: row => + Number(row.contractInitialSerial) === -1 ? '' : row.contractInitialSerial, tip: '该部门当年首个合同时从此流水号起编,后续递增;范围1-999,不填默认从1开始', rules: [ { diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue index 510fa24..ca840d2 100644 --- a/src/views/vehicle/customer-archive.vue +++ b/src/views/vehicle/customer-archive.vue @@ -363,47 +363,6 @@ /> - - - - - - - - - -
- - - 无固定期限 - -
-
-
- - - - - - - - - - - - - + + +
+ + 至 + + + 无固定期限 + +
- - - - - - - - - - - -
-
- - - - + @@ -535,6 +495,29 @@ + + + + + + + + + + - + @@ -1620,8 +1610,10 @@ export default { const nonNegativeLabelMap = { invoiceTaxRate: '开票税点', registeredCapital: '注册资金', + paidInCapital: '实缴资本', maxCreditLimit: '最大资金使用额度', applyCreditLimit: '申请总资金使用额度', + usedCreditLimit: '已使用额度', }; const validateNonNegative = (rule, value, callback) => { if (value === undefined || value === null || value === '') { @@ -1632,15 +1624,6 @@ export default { callback(); } }; - const validateInvoiceTaxRate = (rule, value, callback) => { - if (value === undefined || value === null || value === '') { - callback(); - } else if (Number(value) < 0 || Number(value) > 13) { - callback(new Error('开票税点必须在0到13之间')); - } else { - callback(); - } - }; const validateUnifiedCreditCode = (rule, value, callback) => { const code = String(value || '') .trim() @@ -1767,7 +1750,7 @@ export default { { label: '是', value: 1 }, { label: '否', value: 0 }, ], - businessScopeOptions: [], + bankListOptions: [], qualificationTypeOptions: [], creditLevelOptions: ['A', 'B', 'C', 'D', 'E', 'F'].map(item => ({ label: `${item}级`, @@ -1806,15 +1789,12 @@ export default { ], customerType: [{ required: true, message: '请选择客商分类', trigger: 'change' }], legalPerson: [{ required: true, message: '请输入企业法人', trigger: 'blur' }], - contactPhone: [ - { required: true, message: '请输入联系电话', trigger: 'blur' }, - { pattern: /^1\d{10}$/, message: '联系电话必须为11位手机号', trigger: 'blur' }, - ], - deptName: [{ required: true, message: '请选择所属组织', trigger: 'change' }], - invoiceTaxRate: [{ validator: validateInvoiceTaxRate, trigger: 'blur' }], registeredCapital: [{ validator: validateNonNegative, trigger: 'blur' }], + paidInCapital: [{ validator: validateNonNegative, trigger: 'blur' }], maxCreditLimit: [{ validator: validateNonNegative, trigger: 'blur' }], applyCreditLimit: [{ validator: validateNonNegative, trigger: 'blur' }], + usedCreditLimit: [{ validator: validateNonNegative, trigger: 'blur' }], + businessScope: [{ max: 2000, message: '经营范围最多2000个字符', trigger: 'blur' }], registeredRegionName: [{ required: true, message: '请选择省市区', trigger: 'change' }], registeredDetailAddress: [ { required: true, message: '请输入详细地址', trigger: 'blur' }, @@ -2361,7 +2341,6 @@ export default { ensurePublicViewOptions(archive = {}) { this.mergeSelectOptions('customerNatureOptions', archive.customerNature); this.mergeSelectOptions('customerTypeOptions', archive.customerType); - this.mergeSelectOptions('businessScopeOptions', archive.businessScope); this.mergeSelectOptions( 'qualificationTypeOptions', (this.qualificationFiles || []).map(item => item.type) @@ -2419,9 +2398,11 @@ export default { form.fullName = ''; form.legalPerson = ''; form.registeredCapital = ''; + form.paidInCapital = ''; form.registeredDetailAddress = ''; - form.businessScope = []; + form.businessScope = ''; form.businessTermType = '固定期限'; + form.businessStartDate = ''; form.businessEndDate = ''; }, // 新增态下统一社会信用代码录入完成后自动查询金蝶(A902-1),防抖 500ms; @@ -2479,14 +2460,7 @@ export default { } if (customer.businessterm) this.applyBusinessTermRecognition(customer.businessterm); if (customer.businessscope) { - const matchedScopes = this.businessScopeOptions - .filter( - item => - customer.businessscope.includes(item.label) || - customer.businessscope.includes(item.value) - ) - .map(item => item.value); - if (matchedScopes.length) form.businessScope = matchedScopes; + form.businessScope = String(customer.businessscope).trim(); } if (!form.shortName && customer.simplename) form.shortName = customer.simplename; this.$nextTick(() => { @@ -2495,6 +2469,8 @@ export default { 'fullName', 'legalPerson', 'registeredCapital', + 'paidInCapital', + 'businessStartDate', 'businessEndDate', 'businessScope', 'registeredDetailAddress', @@ -2517,8 +2493,13 @@ export default { deptIds: '', deptName: '', customerType: [], - businessScope: [], + businessScope: '', businessTermType: '固定期限', + businessStartDate: '', + businessEndDate: '', + registeredCapital: '', + paidInCapital: '', + usedCreditLimit: '', networkFreightPlatform: null, guangxiTop100: null, registeredRegionPath: [], @@ -2653,6 +2634,12 @@ export default { approvedTime: '审核通过时间', status: '状态', businessTermType: '营业期限类型', + businessStartDate: '营业期限开始日', + businessEndDate: '营业期限截止日', + registeredCapital: '注册资金(万元)', + paidInCapital: '实缴资本(万元)', + usedCreditLimit: '已使用额度(万元)', + businessScope: '经营范围', networkFreightPlatform: '网络货运平台', registeredRegionName: '注册地址', registeredDetailAddress: '详细地址', @@ -3101,11 +3088,21 @@ export default { const customerTypeColumn = this.findColumn(this.option.column, 'customerType'); customerTypeColumn.dicData = [{ label: '全部', value: '' }, ...options]; }); - this.loadDictOptions('scope_of_business', 'businessScopeOptions'); + this.loadDictOptions('bank_list', 'bankListOptions'); this.loadDictOptions('customer_attachment_types', 'qualificationTypeOptions', [], () => { this.sortQualificationFiles(); }); }, + queryBankNameSuggestions(queryString, callback) { + const query = String(queryString || '') + .trim() + .toLowerCase(); + const options = Array.isArray(this.bankListOptions) ? this.bankListOptions : []; + const matched = query + ? options.filter(item => String(item.value || '').toLowerCase().includes(query)) + : options; + callback(matched.map(item => ({ value: item.value }))); + }, initMkEnabled() { this._mkEnabledResolved = false; loadMkEnabled() @@ -3359,8 +3356,15 @@ export default { }); }, formatBusinessLicenseValidPeriod(row = {}) { - if (row.businessTermType === '长期') return '无固定期限'; - return row.businessEndDate || ''; + if (row.businessTermType === '长期') { + return row.businessStartDate + ? `${row.businessStartDate} 至 无固定期限` + : '无固定期限'; + } + if (row.businessStartDate && row.businessEndDate) { + return `${row.businessStartDate} 至 ${row.businessEndDate}`; + } + return row.businessEndDate || row.businessStartDate || ''; }, formatFundUseRate(row = {}) { if (row.fundUseRate === undefined || row.fundUseRate === null || row.fundUseRate === '') { @@ -3893,8 +3897,13 @@ export default { const legalPerson = this.getBusinessLicenseOcrValue(result, ['法定代表人', '法人']); const address = this.getBusinessLicenseOcrValue(result, ['地址', '住所']); const capital = this.getBusinessLicenseOcrValue(result, ['注册资本']); + const paidInCapital = this.getBusinessLicenseOcrValue(result, ['实缴资本', '实收资本']); const term = this.getBusinessLicenseOcrValue(result, ['营业期限', '有效期']); - const termStartDate = this.getBusinessLicenseOcrValue(result, ['有效期起始日期']); + const termStartDate = this.getBusinessLicenseOcrValue(result, [ + '有效期起始日期', + '成立日期', + '核准日期', + ]); const scope = this.getBusinessLicenseOcrValue(result, ['经营范围']); if (code) this.archiveForm.unifiedCreditCode = code.replace(/\s/g, '').toUpperCase(); if (name) this.archiveForm.fullName = name; @@ -3908,15 +3917,16 @@ export default { const normalizedCapital = capital.replace(/,/g, '').match(/\d+(?:\.\d+)?/); if (normalizedCapital) this.archiveForm.registeredCapital = normalizedCapital[0]; } - this.applyBusinessTermRecognition(term); + if (paidInCapital) { + const normalizedPaidIn = paidInCapital.replace(/,/g, '').match(/\d+(?:\.\d+)?/); + if (normalizedPaidIn) this.archiveForm.paidInCapital = normalizedPaidIn[0]; + } + this.applyBusinessTermRecognition(term, termStartDate); if (this.isNoFixedBusinessTerm(term) || this.isNoFixedBusinessTerm(termStartDate)) { this.handleNoFixedTermChange(true); } if (scope) { - const matchedScopes = this.businessScopeOptions - .filter(item => scope.includes(item.label) || scope.includes(item.value)) - .map(item => item.value); - if (matchedScopes.length) this.archiveForm.businessScope = matchedScopes; + this.archiveForm.businessScope = scope; } this.$nextTick(() => { [ @@ -3924,27 +3934,49 @@ export default { 'fullName', 'legalPerson', 'registeredCapital', + 'paidInCapital', + 'businessStartDate', 'businessEndDate', 'businessScope', 'registeredDetailAddress', ].forEach(prop => this.$refs.archiveForm?.validateField(prop)); }); }, - applyBusinessTermRecognition(term) { + normalizeOcrDate(value) { + if (!value) return ''; + const match = String(value).match(/(\d{4})[年./-](\d{1,2})[月./-](\d{1,2})/); + if (!match) return ''; + const month = String(match[2]).padStart(2, '0'); + const day = String(match[3]).padStart(2, '0'); + return `${match[1]}-${month}-${day}`; + }, + applyBusinessTermRecognition(term, termStartDate = '') { + const startFromField = this.normalizeOcrDate(termStartDate); + if (startFromField) { + this.archiveForm.businessStartDate = startFromField; + } if (!term) return; - if (/长期|永久/.test(term)) { + if (/长期|永久|无固定/.test(term) || this.isNoFixedBusinessTerm(term)) { this.archiveForm.businessTermType = '长期'; this.archiveForm.businessEndDate = ''; return; } - const match = term.match(/(\d{4}[年./-]\d{1,2}[月./-]\d{1,2})/); - if (!match) return; - const date = match[1] - .replace(/[年./]/g, '-') - .replace('月', '-') - .replace('日', ''); - this.archiveForm.businessTermType = '固定期限'; - this.archiveForm.businessEndDate = date; + const dateMatches = String(term).match(/\d{4}[年./-]\d{1,2}[月./-]\d{1,2}/g) || []; + const startDate = this.normalizeOcrDate(dateMatches[0]) || startFromField; + const endDate = this.normalizeOcrDate(dateMatches[1]); + if (startDate) { + this.archiveForm.businessStartDate = startDate; + } + if (endDate) { + this.archiveForm.businessTermType = '固定期限'; + this.archiveForm.businessEndDate = endDate; + return; + } + if (startDate && dateMatches.length === 1 && !/至|到|-|—|~/.test(term)) { + // 仅识别到一个日期且无区间分隔时,按截止日处理(兼容旧 OCR 结果) + this.archiveForm.businessTermType = '固定期限'; + this.archiveForm.businessEndDate = startDate; + } }, getQualificationFileUrl(file = {}) { return file.url || file.link || file.domain || ''; @@ -4112,7 +4144,6 @@ export default { return value; }, normalizeDetail(detail) { - const businessScope = this.splitValue(detail.businessScope); const registeredDetailAddress = detail.registeredDetailAddress || (detail.registeredRegionName ? '' : detail.registeredAddress) || @@ -4125,10 +4156,14 @@ export default { customerKind: detail.customerKind || 'external', invoiceTaxRate: this.normalizeOptionalAmount(detail.invoiceTaxRate), registeredCapital: this.normalizeOptionalAmount(detail.registeredCapital), + paidInCapital: this.normalizeOptionalAmount(detail.paidInCapital), maxCreditLimit: this.normalizeOptionalAmount(detail.maxCreditLimit), applyCreditLimit: this.normalizeOptionalAmount(detail.applyCreditLimit), - businessScope, + usedCreditLimit: this.normalizeOptionalAmount(detail.usedCreditLimit), + businessScope: detail.businessScope || '', businessTermType: detail.businessTermType || '固定期限', + businessStartDate: detail.businessStartDate || '', + businessEndDate: detail.businessEndDate || '', networkFreightPlatform: detail.networkFreightPlatform === 0 || detail.networkFreightPlatform === 1 ? detail.networkFreightPlatform @@ -4348,16 +4383,21 @@ export default { if (archive.businessTermType === '长期') { archive.businessEndDate = null; } + if (!archive.businessStartDate) { + archive.businessStartDate = null; + } const invoiceTaxRate = this.normalizeOptionalAmount(archive.invoiceTaxRate); const registeredCapital = this.normalizeOptionalAmount(archive.registeredCapital); + const paidInCapital = this.normalizeOptionalAmount(archive.paidInCapital); + const usedCreditLimit = this.normalizeOptionalAmount(archive.usedCreditLimit); archive.invoiceTaxRate = invoiceTaxRate === '' ? null : invoiceTaxRate; archive.registeredCapital = registeredCapital === '' ? null : registeredCapital; + archive.paidInCapital = paidInCapital === '' ? null : paidInCapital; + archive.usedCreditLimit = usedCreditLimit === '' ? null : usedCreditLimit; archive.customerType = Array.isArray(archive.customerType) ? archive.customerType.join(',') : archive.customerType; - archive.businessScope = Array.isArray(archive.businessScope) - ? archive.businessScope.join(',') - : archive.businessScope; + archive.businessScope = String(archive.businessScope || '').trim(); archive.networkFreightPlatform = archive.networkFreightPlatform === 0 || archive.networkFreightPlatform === 1 ? archive.networkFreightPlatform @@ -4388,6 +4428,11 @@ export default { return contact; }) .filter(item => item.contactName || item.contactPhone); + // 主表联系电话改由联系人维护,取第一条有效手机号回填 + const firstContactPhone = (archive.contacts || []) + .map(item => String(item.contactPhone || '').trim()) + .find(Boolean); + archive.contactPhone = firstContactPhone || null; archive.receiptAccounts = (archive.receiptAccounts || []) .map(item => this.normalizeReceipt(item)) .filter(item => item.accountName || item.accountHolderName || item.bankAccount || item.cnapsCode); @@ -4426,16 +4471,29 @@ export default { archive.applyCreditLimit = applyCreditLimit === '' ? null : applyCreditLimit; return archive; }, + validateContactsRequired(archive = this.archiveForm) { + const contacts = (archive.contacts || []).filter( + item => String(item.contactName || '').trim() || String(item.contactPhone || '').trim() + ); + if (!contacts.length) { + this.$message.warning('请至少维护一条联系人'); + this.activeTab = 'contacts'; + return false; + } + return true; + }, saveArchive() { if (this.kingdeeBlocked) { this.$message.warning('金蝶审核中,请稍后重新添加'); return; } + this.applyFixedOwnerDept(); this.$refs.archiveForm.validate(valid => { if (!valid) { this.$message.warning('请先完整填写必填项'); return; } + if (!this.validateContactsRequired()) return; submit(this.normalizeArchive()).then(() => { this.closeArchive(); this.onLoad(this.page); @@ -4448,11 +4506,13 @@ export default { this.$message.warning('金蝶审核中,请稍后重新添加'); return; } + this.applyFixedOwnerDept(); this.$refs.archiveForm.validate(valid => { if (!valid) { this.$message.warning('请先完整填写必填项'); return; } + if (!this.validateContactsRequired()) return; const archive = this.normalizeArchive(); // 仅提交时落变更记录;保存不记录 archive.recordChange = true; @@ -5174,6 +5234,7 @@ export default { getDetail(row.id).then(res => { const archive = this.normalizeDetail(res.data.data); archive.qualificationAttachments = archive.qualificationAttachments || ''; + if (!this.validateContactsRequired(archive)) return; if (!this.validateScoreForApproval(archive)) return; this.$confirm('是否提交客商准入审批?', '提示', { confirmButtonText: '确定', @@ -5501,7 +5562,8 @@ export default { display: flex; align-items: center; gap: 8px; - flex-wrap: nowrap; + flex-wrap: wrap; + width: 100%; :deep(.el-date-editor) { flex: 0 0 140px; @@ -5509,6 +5571,11 @@ export default { min-width: 0; } + .business-term-separator { + flex: 0 0 auto; + color: #606266; + } + :deep(.el-checkbox) { flex: 0 0 auto; margin-right: 0; @@ -5516,6 +5583,10 @@ export default { } } +.invoice-bank-autocomplete { + width: 100%; +} + .archive-form__address { :deep(.el-cascader) { flex: 0 0 240px; @@ -5743,11 +5814,13 @@ export default { :deep(.el-input), :deep(.el-cascader), - :deep(.el-select) { + :deep(.el-select), + :deep(.el-autocomplete) { width: 100%; } - :deep(.el-cascader .el-input) { + :deep(.el-cascader .el-input), + :deep(.el-autocomplete .el-input) { width: 100%; } }