This commit is contained in:
2026-08-11 09:31:42 +08:00
parent 9391c4db09
commit 0a5b3b2cab
21 changed files with 409 additions and 108 deletions
+208 -60
View File
@@ -581,20 +581,11 @@
<template #extra>
<div v-if="!readonly" class="section-actions">
<el-button icon="el-icon-download" @click="downloadAttachments">批量下载</el-button>
<el-button type="primary" icon="el-icon-plus" @click="addAttachment"
>普通上传</el-button
>
<el-button type="primary" icon="el-icon-upload" @click="addAttachment">
OCR上传识别
</el-button>
</div>
</template>
<el-alert
type="info"
:closable="false"
title="支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip的文件格式,单个文件大小限制500M"
class="archive-rule-alert"
/>
<el-alert
v-if="missingQualificationText"
type="error"
@@ -602,29 +593,28 @@
:title="missingQualificationText"
class="archive-rule-alert"
/>
<el-table :data="qualificationFiles" border>
<el-table
:data="qualificationFiles"
border
@selection-change="handleQualificationSelectionChange"
>
<el-table-column type="selection" width="55" align="center" />
<el-table-column label="序号" type="index" width="90" align="center" />
<el-table-column label="附件类型" min-width="160">
<template #default="{ row }">
<el-select v-model="row.type" :disabled="readonly" filterable>
<el-option label="法人身份证" value="法人身份证" />
<el-option label="道路运输许可证" value="道路运输许可证" />
<el-option label="其他附件" value="其他附件" />
<el-option
v-for="item in qualificationTypeOptions"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</template>
</el-table-column>
<el-table-column label="文件名称" min-width="180">
<template #default="{ row }">
<vehicle-attachment-upload
v-model="row.files"
:readonly="readonly"
:multiple="false"
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)"
/>
<span>{{ row.originalName || row.name || '-' }}</span>
</template>
</el-table-column>
<el-table-column label="附件描述" min-width="220">
@@ -655,15 +645,59 @@
</template>
</el-table-column>
</el-table>
<div v-if="!readonly" class="qualification-upload-bar">
<vehicle-attachment-upload
v-model="qualificationUploadFiles"
:multiple="true"
:limit="20"
accept=".pdf,.bmp,.jpeg,.png,.jpg,.doc,.docx,.ppt,.pptx,.xlsx,.xls,.eml,.msg,.zip"
:max-size="500"
button-text="上传附件"
:show-tip="false"
:show-file-list="false"
:show-uploading="true"
@success="handleQualificationUploadSuccess"
/>
<span class="qualification-upload-bar__tip">
支持pdf、bmp、jpeg、png、jpg、doc、docx、ppt、pptx、xlsx、xls、eml、msg、zip,单个文件不超过500M
</span>
</div>
</section-card>
<section-card title="变更记录">
<el-table :data="archiveForm.changeRecords" border>
<el-table-column label="序号" type="index" width="90" align="center" />
<el-table :data="changeRecordPage.records" border>
<el-table-column
label="序号"
type="index"
width="90"
align="center"
:index="changeRecordIndex"
/>
<el-table-column label="变更日期" prop="changeTime" min-width="170" sortable />
<el-table-column label="变更内容" prop="changeContent" min-width="260" />
<el-table-column label="变更字段" prop="changedFields" min-width="180" />
<el-table-column
label="原数据"
prop="beforeData"
min-width="240"
show-overflow-tooltip
:formatter="formatChangeData"
/>
<el-table-column
label="修改后数据"
prop="afterData"
min-width="240"
show-overflow-tooltip
:formatter="formatChangeData"
/>
<el-table-column label="变更内容" prop="changeContent" min-width="180" />
<el-table-column label="变更账号" prop="changeUserName" min-width="160" />
</el-table>
<empty-pagination
:page="changeRecordPage"
always-show
@size-change="handleChangeRecordSizeChange"
@current-change="handleChangeRecordCurrentChange"
/>
</section-card>
<template #footer>
@@ -1067,7 +1101,7 @@
<el-table-column label="得分说明" prop="scoreDescription" min-width="160" />
<el-table-column label="自评得分" width="130" align="center">
<template #default="{ row: detail }">
<span>{{ formatScoreValue(detail.selfScore) }}分</span>
<span>{{ formatScoreValue(getSignedScore(detail, 'selfScore')) }}分</span>
</template>
</el-table-column>
<el-table-column label="复评得分" width="150" align="center">
@@ -1075,9 +1109,13 @@
<el-input
v-model="detail.reviewScore"
maxlength="10"
inputmode="numeric"
:disabled="readonly || !hasPermission('customer_type_re_cert')"
@input="value => handleScoreDetailScoreInput(detail, 'reviewScore', value)"
>
<template v-if="isMinusScoreDetail(detail) && Number(detail.reviewScore) > 0" #prefix>
-
</template>
<template #suffix>分</template>
</el-input>
</template>
@@ -1089,8 +1127,8 @@
<el-table-column min-width="560">
<template #default="{ row }">
<span class="score-category-table__name">{{ row.categoryName }}</span>
<span>自评:{{ row.selfScore }}分</span>
<span>复评:{{ row.reviewScore }}分</span>
<span>自评:{{ getSignedScore(row, 'selfScore') }}分</span>
<span>复评:{{ getSignedScore(row, 'reviewScore') }}分</span>
</template>
</el-table-column>
<el-table-column width="60" align="center">
@@ -1113,12 +1151,17 @@
button-text="上传附件"
button-icon="el-icon-upload"
:show-tip="false"
:show-uploading="true"
@success="handleScoreAttachmentUploadSuccess"
/>
</template>
<el-table :data="scoreAttachmentFiles" border class="score-material-table">
<el-table-column label="序号" type="index" width="90" align="center" />
<el-table-column label="文件名" prop="name" min-width="220" />
<el-table-column label="文件名" min-width="220">
<template #default="{ row }">
{{ row.originalName || row.name || '-' }}
</template>
</el-table-column>
<el-table-column label="附件描述" prop="description" min-width="220" />
<el-table-column label="文件大小" min-width="120" align="center">
<template #default="{ row }">
@@ -1137,7 +1180,7 @@
</el-table-column>
<el-table-column label="操作" width="120" align="center" v-if="!readonly">
<template #default="{ $index }">
<el-link type="primary" @click="deleteScoreAttachment($index)">
<el-link type="danger" @click="deleteScoreAttachment($index)">
删除
</el-link>
</template>
@@ -1164,6 +1207,7 @@
import {
getList,
getDetail,
getChangeRecordList,
submit,
submitApproval,
withdrawApproval,
@@ -1294,6 +1338,13 @@ export default {
pageSize: 10,
pageSizes: [10, 20, 50, 100],
},
changeRecordPage: {
currentPage: 1,
pageSize: 5,
pageSizes: [5],
total: 0,
records: [],
},
contactIndex: -1,
contactForm: this.emptyContact(),
contactMapBox: false,
@@ -1310,6 +1361,8 @@ export default {
invoiceIndex: -1,
invoiceForm: this.emptyInvoice(),
qualificationFiles: [],
qualificationUploadFiles: [],
selectedQualificationFiles: [],
deptTree: [],
deptOptions: [],
regionOptions: [],
@@ -1317,6 +1370,7 @@ export default {
customerTypeOptions: [],
businessScopeOptions: [],
bankListOptions: [],
qualificationTypeOptions: [],
creditLevelOptions: ['A', 'B', 'C', 'D', 'E', 'F'].map(item => ({
label: `${item}级`,
value: `${item}级`,
@@ -1503,7 +1557,7 @@ export default {
dicData: [{ label: '全部', value: '' }],
},
{
label: '准入标准',
label: '准入类型',
prop: 'accessType',
slot: true,
type: 'select',
@@ -1643,14 +1697,14 @@ export default {
},
scoreTableData() {
const start = (this.scorePage.currentPage - 1) * this.scorePage.pageSize;
return this.scoreList
return this.sortScoresByLatest(this.scoreList)
.slice(start, start + this.scorePage.pageSize)
.map((item, index) => ({
...item,
__raw: item,
__rawIndex: start + index,
__index: start + index + 1,
maxCreditLimit: item.maxCreditLimit || '',
.map(({ score, index }, pageIndex) => ({
...score,
__raw: score,
__rawIndex: index,
__index: start + pageIndex + 1,
maxCreditLimit: score.maxCreditLimit || '',
}));
},
contactPaginationPage() {
@@ -1770,6 +1824,43 @@ export default {
this.handleDetailCurrentChange('receipt', 1);
this.handleDetailCurrentChange('invoice', 1);
},
loadChangeRecords() {
if (!this.archiveForm.id) return;
const page = this.changeRecordPage;
getChangeRecordList(this.archiveForm.id, page.currentPage, page.pageSize).then(res => {
const data = res.data.data || {};
page.records = data.records || [];
page.total = Number(data.total || 0);
page.currentPage = Number(data.current || page.currentPage);
});
},
handleChangeRecordCurrentChange(currentPage) {
this.changeRecordPage.currentPage = Number(currentPage) || 1;
this.loadChangeRecords();
},
handleChangeRecordSizeChange(pageSize) {
this.changeRecordPage.pageSize = Number(pageSize) || 5;
this.changeRecordPage.currentPage = 1;
this.loadChangeRecords();
},
resetChangeRecordPage() {
this.changeRecordPage.currentPage = 1;
this.changeRecordPage.total = 0;
this.changeRecordPage.records = [];
},
changeRecordIndex(index) {
return (this.changeRecordPage.currentPage - 1) * this.changeRecordPage.pageSize + index + 1;
},
formatChangeData(row, column, value) {
if (!value) return '-';
try {
return Object.entries(JSON.parse(value))
.map(([field, fieldValue]) => `${field}${fieldValue ?? '-'}`)
.join('');
} catch (error) {
return value;
}
},
emptyContact() {
return {
contactName: '',
@@ -1958,6 +2049,7 @@ export default {
});
this.loadDictOptions('scope_of_business', 'businessScopeOptions');
this.loadDictOptions('bank_list', 'bankListOptions');
this.loadDictOptions('customer_attachment_types', 'qualificationTypeOptions');
},
initScoreQuantificationOptions() {
this.scoreQuantificationLoading = true;
@@ -2611,7 +2703,8 @@ export default {
.filter(item => item.url)
.map(item => ({
type: String(item.type || '').trim(),
name: String(item.name || '').trim(),
originalName: String(item.originalName || item.name || '').trim(),
name: String(item.originalName || item.name || '').trim(),
description: String(item.description || '').trim(),
size: String(item.size || '').trim(),
uploadUserName: String(item.uploadUserName || '').trim(),
@@ -2641,22 +2734,51 @@ export default {
if (mb >= 1) return `${mb.toFixed(2)} MB`;
return `${(byteSize / 1024).toFixed(2)} KB`;
},
handleQualificationUploadSuccess(file, row) {
row.name = file.name || row.name || '客商材料';
row.size = this.formatAttachmentSize(file.size || row.size);
row.uploadUserName = this.userInfo.realName || this.userInfo.userName || '';
row.uploadTime = this.$dayjs().format('YYYY-MM-DD HH:mm:ss');
row.url = file.url || row.url || '';
row.files = [file];
handleQualificationUploadSuccess(file) {
const originalName = file.originalName || file.name || '客商材料';
this.qualificationFiles.push({
type: this.resolveQualificationType(originalName),
originalName,
name: originalName,
description: '',
size: this.formatAttachmentSize(file.size),
uploadUserName: this.userInfo.realName || this.userInfo.userName || '',
uploadTime: this.$dayjs().format('YYYY-MM-DD HH:mm:ss'),
url: file.url || file.link || '',
files: [file],
});
},
resolveQualificationType(fileName) {
const name = String(fileName || '').toLocaleLowerCase();
return (
[...this.qualificationTypeOptions]
.filter(item => item?.label || item?.value)
.sort(
(a, b) =>
String(b.label || b.value || '').length - String(a.label || a.value || '').length
)
.find(item => {
const typeText = String(item.label || item.value || '').toLocaleLowerCase();
return typeText && name.includes(typeText);
})?.value || ''
);
},
downloadAttachments() {
const files = this.qualificationFiles.filter(item => item.url);
const source = this.selectedQualificationFiles.length
? this.selectedQualificationFiles
: this.qualificationFiles;
const files = source.filter(item => item.url);
if (!files.length) {
this.$message.warning('暂无可下载附件');
this.$message.warning(
this.selectedQualificationFiles.length ? '所选附件暂无可下载地址' : '暂无可下载附件'
);
return;
}
files.forEach(item => window.open(item.url, '_blank'));
},
handleQualificationSelectionChange(rows) {
this.selectedQualificationFiles = rows || [];
},
normalizeDetail(detail) {
const businessScope = this.splitValue(detail.businessScope);
const registeredDetailAddress =
@@ -2723,10 +2845,9 @@ export default {
const time = this.$dayjs(value).valueOf();
return Number.isFinite(time) ? time : 0;
},
getLatestCreditScore(scores = []) {
sortScoresByLatest(scores = []) {
return (scores || [])
.map((score, index) => ({ score, index }))
.filter(item => String(item.score.creditLevel || '').trim())
.sort((a, b) => {
const scoreDateDiff =
this.getScoreTimeValue(b.score.scoreDate) - this.getScoreTimeValue(a.score.scoreDate);
@@ -2738,7 +2859,12 @@ export default {
this.getScoreTimeValue(b.score.createTime) - this.getScoreTimeValue(a.score.createTime);
if (createTimeDiff) return createTimeDiff;
return b.index - a.index;
})[0]?.score;
});
},
getLatestCreditScore(scores = []) {
return this.sortScoresByLatest(scores)
.filter(item => String(item.score.creditLevel || '').trim())
[0]?.score;
},
applyArchiveCreditFromScores(archive) {
const latestScore = this.getLatestCreditScore(archive.scores || []);
@@ -2754,27 +2880,35 @@ export default {
this.readonly = readonly;
this.activeTab = 'scores';
this.resetDetailPagination();
this.resetChangeRecordPage();
if (row && row.id) {
getDetail(row.id).then(res => {
this.archiveForm = this.normalizeDetail(res.data.data);
this.qualificationFiles = this.parseAttachments(
this.archiveForm.qualificationAttachments
);
this.qualificationUploadFiles = [];
this.archiveBox = true;
this.loadChangeRecords();
});
return;
}
this.archiveForm = this.emptyArchive();
this.qualificationFiles = [];
this.qualificationUploadFiles = [];
this.selectedQualificationFiles = [];
this.archiveBox = true;
},
resetArchive() {
this.readonly = false;
this.archiveForm = this.emptyArchive();
this.qualificationFiles = [];
this.qualificationUploadFiles = [];
this.selectedQualificationFiles = [];
this.scoreBox = false;
this.resetScoreDialog();
this.resetDetailPagination();
this.resetChangeRecordPage();
this.contactBox = false;
this.contactIndex = -1;
this.contactForm = this.emptyContact();
@@ -3056,13 +3190,9 @@ export default {
this.calculateScore(this.currentScore);
},
handleScoreDetailScoreInput(detail, prop, value) {
const normalized = String(value || '')
.replace(/[^\d.]/g, '')
.replace(/^\./, '')
.replace(/(\..*)\./g, '$1')
.replace(/^(\d+)(\.\d{0,2})?.*$/, '$1$2');
const normalized = String(value || '').replace(/\D/g, '');
if (prop === 'reviewScore' && normalized !== '') {
const maxScore = this.getScoreItemFullScore(detail);
const maxScore = Math.floor(this.getScoreItemFullScore(detail));
if (Number(normalized) > maxScore) {
detail[prop] = String(maxScore);
this.$message.warning(
@@ -3112,7 +3242,7 @@ export default {
},
getSignedScore(detail, prop) {
const score = Number(detail[prop] || 0);
return this.isMinusScoreDetail(detail) ? -score : score;
return this.isMinusScoreDetail(detail) && score > 0 ? -score : score;
},
getScoreItemFullScore(detail = {}) {
const itemScore = Number(detail.score);
@@ -3220,7 +3350,7 @@ export default {
this.archiveForm.scores.splice(this.scoreRecordIndex, 1, score);
} else {
this.archiveForm.scores.push(score);
this.handleScoreCurrentChange(this.scorePageCount);
this.handleScoreCurrentChange(1);
}
this.syncArchiveCreditFromScores();
this.activeTab = 'scores';
@@ -3538,6 +3668,24 @@ business-term-field,
margin-bottom: 12px;
}
.qualification-upload-bar {
display: grid;
grid-template-columns: 1fr auto 1fr;
align-items: center;
margin-top: 12px;
:deep(.vehicle-attachment-upload) {
width: auto;
}
&__tip {
grid-column: 2;
color: #909399;
font-size: 13px;
text-align: center;
}
}
.archive-tabs {
margin-top: 18px;
}