客商档案新增金蝶客商查询回填与同步金蝶重推入口

This commit is contained in:
刘泉佳
2026-09-18 20:01:29 +08:00
parent f067518c0e
commit 58aaf79445
2 changed files with 204 additions and 16 deletions
+20
View File
@@ -113,6 +113,26 @@ export const getScoreTemplate = quantificationId => {
}); });
}; };
export const queryKingdeeCustomer = creditCode => {
return request({
url: '/blade-transport/bfi/customer/query-by-credit-code',
method: 'get',
params: {
creditCode,
},
});
};
export const syncKingdee = id => {
return request({
url: '/blade-transport/customer-archive/sync-kingdee',
method: 'post',
params: {
id,
},
});
};
export const recognizeBusinessLicenseOcr = imageUrl => { export const recognizeBusinessLicenseOcr = imageUrl => {
return request({ return request({
url: '/blade-transport/baidu-ocr/recognize-url', url: '/blade-transport/baidu-ocr/recognize-url',
+184 -16
View File
@@ -109,6 +109,12 @@
{{ row.status === 1 ? '启用' : '停用' }} {{ row.status === 1 ? '启用' : '停用' }}
</el-tag> </el-tag>
</template> </template>
<template #kingdeeStatus="{ row }">
<el-tag v-if="row.kingdeeStatus === 'synced'" type="success">已推送</el-tag>
<el-tag v-else-if="row.kingdeeStatus === 'exist'" type="primary">金蝶已有</el-tag>
<el-tag v-else-if="row.kingdeeStatus === 'failed'" type="danger">推送失败</el-tag>
<el-tag v-else type="info">未推送</el-tag>
</template>
<template #menu="{ row }"> <template #menu="{ row }">
<el-link <el-link
type="primary" type="primary"
@@ -165,6 +171,17 @@
> >
{{ row.status === 1 ? '停用' : '启用' }} {{ row.status === 1 ? '停用' : '启用' }}
</el-link> </el-link>
<el-link
type="primary"
v-if="
hasPermission('customer_archive_sync') &&
row.approvalStatus === 'approved' &&
row.kingdeeStatus === 'failed'
"
@click="handleSyncKingdee(row)"
>
同步金蝶
</el-link>
<el-link <el-link
type="danger" type="danger"
v-if="hasPermission('customer_archive_delete') && row.approvalStatus === 'draft'" v-if="hasPermission('customer_archive_delete') && row.approvalStatus === 'draft'"
@@ -266,6 +283,7 @@
placeholder="请输入" placeholder="请输入"
maxlength="18" maxlength="18"
show-word-limit show-word-limit
:disabled="kingdeeLocked"
@input=" @input="
archiveForm.unifiedCreditCode = String( archiveForm.unifiedCreditCode = String(
archiveForm.unifiedCreditCode || '' archiveForm.unifiedCreditCode || ''
@@ -281,6 +299,7 @@
placeholder="请输入" placeholder="请输入"
maxlength="100" maxlength="100"
show-word-limit show-word-limit
:disabled="kingdeeLocked"
/> />
</el-form-item> </el-form-item>
</el-col> </el-col>
@@ -304,12 +323,23 @@
</el-col> </el-col>
<el-col :span="6"> <el-col :span="6">
<el-form-item label="企业法人" prop="legalPerson"> <el-form-item label="企业法人" prop="legalPerson">
<el-input v-model="archiveForm.legalPerson" maxlength="10" show-word-limit /> <el-input
v-model="archiveForm.legalPerson"
maxlength="10"
show-word-limit
:disabled="kingdeeLocked"
/>
</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" required>
<el-select v-model="archiveForm.businessScope" multiple filterable clearable> <el-select
v-model="archiveForm.businessScope"
multiple
filterable
clearable
:disabled="kingdeeLocked"
>
<el-option <el-option
v-for="item in businessScopeOptions" v-for="item in businessScopeOptions"
:key="item.value" :key="item.value"
@@ -331,11 +361,12 @@
v-model="archiveForm.businessEndDate" v-model="archiveForm.businessEndDate"
type="date" type="date"
value-format="YYYY-MM-DD" value-format="YYYY-MM-DD"
:disabled="archiveForm.businessTermType === '长期'" :disabled="kingdeeLocked || archiveForm.businessTermType === '长期'"
@change="handleBusinessEndDateChange" @change="handleBusinessEndDateChange"
/> />
<el-checkbox <el-checkbox
:model-value="archiveForm.businessTermType === '长期'" :model-value="archiveForm.businessTermType === '长期'"
:disabled="kingdeeLocked"
@change="handleNoFixedTermChange" @change="handleNoFixedTermChange"
> >
无固定期限 无固定期限
@@ -367,6 +398,7 @@
:options="regionOptions" :options="regionOptions"
:props="regionCascaderProps" :props="regionCascaderProps"
:placeholder="archiveForm.registeredRegionName || '请选择省市区'" :placeholder="archiveForm.registeredRegionName || '请选择省市区'"
:disabled="kingdeeLocked"
clearable clearable
filterable filterable
@change="handleRegisteredRegionChange" @change="handleRegisteredRegionChange"
@@ -387,6 +419,7 @@
v-model="archiveForm.registeredDetailAddress" v-model="archiveForm.registeredDetailAddress"
maxlength="255" maxlength="255"
placeholder="请输入详细地址" placeholder="请输入详细地址"
:disabled="kingdeeLocked"
@input="checkOverflow('registeredDetailInput', 'registeredDetailOverflow')" @input="checkOverflow('registeredDetailInput', 'registeredDetailOverflow')"
/> />
</el-tooltip> </el-tooltip>
@@ -446,6 +479,7 @@
<el-input <el-input
v-model="archiveForm.registeredCapital" v-model="archiveForm.registeredCapital"
maxlength="18" maxlength="18"
:disabled="kingdeeLocked"
@input="value => handleDecimalInput('registeredCapital', value)" @input="value => handleDecimalInput('registeredCapital', value)"
/> />
</el-form-item> </el-form-item>
@@ -1492,6 +1526,8 @@ import {
remove, remove,
getScoreTemplate, getScoreTemplate,
recognizeBusinessLicenseOcr, recognizeBusinessLicenseOcr,
queryKingdeeCustomer,
syncKingdee,
} from '@/api/vehicle/customer-archive'; } from '@/api/vehicle/customer-archive';
import { import {
getList as getCreditScoreQuantificationList, getList as getCreditScoreQuantificationList,
@@ -1565,23 +1601,13 @@ export default {
const code = String(value || '') const code = String(value || '')
.trim() .trim()
.toUpperCase(); .toUpperCase();
const charset = '0123456789ABCDEFGHJKLMNPQRTUWXY';
const weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
if (!code) { if (!code) {
callback(); callback();
return; return;
} }
if (code.length !== 18 || ![...code].every(char => charset.includes(char))) { const error = this.unifiedCreditCodeError(code);
callback(new Error('统一社会信用代码必须为18位有效字符')); if (error) {
return; callback(new Error(error));
}
const sum = [...code.slice(0, 17)].reduce(
(total, char, index) => total + charset.indexOf(char) * weights[index],
0
);
const checkCode = charset[(31 - (sum % 31)) % 31];
if (code[17] !== checkCode) {
callback(new Error('统一社会信用代码校验码错误'));
return; return;
} }
callback(); callback();
@@ -1621,6 +1647,9 @@ export default {
originalAccessType: '', originalAccessType: '',
activeTab: 'scores', activeTab: 'scores',
archiveForm: this.emptyArchive(), archiveForm: this.emptyArchive(),
kingdeeBlocked: false,
kingdeeQueriedCode: '',
kingdeeQueryTimer: null,
currentScore: { details: [] }, currentScore: { details: [] },
scoreRecordIndex: -1, scoreRecordIndex: -1,
scoreAttachmentFiles: [], scoreAttachmentFiles: [],
@@ -1967,6 +1996,12 @@ export default {
valueFormat: 'YYYY-MM-DD HH:mm:ss', valueFormat: 'YYYY-MM-DD HH:mm:ss',
minWidth: 170, minWidth: 170,
}, },
{
label: '金蝶同步状态',
prop: 'kingdeeStatus',
slot: true,
minWidth: 110,
},
{ {
label: '状态', label: '状态',
prop: 'status', prop: 'status',
@@ -2004,6 +2039,9 @@ export default {
const authority = this.userInfo.authority || ''; const authority = this.userInfo.authority || '';
return authority.includes('admin'); return authority.includes('admin');
}, },
kingdeeLocked() {
return this.archiveForm.kingdeeStatus === 'exist';
},
permissionList() { permissionList() {
return { return {
addBtn: false, addBtn: false,
@@ -2179,6 +2217,9 @@ export default {
}, },
}, },
watch: { watch: {
'archiveForm.unifiedCreditCode'(val) {
this.handleKingdeeCreditCodeChange(val);
},
'archiveForm.registeredDetailAddress'() { 'archiveForm.registeredDetailAddress'() {
this.$nextTick(() => this.checkOverflow('registeredDetailInput', 'registeredDetailOverflow')); this.$nextTick(() => this.checkOverflow('registeredDetailInput', 'registeredDetailOverflow'));
}, },
@@ -2190,6 +2231,101 @@ export default {
hasPermission(code) { hasPermission(code) {
return this.isAdmin || this.validData(this.permission[code], false); return this.isAdmin || this.validData(this.permission[code], false);
}, },
unifiedCreditCodeError(value) {
const code = String(value || '')
.trim()
.toUpperCase();
const charset = '0123456789ABCDEFGHJKLMNPQRTUWXY';
const weights = [1, 3, 9, 27, 19, 26, 16, 17, 20, 29, 25, 13, 8, 24, 10, 30, 28];
if (code.length !== 18 || ![...code].every(char => charset.includes(char))) {
return '统一社会信用代码必须为18位有效字符';
}
const sum = [...code.slice(0, 17)].reduce(
(total, char, index) => total + charset.indexOf(char) * weights[index],
0
);
const checkCode = charset[(31 - (sum % 31)) % 31];
if (code[17] !== checkCode) {
return '统一社会信用代码校验码错误';
}
return '';
},
resetKingdeeQueryState() {
this.kingdeeBlocked = false;
this.kingdeeQueriedCode = '';
clearTimeout(this.kingdeeQueryTimer);
this.kingdeeQueryTimer = null;
},
// 新增态下统一社会信用代码录入完成后自动查询金蝶(A902-1),防抖 500ms
handleKingdeeCreditCodeChange(val) {
this.kingdeeBlocked = false;
if (this.readonly || this.archiveForm.id) return;
const code = String(val || '')
.trim()
.toUpperCase();
if (code.length !== 18 || this.unifiedCreditCodeError(code)) return;
if (this.kingdeeQueriedCode === code) return;
this.kingdeeQueriedCode = code;
clearTimeout(this.kingdeeQueryTimer);
this.kingdeeQueryTimer = setTimeout(() => this.fetchKingdeeCustomer(code), 500);
},
async fetchKingdeeCustomer(code) {
let customer = null;
try {
const res = await queryKingdeeCustomer(code);
customer = res?.data?.data || null;
} catch (error) {
this.$message.warning('金蝶查询失败,可继续填写,审批通过后系统将自动复查');
return;
}
// 防止响应返回时用户已修改代码
if (String(this.archiveForm.unifiedCreditCode || '').trim().toUpperCase() !== code) return;
if (!customer) return;
if (customer.status === 'C') {
this.applyKingdeeCustomer(customer);
this.$alert('金蝶已创建该客户,将获取金蝶的工商信息,相关字段已自动回填并锁定。', '提示', {
confirmButtonText: '确定',
});
} else {
this.kingdeeBlocked = true;
this.$alert('金蝶审核中,请稍后重新添加。', '提示', { confirmButtonText: '确定' });
}
},
applyKingdeeCustomer(customer) {
const form = this.archiveForm;
form.kingdeeStatus = 'exist';
// 工商信息以金蝶为准,直接覆盖(后续字段锁定)
if (customer.name) form.fullName = customer.name;
if (customer.artificialperson) form.legalPerson = customer.artificialperson;
if (customer.bizpartnerAddress) form.registeredDetailAddress = customer.bizpartnerAddress;
if (customer.regcapital) {
const capital = String(customer.regcapital).replace(/,/g, '').match(/\d+(?:\.\d+)?/);
if (capital) form.registeredCapital = capital[0];
}
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;
}
if (!form.shortName && customer.simplename) form.shortName = customer.simplename;
this.$nextTick(() => {
[
'unifiedCreditCode',
'fullName',
'legalPerson',
'registeredCapital',
'businessEndDate',
'businessScope',
'registeredDetailAddress',
].forEach(prop => this.$refs.archiveForm?.validateField(prop));
});
},
// 检测输入框文本是否溢出,仅溢出时才允许 tooltip 显示完整地址 // 检测输入框文本是否溢出,仅溢出时才允许 tooltip 显示完整地址
checkOverflow(refName, flag) { checkOverflow(refName, flag) {
const inst = this.$refs[refName]; const inst = this.$refs[refName];
@@ -2219,6 +2355,9 @@ export default {
invoices: [], invoices: [],
scores: [], scores: [],
changeRecords: [], changeRecords: [],
kingdeeStatus: 'none',
kingdeeFailReason: '',
kingdeeSyncTime: null,
}; };
}, },
getDetailList(type) { getDetailList(type) {
@@ -3919,6 +4058,7 @@ export default {
} }
this.archiveForm = this.emptyArchive(); this.archiveForm = this.emptyArchive();
this.originalAccessType = ''; this.originalAccessType = '';
this.resetKingdeeQueryState();
this.qualificationFiles = []; this.qualificationFiles = [];
this.qualificationUploadFiles = []; this.qualificationUploadFiles = [];
this.ocrQualificationUploadFiles = []; this.ocrQualificationUploadFiles = [];
@@ -3927,6 +4067,7 @@ export default {
}, },
resetArchive() { resetArchive() {
this.readonly = false; this.readonly = false;
this.resetKingdeeQueryState();
this.changeRecordDetailVisible = false; this.changeRecordDetailVisible = false;
this.changeRecordDetail = null; this.changeRecordDetail = null;
this.changeRecordDetailRows = []; this.changeRecordDetailRows = [];
@@ -4047,6 +4188,10 @@ export default {
return archive; return archive;
}, },
saveArchive() { saveArchive() {
if (this.kingdeeBlocked) {
this.$message.warning('金蝶审核中,请稍后重新添加');
return;
}
this.$refs.archiveForm.validate(valid => { this.$refs.archiveForm.validate(valid => {
if (!valid) { if (!valid) {
this.$message.warning('请先完整填写必填项'); this.$message.warning('请先完整填写必填项');
@@ -4060,6 +4205,10 @@ export default {
}); });
}, },
saveAndSubmitArchive() { saveAndSubmitArchive() {
if (this.kingdeeBlocked) {
this.$message.warning('金蝶审核中,请稍后重新添加');
return;
}
this.$refs.archiveForm.validate(valid => { this.$refs.archiveForm.validate(valid => {
if (!valid) { if (!valid) {
this.$message.warning('请先完整填写必填项'); this.$message.warning('请先完整填写必填项');
@@ -4707,6 +4856,25 @@ export default {
this.$message({ type: 'success', message: '审核通过!' }); this.$message({ type: 'success', message: '审核通过!' });
}); });
}, },
handleSyncKingdee(row) {
this.$confirm('是否确认推送金蝶?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning',
})
.then(() => syncKingdee(row.id))
.then(res => {
const archive = res?.data?.data || {};
if (archive.kingdeeStatus === 'synced') {
this.$message.success('推送成功,金蝶客户编码与客商编号一致');
} else if (archive.kingdeeStatus === 'exist') {
this.$message.info('金蝶已有该客商档案,无需推送');
} else {
this.$message.warning(`推送失败:${archive.kingdeeFailReason || '未知原因'}`);
}
this.onLoad(this.page);
});
},
handleReject(row) { handleReject(row) {
this.$confirm('是否确认审核不通过?', '提示', { this.$confirm('是否确认审核不通过?', '提示', {
confirmButtonText: '确定', confirmButtonText: '确定',