1、基础数据修复bug

2、客商模块修复bug
This commit is contained in:
2026-08-06 02:57:55 +08:00
parent e5a7aca09e
commit c339852e04
24 changed files with 1612 additions and 548 deletions

View File

@@ -20,7 +20,6 @@
<el-button
type="primary"
icon="el-icon-plus"
plain
v-if="hasPermission('customer_archive_add')"
@click="openArchive()"
>新增
@@ -87,6 +86,16 @@
>
提交
</el-link>
<el-link
type="warning"
v-if="
hasPermission('customer_archive_submit') &&
['draft', 'reviewing'].includes(row.approvalStatus)
"
@click="handleWithdrawApproval(row)"
>
撤回
</el-link>
<el-link
type="success"
v-if="hasPermission('customer_archive_approve') && row.approvalStatus === 'reviewing'"
@@ -153,7 +162,12 @@
</el-col>
<el-col :span="6">
<el-form-item label="客商性质" prop="customerNature">
<el-select v-model="archiveForm.customerNature" filterable clearable>
<el-select
v-model="archiveForm.customerNature"
placeholder="请输入"
filterable
clearable
>
<el-option
v-for="item in customerNatureOptions"
:key="item.value"
@@ -167,6 +181,7 @@
<el-form-item label="统一社会信用代码" prop="unifiedCreditCode">
<el-input
v-model="archiveForm.unifiedCreditCode"
placeholder="请输入"
maxlength="18"
show-word-limit
@input="
@@ -179,12 +194,22 @@
</el-col>
<el-col :span="6">
<el-form-item label="客商名称" prop="fullName">
<el-input v-model="archiveForm.fullName" maxlength="100" show-word-limit />
<el-input
v-model="archiveForm.fullName"
placeholder="请输入"
maxlength="100"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="客商类型" prop="customerType">
<el-select v-model="archiveForm.customerType" filterable clearable>
<el-select
v-model="archiveForm.customerType"
placeholder="请输入"
filterable
clearable
>
<el-option
v-for="item in customerTypeOptions"
:key="item.value"
@@ -200,7 +225,7 @@
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="经营范围" prop="businessScope">
<el-form-item label="经营范围" prop="businessScope" required>
<el-select v-model="archiveForm.businessScope" multiple filterable clearable>
<el-option
v-for="item in businessScopeOptions"
@@ -237,11 +262,16 @@
</el-col>
<el-col :span="6">
<el-form-item label="客户简称" prop="shortName">
<el-input v-model="archiveForm.shortName" maxlength="20" show-word-limit />
<el-input
v-model="archiveForm.shortName"
placeholder="请输入"
maxlength="20"
show-word-limit
/>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="地址" prop="registeredDetailAddress">
<el-form-item label="地址" prop="registeredDetailAddress" required>
<div class="archive-form__address">
<el-cascader
ref="registeredRegionCascader"
@@ -333,13 +363,13 @@
</el-form-item>
</el-col>
<el-col :span="6">
<el-form-item label="申请总资金使用额度(万元)" prop="applyCreditLimit">
<el-input
v-model="archiveForm.applyCreditLimit"
maxlength="18"
@input="value => handleDecimalInput('applyCreditLimit', value)"
/>
</el-form-item>
<el-form-item label="申请总资金使用额度(万元)" prop="applyCreditLimit">
<el-input
v-model="archiveForm.applyCreditLimit"
maxlength="18"
disabled
/>
</el-form-item>
</el-col>
</el-row>
</div>
@@ -559,7 +589,7 @@
<el-alert
type="info"
:closable="false"
title="支持 JPG、PNG、PDF、Word、Excel、PPT,单文件大小不超过 10MB。"
title="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单文件大小限制500M"
class="archive-rule-alert"
/>
<el-alert
@@ -586,8 +616,8 @@
v-model="row.files"
:readonly="readonly"
:multiple="false"
accept=".jpg,.jpeg,.png,.pdf,.doc,.docx,.xls,.xlsx,.ppt,.pptx"
:max-size="10"
accept=".pdf,.bmp,.jpeg,.png,.jpg,.doc,.docx,.ppt,.pptx,.xlsx,.xls,.eml,.msg,.zip"
:max-size="500"
button-text="上传文件"
:show-tip="false"
@success="file => handleQualificationUploadSuccess(file, row)"
@@ -658,13 +688,13 @@
label-width="110px"
class="contact-form"
>
<el-form-item label="联系人姓名" prop="contactName">
<el-form-item label="联系人姓名" prop="contactName" class="contact-form__compact-field">
<el-input v-model="contactForm.contactName" maxlength="30" />
</el-form-item>
<el-form-item label="手机号" prop="contactPhone">
<el-form-item label="手机号" prop="contactPhone" class="contact-form__compact-field">
<el-input v-model="contactForm.contactPhone" maxlength="11" />
</el-form-item>
<el-form-item label="邮箱" prop="email">
<el-form-item label="邮箱" prop="email" class="contact-form__compact-field">
<el-input v-model="contactForm.email" maxlength="100" />
</el-form-item>
<el-form-item label="地址" prop="detailAddress">
@@ -685,13 +715,15 @@
/>
</div>
</el-form-item>
<el-form-item label="备注" prop="remark">
<el-form-item label="备注" prop="remark" class="contact-form__compact-field">
<el-input v-model="contactForm.remark" maxlength="200" />
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="saveContact">保存</el-button>
<el-button @click="contactBox = false">返回</el-button>
<div class="contact-dialog__footer-actions">
<el-button type="primary" @click="saveContact">保存</el-button>
<el-button @click="contactBox = false">返回</el-button>
</div>
</template>
</el-dialog>
@@ -778,8 +810,10 @@
</el-form-item>
</el-form>
<template #footer>
<el-button type="primary" @click="saveReceipt">保存</el-button>
<el-button @click="receiptBox = false">返回</el-button>
<div class="receipt-dialog__footer-actions">
<el-button type="primary" @click="saveReceipt">保存</el-button>
<el-button @click="receiptBox = false">返回</el-button>
</div>
</template>
</el-dialog>
@@ -809,24 +843,24 @@
<el-input v-model="invoiceForm.registeredPhone" maxlength="20" />
</el-form-item>
<el-form-item label="注册地址" prop="registeredRegionName">
<div class="invoice-form__address">
<el-input
v-model="invoiceForm.registeredRegionName"
readonly
maxlength="100"
placeholder="点击后弹出地图组件"
suffix-icon="el-icon-location"
@click="handleInvoiceRegisteredMapPick"
/>
<el-input
v-model="invoiceForm.registeredDetailAddress"
readonly
maxlength="255"
placeholder="点击后弹出地图组件"
suffix-icon="el-icon-location"
@click="handleInvoiceRegisteredMapPick"
/>
</div>
<el-input
v-model="invoiceForm.registeredRegionName"
readonly
maxlength="100"
placeholder="点击后弹出地图组件"
suffix-icon="el-icon-location"
@click="handleInvoiceRegisteredMapPick"
/>
</el-form-item>
<el-form-item label="详细地址" prop="registeredDetailAddress">
<el-input
v-model="invoiceForm.registeredDetailAddress"
readonly
maxlength="255"
placeholder="点击后弹出地图组件"
suffix-icon="el-icon-location"
@click="handleInvoiceRegisteredMapPick"
/>
</el-form-item>
</el-col>
<el-col :span="12">
@@ -880,8 +914,10 @@
</el-row>
</el-form>
<template #footer>
<el-button type="primary" @click="saveInvoice">保存</el-button>
<el-button @click="invoiceBox = false">返回</el-button>
<div class="invoice-dialog__footer-actions">
<el-button type="primary" @click="saveInvoice">保存</el-button>
<el-button @click="invoiceBox = false">返回</el-button>
</div>
</template>
</el-dialog>
@@ -1097,7 +1133,7 @@
</el-table-column>
<el-table-column label="操作" width="120" align="center" v-if="!readonly">
<template #default="{ $index }">
<el-link type="primary" @click="scoreAttachmentFiles.splice($index, 1)">
<el-link type="primary" @click="deleteScoreAttachment($index)">
删除
</el-link>
</template>
@@ -1120,6 +1156,7 @@ import {
getDetail,
submit,
submitApproval,
withdrawApproval,
approve,
reject,
changeStatus,
@@ -1187,11 +1224,11 @@ export default {
callback();
}
};
const validateInvoiceRegisteredAddress = (rule, value, callback) => {
const regionName = (this.invoiceForm.registeredRegionName || '').trim();
const detailAddress = (this.invoiceForm.registeredDetailAddress || '').trim();
const validateRegisteredAddress = (rule, value, callback) => {
const regionName = (this.archiveForm.registeredRegionName || '').trim();
const detailAddress = String(value || '').trim();
if (!regionName) {
callback(new Error('请选择注册地址'));
callback(new Error('请选择省市区'));
} else if (!detailAddress) {
callback(new Error('请输入详细地址'));
} else if (detailAddress.length > 255) {
@@ -1203,6 +1240,7 @@ export default {
return {
form: {},
query: {},
deptSearchInitialized: false,
loading: true,
data: [],
page: {
@@ -1312,8 +1350,18 @@ export default {
maxCreditLimit: [{ validator: validateNonNegative, trigger: 'blur' }],
applyCreditLimit: [{ validator: validateNonNegative, trigger: 'blur' }],
businessEndDate: [{ validator: validateBusinessEndDate, trigger: 'change' }],
registeredDetailAddress: [{ max: 255, message: '详细地址最多255个字符', trigger: 'blur' }],
businessScope: [{ type: 'array', message: '请选择经营范围', trigger: 'change' }],
registeredDetailAddress: [
{ validator: validateRegisteredAddress, trigger: ['change', 'blur'] },
],
businessScope: [
{
required: true,
type: 'array',
min: 1,
message: '请选择经营范围',
trigger: 'change',
},
],
remark: [{ max: 500, message: '备注最多500个字符', trigger: 'blur' }],
},
contactRules: {
@@ -1339,7 +1387,11 @@ export default {
registeredPhone: [{ required: true, message: '请输入注册电话', trigger: 'blur' }],
bankName: [{ required: true, message: '请输入开户行名称', trigger: 'blur' }],
registeredRegionName: [
{ required: true, validator: validateInvoiceRegisteredAddress, trigger: 'blur' },
{ required: true, message: '请选择注册地址', trigger: 'blur' },
],
registeredDetailAddress: [
{ required: true, message: '请输入详细地址', trigger: 'blur' },
{ max: 255, message: '详细地址最多255个字符', trigger: 'blur' },
],
bankAccount: [{ required: true, message: '请输入银行账号', trigger: 'blur' }],
receiverDetailAddress: [
@@ -1376,6 +1428,7 @@ export default {
slot: true,
search: true,
searchOrder: 10,
searchPlaceholder: '请输入',
minWidth: 140,
},
{
@@ -1383,6 +1436,7 @@ export default {
prop: 'shortName',
search: true,
searchOrder: 2,
searchPlaceholder: '请输入',
minWidth: 150,
},
{
@@ -1390,6 +1444,7 @@ export default {
prop: 'fullName',
search: true,
searchOrder: 9,
searchPlaceholder: '请输入',
minWidth: 220,
overHidden: true,
},
@@ -1399,8 +1454,10 @@ export default {
search: true,
searchType: 'select',
searchOrder: 7,
searchValue: '',
searchPlaceholder: '请输入',
minWidth: 140,
dicData: this.customerTypeOptions,
dicData: [{ label: '全部', value: '' }],
},
{
label: '客户性质',
@@ -1408,8 +1465,11 @@ export default {
type: 'select',
search: true,
searchOrder: 5,
searchValue: '',
searchPlaceholder: '请输入',
minWidth: 120,
dicData: [
{ label: '全部', value: '' },
{ label: '有限公司', value: '有限公司' },
{ label: '个体工商户', value: '个体工商户' },
],
@@ -1419,6 +1479,7 @@ export default {
prop: 'unifiedCreditCode',
search: true,
searchOrder: 3,
searchPlaceholder: '请输入',
minWidth: 190,
},
{
@@ -1427,8 +1488,9 @@ export default {
search: true,
searchType: 'select',
searchOrder: 1,
searchValue: '',
minWidth: 180,
dicData: [],
dicData: [{ label: '全部', value: '' }],
},
{
label: '准入标准',
@@ -1439,8 +1501,8 @@ export default {
searchOrder: 8,
minWidth: 120,
dicData: [
{ label: '临时客商', value: 'temporary' },
{ label: '正式客商', value: 'formal' },
{ label: '临时', value: 'temporary' },
{ label: '正式', value: 'formal' },
],
},
{
@@ -1450,8 +1512,10 @@ export default {
type: 'select',
search: true,
searchOrder: 4,
searchValue: '',
minWidth: 130,
dicData: [
{ label: '全部', value: '' },
{ label: '草稿', value: 'draft' },
{ label: '审核中', value: 'reviewing' },
{ label: '审核通过', value: 'approved' },
@@ -1475,9 +1539,11 @@ export default {
type: 'select',
search: true,
searchOrder: 6,
searchValue: '',
dataType: 'number',
minWidth: 100,
dicData: [
{ label: '全部', value: '' },
{ label: '启用', value: 1 },
{ label: '停用', value: 2 },
],
@@ -1743,15 +1809,38 @@ export default {
};
},
initDeptTree() {
getDeptTree(this.userInfo.tenantId).then(res => {
this.deptTree = this.normalizeDeptTree(res.data.data || []);
this.deptOptions = this.flattenDept(this.deptTree);
const deptColumn = this.findColumn(this.option.column, 'deptName');
deptColumn.dicData = this.deptOptions.map(item => ({
label: item.label,
value: item.rawLabel,
}));
});
getDeptTree(this.userInfo.tenantId)
.then(res => {
this.deptTree = this.normalizeDeptTree(res.data.data || []);
this.deptOptions = this.flattenDept(this.deptTree);
const deptColumn = this.findColumn(this.option.column, 'deptName');
deptColumn.dicData = [
{ label: '全部', value: '' },
...this.deptOptions.map(item => ({
label: item.label,
value: item.rawLabel,
})),
];
this.applyDefaultDeptSearch(deptColumn);
})
.finally(() => {
this.deptSearchInitialized = true;
this.$nextTick(() => this.onLoad(this.page, this.query));
});
},
applyDefaultDeptSearch(deptColumn) {
if (this.isAdmin) return;
const currentDeptId = this.userInfo.deptId || this.userInfo.dept_id;
const currentDept = this.deptOptions.find(
item => String(item.value) === String(currentDeptId)
);
const deptName = currentDept?.rawLabel || this.userInfo.deptName || this.userInfo.dept_name;
if (!deptName) return;
deptColumn.searchValue = deptName;
this.query = { ...this.query, deptName };
if (this.$refs.crud?.searchForm) {
this.$refs.crud.searchForm.deptName = deptName;
}
},
initRegionOptions() {
getLazyTree().then(res => {
@@ -1834,10 +1923,12 @@ export default {
handleRegisteredRegionChange(value) {
if (!value || !value.length) {
this.archiveForm.registeredRegionName = '';
this.$refs.archiveForm?.validateField('registeredDetailAddress');
return;
}
this.$nextTick(() => {
this.archiveForm.registeredRegionName = this.getRegisteredRegionLabels(value).join('');
this.$refs.archiveForm?.validateField('registeredDetailAddress');
});
},
initBusinessDictionaries() {
@@ -1847,12 +1938,12 @@ export default {
['有限公司', '个体工商户'],
options => {
const customerNatureColumn = this.findColumn(this.option.column, 'customerNature');
customerNatureColumn.dicData = options;
customerNatureColumn.dicData = [{ label: '全部', value: '' }, ...options];
}
);
this.loadDictOptions('customer_type', 'customerTypeOptions', ['客户', '承运商'], options => {
const customerTypeColumn = this.findColumn(this.option.column, 'customerType');
customerTypeColumn.dicData = options;
const customerTypeColumn = this.findColumn(this.option.column, 'customerType');
customerTypeColumn.dicData = [{ label: '全部', value: '' }, ...options];
});
this.loadDictOptions('scope_of_business', 'businessScopeOptions');
this.loadDictOptions('bank_list', 'bankListOptions');
@@ -2040,8 +2131,16 @@ export default {
});
},
deleteContact(index) {
this.archiveForm.contacts.splice(index, 1);
this.handleDetailCurrentChange('contact', this.contactPage.currentPage);
this.$confirm('确定删除该联系人?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.archiveForm.contacts.splice(index, 1);
this.handleDetailCurrentChange('contact', this.contactPage.currentPage);
})
.catch(() => {});
},
handleContactMapPick() {
this.contactMapTarget = 'contact';
@@ -2368,8 +2467,16 @@ export default {
});
},
deleteReceipt(index) {
this.archiveForm.receiptAccounts.splice(index, 1);
this.handleDetailCurrentChange('receipt', this.receiptPage.currentPage);
this.$confirm('确定删除该收款信息?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.archiveForm.receiptAccounts.splice(index, 1);
this.handleDetailCurrentChange('receipt', this.receiptPage.currentPage);
})
.catch(() => {});
},
normalizeInvoice(invoice = {}) {
const registeredDetailAddress =
@@ -2423,8 +2530,27 @@ export default {
});
},
deleteInvoice(index) {
this.archiveForm.invoices.splice(index, 1);
this.handleDetailCurrentChange('invoice', this.invoicePage.currentPage);
this.$confirm('确定删除该发票信息?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.archiveForm.invoices.splice(index, 1);
this.handleDetailCurrentChange('invoice', this.invoicePage.currentPage);
})
.catch(() => {});
},
deleteScoreAttachment(index) {
this.$confirm('确定删除该评分证明材料?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => {
this.scoreAttachmentFiles.splice(index, 1);
})
.catch(() => {});
},
parseAttachments(value) {
if (!value) return [];
@@ -2578,6 +2704,7 @@ export default {
const latestScore = this.getLatestCreditScore(archive.scores || []);
archive.customerLevel = latestScore?.creditLevel || archive.customerLevel || '';
archive.maxCreditLimit = latestScore?.maxCreditLimit || archive.maxCreditLimit || '';
archive.applyCreditLimit = archive.maxCreditLimit;
return archive;
},
syncArchiveCreditFromScores() {
@@ -3172,6 +3299,18 @@ export default {
});
});
},
handleWithdrawApproval(row) {
this.$confirm('是否确认撤回该客商审批?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => withdrawApproval(row.id))
.then(() => {
this.onLoad(this.page);
this.$message({ type: 'success', message: '已撤回至草稿状态!' });
});
},
handleApprove(row) {
this.$confirm('是否确认审核通过?', '提示', {
confirmButtonText: '确定',
@@ -3211,7 +3350,7 @@ export default {
});
},
searchReset() {
this.query = {};
this.query = this.isAdmin ? {} : { deptName: this.getCurrentDeptName() };
this.onLoad(this.page);
},
searchChange(params, done) {
@@ -3237,6 +3376,7 @@ export default {
this.onLoad(this.page, this.query);
},
onLoad(page, params = {}) {
if (!this.deptSearchInitialized) return;
this.loading = true;
getList(page.currentPage, page.pageSize, this.buildQuery(params))
.then(res => {
@@ -3279,6 +3419,13 @@ export default {
buildQuery(params = {}) {
return normalizeSearchRangeParams({ ...params, ...this.query }, createTimeRangeMap);
},
getCurrentDeptName() {
const currentDeptId = this.userInfo.deptId || this.userInfo.dept_id;
const currentDept = this.deptOptions.find(
item => String(item.value) === String(currentDeptId)
);
return currentDept?.rawLabel || this.userInfo.deptName || this.userInfo.dept_name || '';
},
},
};
</script>
@@ -3579,6 +3726,37 @@ export default {
}
}
.contact-form__compact-field {
:deep(.el-input) {
width: 60%;
}
}
.contact-dialog__footer-actions {
display: flex;
justify-content: center;
gap: 12px;
}
.receipt-form {
:deep(.el-input),
:deep(.el-select) {
width: 60%;
}
}
.receipt-dialog__footer-actions {
display: flex;
justify-content: center;
gap: 12px;
}
.invoice-dialog__footer-actions {
display: flex;
justify-content: center;
gap: 12px;
}
.contact-form__map-toolbar {
display: flex;
gap: 10px;