Merge pull request '金蝶单据状态着色并悬浮展示失败原因+认领流水认领记录的改造' (#9) from feature/20261027-hcs-bif-all-web into master
Reviewed-on: #9
This commit was merged in pull request #9.
This commit is contained in:
@@ -49,24 +49,27 @@
|
||||
</template>
|
||||
<template #customerRisk="{ row }">
|
||||
<el-tooltip
|
||||
v-if="customerRiskMap[row.customerCode] && customerRiskMap[row.customerCode].risky"
|
||||
v-if="customerRowRiskName(row) && customerRowRiskName(row) !== '无风险'"
|
||||
placement="top"
|
||||
effect="dark"
|
||||
popper-class="customer-risk-popper"
|
||||
>
|
||||
<template #content>
|
||||
<div>{{ customerRiskMap[row.customerCode].riskTip || '该客商为高风险/黑名单客商' }}</div>
|
||||
<div>{{ row.hcsRiskDetail || customerRowRiskName(row) }}</div>
|
||||
</template>
|
||||
<el-tag type="danger" class="status-text">
|
||||
{{ customerRiskLabel(customerRiskMap[row.customerCode]) }}
|
||||
<el-tag
|
||||
:type="customerRowRisky(row) ? 'danger' : row.hcsRiskLevel === '1' ? 'warning' : 'success'"
|
||||
class="status-text"
|
||||
>
|
||||
{{ customerRowRiskName(row) }}
|
||||
</el-tag>
|
||||
</el-tooltip>
|
||||
<el-tag
|
||||
v-else-if="customerRiskMap[row.customerCode]"
|
||||
:type="customerRiskMap[row.customerCode].fdRiskLevel === '1' ? 'warning' : 'success'"
|
||||
v-else-if="customerRowRiskName(row)"
|
||||
type="success"
|
||||
class="status-text"
|
||||
>
|
||||
{{ customerRiskLabel(customerRiskMap[row.customerCode]) }}
|
||||
{{ customerRowRiskName(row) }}
|
||||
</el-tag>
|
||||
<span v-else>-</span>
|
||||
</template>
|
||||
@@ -135,7 +138,13 @@
|
||||
<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-tooltip
|
||||
v-else-if="row.kingdeeStatus === 'failed'"
|
||||
:content="row.kingdeeFailReason || '推送金蝶失败,请重试'"
|
||||
placement="top"
|
||||
>
|
||||
<el-tag type="danger">推送失败</el-tag>
|
||||
</el-tooltip>
|
||||
<el-tag v-else type="info">未推送</el-tag>
|
||||
</template>
|
||||
<template #menu="{ row }">
|
||||
@@ -285,6 +294,17 @@
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="供应商编码" prop="supplierCode">
|
||||
<el-input
|
||||
v-model="archiveForm.supplierCode"
|
||||
maxlength="64"
|
||||
show-word-limit
|
||||
disabled
|
||||
placeholder="金蝶供应商编码,系统自动获取"
|
||||
/>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
<el-col :span="6">
|
||||
<el-form-item label="客商类型" prop="customerKind">
|
||||
<el-select
|
||||
@@ -366,7 +386,7 @@
|
||||
<template #content>
|
||||
<div>{{ archiveNameRiskTip || '该客商为高风险/黑名单客商' }}</div>
|
||||
</template>
|
||||
<div class="archive-name-risk">高风险/黑名单客商</div>
|
||||
<div class="archive-name-risk">{{ archiveNameRiskLabel }}</div>
|
||||
</el-tooltip>
|
||||
</el-form-item>
|
||||
</el-col>
|
||||
@@ -1080,8 +1100,18 @@
|
||||
<el-form-item label="开户人姓名" prop="accountHolderName">
|
||||
<el-input v-model="receiptForm.accountHolderName" maxlength="50" />
|
||||
</el-form-item>
|
||||
<el-form-item label="开户行" prop="bankName">
|
||||
<el-input v-model="receiptForm.bankName" maxlength="100" />
|
||||
<el-form-item prop="bankName">
|
||||
<template #label>
|
||||
<span class="receipt-bank-label">
|
||||
开户行
|
||||
<el-tooltip placement="top" effect="dark" content="请填写银行全称,系统将自动匹配金蝶档案带出联行号">
|
||||
<el-icon class="receipt-bank-help">
|
||||
<el-icon-question-filled />
|
||||
</el-icon>
|
||||
</el-tooltip>
|
||||
</span>
|
||||
</template>
|
||||
<el-input v-model="receiptForm.bankName" maxlength="100" @blur="fetchReceiptCnapsCode" />
|
||||
</el-form-item>
|
||||
<el-form-item label="联行号" prop="cnapsCode">
|
||||
<el-input v-model="receiptForm.cnapsCode" maxlength="32" />
|
||||
@@ -1588,10 +1618,14 @@ import {
|
||||
remove,
|
||||
getScoreTemplate,
|
||||
recognizeBusinessLicenseOcr,
|
||||
queryKingdeeBank,
|
||||
queryKingdeeBankByNumber,
|
||||
queryKingdeeCustomer,
|
||||
querySupplierCode,
|
||||
syncKingdee,
|
||||
} from '@/api/vehicle/customer-archive';
|
||||
import { getRiskBatch, getRiskByName } from '@/api/business/hcs';
|
||||
import { getRisk, getRiskByName } from '@/api/business/hcs';
|
||||
import { isKingdeeBlack, isRiskyTag, resolveRiskTagName } from '@/utils/risk-display';
|
||||
import {
|
||||
getList as getCreditScoreQuantificationList,
|
||||
getDetail as getCreditScoreQuantificationDetail,
|
||||
@@ -1693,9 +1727,9 @@ export default {
|
||||
deptSearchInitialized: false,
|
||||
loading: true,
|
||||
data: [],
|
||||
customerRiskMap: {},
|
||||
archiveNameRisky: false,
|
||||
archiveNameRiskTip: '',
|
||||
archiveNameRiskLabel: '',
|
||||
page: {
|
||||
pageSize: 10,
|
||||
pageSizes: [10, 20, 50, 100],
|
||||
@@ -1915,6 +1949,11 @@ export default {
|
||||
searchPlaceholder: '请输入',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '供应商编码',
|
||||
prop: 'supplierCode',
|
||||
minWidth: 140,
|
||||
},
|
||||
{
|
||||
label: '客商简称',
|
||||
prop: 'shortName',
|
||||
@@ -1957,7 +1996,13 @@ export default {
|
||||
label: '客商风险',
|
||||
prop: 'customerRisk',
|
||||
slot: true,
|
||||
minWidth: 100,
|
||||
search: true,
|
||||
searchType: 'select',
|
||||
searchOrder: 4,
|
||||
searchPlaceholder: '请选择',
|
||||
minWidth: 150,
|
||||
// 选项走业务字典 customer_risk(initBusinessDictionaries 加载:dictKey=筛选值,dictValue=名称),未配置时下拉为空
|
||||
dicData: [],
|
||||
},
|
||||
{
|
||||
label: '客户性质',
|
||||
@@ -2463,6 +2508,7 @@ export default {
|
||||
const form = this.archiveForm;
|
||||
form.kingdeeStatus = 'none';
|
||||
form.customerCode = '';
|
||||
form.supplierCode = '';
|
||||
form.fullName = '';
|
||||
form.legalPerson = '';
|
||||
form.registeredCapital = '';
|
||||
@@ -2478,6 +2524,7 @@ export default {
|
||||
handleKingdeeCreditCodeChange(val) {
|
||||
this.kingdeeBlocked = false;
|
||||
if (this.readonly || this.archiveForm.id) return;
|
||||
this.clearArchiveNameRisk();
|
||||
if (this.archiveForm.kingdeeStatus === 'exist') {
|
||||
this.resetKingdeeBackfill();
|
||||
}
|
||||
@@ -2486,7 +2533,21 @@ export default {
|
||||
.toUpperCase();
|
||||
if (code.length !== 18 || this.unifiedCreditCodeError(code)) return;
|
||||
clearTimeout(this.kingdeeQueryTimer);
|
||||
this.kingdeeQueryTimer = setTimeout(() => this.fetchKingdeeCustomer(code), 500);
|
||||
this.kingdeeQueryTimer = setTimeout(() => {
|
||||
this.fetchKingdeeCustomer(code);
|
||||
this.fetchSupplierCode(code);
|
||||
}, 500);
|
||||
},
|
||||
// 新增态下信用代码录入后即时查询金蝶供应商编码(A901-1)回显,查询失败静默留空,保存/同步时后端兜底落库
|
||||
async fetchSupplierCode(code) {
|
||||
try {
|
||||
const res = await querySupplierCode(code);
|
||||
// 防止响应返回时用户已修改代码
|
||||
if (String(this.archiveForm.unifiedCreditCode || '').trim().toUpperCase() !== code) return;
|
||||
this.archiveForm.supplierCode = res?.data?.data || '';
|
||||
} catch (error) {
|
||||
// 忽略查询异常,编码留空
|
||||
}
|
||||
},
|
||||
async fetchKingdeeCustomer(code) {
|
||||
let customer = null;
|
||||
@@ -2694,6 +2755,7 @@ export default {
|
||||
currentNode: '当前节点',
|
||||
currentProcessor: '当前处理人',
|
||||
customerCode: '客商编号',
|
||||
supplierCode: '供应商编码',
|
||||
shortName: '客商简称',
|
||||
fullName: '客商名称',
|
||||
customerType: '客商分类',
|
||||
@@ -3151,6 +3213,15 @@ export default {
|
||||
});
|
||||
},
|
||||
initBusinessDictionaries() {
|
||||
// 客商风险筛选项走业务字典 customer_risk(dictKey=筛选值 blacklist/high/middle/low,dictValue=名称),字典缺失保留固定兜底项
|
||||
getDictionary({ code: 'customer_risk' }).then(res => {
|
||||
const options = (res.data.data || [])
|
||||
.filter(item => item.dictKey !== '-1')
|
||||
.map(item => ({ label: item.dictValue, value: item.dictKey }));
|
||||
if (options.length) {
|
||||
this.findColumn(this.option.column, 'customerRisk').dicData = options;
|
||||
}
|
||||
});
|
||||
this.loadDictOptions('nature_of_client', 'customerNatureOptions', [], options => {
|
||||
const customerNatureColumn = this.findColumn(this.option.column, 'customerNature');
|
||||
customerNatureColumn.dicData = [{ label: '全部', value: '' }, ...options];
|
||||
@@ -3598,18 +3669,50 @@ export default {
|
||||
this.receiptForm = this.emptyReceiptAccount();
|
||||
this.$refs.receiptForm?.clearValidate();
|
||||
},
|
||||
saveReceipt() {
|
||||
this.$refs.receiptForm.validate(valid => {
|
||||
if (!valid) return;
|
||||
const receipt = this.normalizeReceipt(this.receiptForm);
|
||||
if (this.receiptIndex > -1) {
|
||||
this.archiveForm.receiptAccounts.splice(this.receiptIndex, 1, receipt);
|
||||
// 开户行失焦后按行名精确匹配金蝶行名行号档案(A905-3),命中自动带出联行号,未命中提示检查
|
||||
async fetchReceiptCnapsCode() {
|
||||
const bankName = String(this.receiptForm.bankName || '').trim();
|
||||
if (!bankName) return;
|
||||
try {
|
||||
const res = await queryKingdeeBank(bankName);
|
||||
// 防止响应返回时用户已修改开户行
|
||||
if (String(this.receiptForm.bankName || '').trim() !== bankName) return;
|
||||
const bank = res?.data?.data || null;
|
||||
if (bank && bank.unionNumber) {
|
||||
this.receiptForm.cnapsCode = bank.unionNumber;
|
||||
this.$refs.receiptForm?.clearValidate('cnapsCode');
|
||||
} else {
|
||||
this.archiveForm.receiptAccounts.push(receipt);
|
||||
this.handleDetailCurrentChange('receipt', this.getDetailPageCount('receipt'));
|
||||
this.$message.warning('未查询到金蝶开户行信息,请检查开户行名称');
|
||||
}
|
||||
this.receiptBox = false;
|
||||
});
|
||||
} catch (error) {
|
||||
// 忽略查询异常,联行号留空由用户手填
|
||||
}
|
||||
},
|
||||
async saveReceipt() {
|
||||
const valid = await this.$refs.receiptForm.validate().catch(() => false);
|
||||
if (!valid) return;
|
||||
// 保存前按联行号精确校验金蝶行名行号档案(A905-3),查不到不允许保存
|
||||
const cnapsCode = String(this.receiptForm.cnapsCode || '').trim();
|
||||
let bank = null;
|
||||
try {
|
||||
const res = await queryKingdeeBankByNumber(cnapsCode);
|
||||
bank = res?.data?.data || null;
|
||||
} catch (error) {
|
||||
this.$message.warning('金蝶联行号校验失败,请稍后重试');
|
||||
return;
|
||||
}
|
||||
if (!bank || !bank.unionNumber) {
|
||||
this.$message.warning('未查询到金蝶联行号信息,不能保存,请检查联行号');
|
||||
return;
|
||||
}
|
||||
const receipt = this.normalizeReceipt(this.receiptForm);
|
||||
if (this.receiptIndex > -1) {
|
||||
this.archiveForm.receiptAccounts.splice(this.receiptIndex, 1, receipt);
|
||||
} else {
|
||||
this.archiveForm.receiptAccounts.push(receipt);
|
||||
this.handleDetailCurrentChange('receipt', this.getDetailPageCount('receipt'));
|
||||
}
|
||||
this.receiptBox = false;
|
||||
},
|
||||
deleteReceipt(index) {
|
||||
this.$confirm('确定删除该收款信息?', '提示', {
|
||||
@@ -5534,7 +5637,9 @@ export default {
|
||||
this.onLoad(this.page);
|
||||
},
|
||||
searchChange(params, done) {
|
||||
this.query = this.buildQuery(params);
|
||||
// Avue 只回传非空筛选项,被清空的字段不会出现在 params 里,
|
||||
// 因此查询条件必须整体重建,不能与上一次的 this.query 合并,否则清空后仍会带上次的值
|
||||
this.query = this.buildQuery(params, true);
|
||||
this.page.currentPage = 1;
|
||||
this.onLoad(this.page, this.query);
|
||||
done();
|
||||
@@ -5563,52 +5668,56 @@ export default {
|
||||
const pageData = res.data.data;
|
||||
this.page.total = pageData.total;
|
||||
this.data = pageData.records;
|
||||
this.loadCustomerRisk(this.data);
|
||||
this.selectionClear();
|
||||
})
|
||||
.finally(() => {
|
||||
this.loading = false;
|
||||
});
|
||||
},
|
||||
// 客商风险标签文案:后端 riskLevelName 转义(黑名单/高风险/中风险/低风险),缺失时兜底
|
||||
customerRiskLabel(risk) {
|
||||
if (!risk) return '';
|
||||
return risk.riskLevelName || (risk.risky ? '风险客商' : '正常');
|
||||
// 黑名单判定:仅以金蝶黑名单(A801-5)命中为准(失信类别/列入事由任一非空);C101-1 的 hcsBlackStatus 不作为黑名单依据
|
||||
customerRowIsBlack(row) {
|
||||
return isKingdeeBlack(row.kingdeeBlackCategory, row.kingdeeBlackReason);
|
||||
},
|
||||
// 客商风险名称(每日定时刷新落库字段):等级与黑名单组合展示(如"低风险、黑名单");内部组织默认无风险;未查询显示"-"
|
||||
customerRowRiskName(row) {
|
||||
return resolveRiskTagName(row.hcsRiskLevel, this.customerRowIsBlack(row), row.customerKind);
|
||||
},
|
||||
// 高风险/黑名单判定(与列表筛选口径一致,命中显示红色标签)
|
||||
customerRowRisky(row) {
|
||||
return isRiskyTag(row.hcsRiskLevel, this.customerRowIsBlack(row));
|
||||
},
|
||||
// 客商名称风险校验(C101-1,仅展示不作为安全边界):名称失焦/回显时查询,
|
||||
// risky 在名称框下展示红色提示,悬浮见风险项明细;查询失败静默不阻断填写,提交链路由后端强校验兜底
|
||||
checkArchiveNameRisk() {
|
||||
// 清空客商名称下风险提示(信用代码变化后原按旧编号+信用代码查询的结果失效)
|
||||
clearArchiveNameRisk() {
|
||||
this.archiveNameRisky = false;
|
||||
this.archiveNameRiskTip = '';
|
||||
this.archiveNameRiskLabel = '';
|
||||
},
|
||||
checkArchiveNameRisk() {
|
||||
this.clearArchiveNameRisk();
|
||||
const customerName = String(this.archiveForm.fullName || '').trim();
|
||||
if (!customerName) return;
|
||||
getRiskByName(customerName)
|
||||
// 新增客商档案本地反查不到编号:金蝶带出后表单已有客商编号,优先按编号查 C101-1,
|
||||
// 并传信用代码供金蝶黑名单(A801-5)兜底;无编号时按名称反查档案
|
||||
const customerCode = String(this.archiveForm.customerCode || '').trim();
|
||||
const request = customerCode
|
||||
? getRisk(customerCode, String(this.archiveForm.unifiedCreditCode || '').trim(), customerName)
|
||||
: getRiskByName(customerName);
|
||||
request
|
||||
.then(res => {
|
||||
const risk = (res.data && res.data.data) || {};
|
||||
this.archiveNameRisky = risk.risky === true;
|
||||
this.archiveNameRiskTip = risk.riskTip || '';
|
||||
// 红字与列表标签同口径(risk-display):等级按合同系统返回值翻译,黑名单按金蝶命中标记独立展示,组合不分家
|
||||
this.archiveNameRiskLabel = this.archiveNameRisky
|
||||
? (resolveRiskTagName(risk.fdRiskLevel, risk.kingdeeBlackHit === true) || '高风险/黑名单') + '客商'
|
||||
: '';
|
||||
})
|
||||
.catch(() => {
|
||||
// 忽略风险查询异常,表单正常填写
|
||||
});
|
||||
},
|
||||
// 客商列表风险批量查询(C101-1,仅展示不作为安全边界):失败静默,行内显示"-",提交链路由后端强校验兜底
|
||||
loadCustomerRisk(rows) {
|
||||
this.customerRiskMap = {};
|
||||
const customerCodes = [...new Set(rows.map(row => row.customerCode).filter(Boolean))];
|
||||
if (!customerCodes.length) return;
|
||||
getRiskBatch(customerCodes)
|
||||
.then(res => {
|
||||
const riskMap = {};
|
||||
((res.data && res.data.data) || []).forEach(risk => {
|
||||
if (risk && risk.customerCode) riskMap[risk.customerCode] = risk;
|
||||
});
|
||||
this.customerRiskMap = riskMap;
|
||||
})
|
||||
.catch(() => {
|
||||
// 忽略风险查询异常,列表正常展示
|
||||
});
|
||||
},
|
||||
handleExport() {
|
||||
this.$confirm('是否导出客商档案数据?', '提示', {
|
||||
confirmButtonText: '确定',
|
||||
@@ -5636,9 +5745,10 @@ export default {
|
||||
[this.website.tokenHeader]: getToken(),
|
||||
};
|
||||
},
|
||||
buildQuery(params = {}) {
|
||||
// 新条件覆盖旧条件;本次显式清空的字段必须从查询里去掉,避免第二次搜索仍带着上一次的客商名称。
|
||||
const merged = { ...this.query, ...params };
|
||||
// replace=true 表示以本次搜索条件为准整体重建(清空字段不会回传,需丢弃旧条件);
|
||||
// 翻页、刷新等场景传 false,沿用上一次的查询条件
|
||||
buildQuery(params = {}, replace = false) {
|
||||
const merged = replace ? { ...params } : { ...this.query, ...params };
|
||||
Object.keys(params).forEach(key => {
|
||||
const value = params[key];
|
||||
if (
|
||||
@@ -6096,6 +6206,19 @@ export default {
|
||||
:deep(.el-select) {
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.receipt-bank-label {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.receipt-bank-help {
|
||||
color: #a8abb2;
|
||||
cursor: help;
|
||||
font-size: 14px;
|
||||
flex: none;
|
||||
}
|
||||
}
|
||||
|
||||
.receipt-dialog__footer-actions {
|
||||
|
||||
Reference in New Issue
Block a user