From 81c98f6ad8cc9aaf911a036d96132b2f5489e2ca Mon Sep 17 00:00:00 2001 From: b2894lxlx <517289602@qq.com> Date: Sat, 1 Aug 2026 01:23:13 +0800 Subject: [PATCH] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E5=96=84=E5=AE=A2=E5=95=86?= =?UTF-8?q?=E6=A8=A1=E5=9D=97=202=E3=80=81=E5=AE=8C=E5=96=84=E5=9F=BA?= =?UTF-8?q?=E7=A1=80=E6=95=B0=E6=8D=AE=E6=A8=A1=E5=9D=97=203=E3=80=81?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E8=A7=84=E8=8C=83?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- AGENTS.md | 1 + src/api/common.js | 24 +- src/components/empty-pagination/main.vue | 9 +- src/lang/zh.js | 2 +- src/main.js | 8 + src/option/business/contract-manage.js | 5 - src/option/business/project-apply.js | 6 - src/option/business/temporary-credit-limit.js | 3 - src/utils/import-excel.js | 9 +- src/views/authority/apikey.vue | 3 - src/views/authority/apiscope.vue | 1 - src/views/authority/datascope.vue | 1 - src/views/authority/ratelimit.vue | 3 - src/views/authority/role.vue | 1 - src/views/base/airport-master.vue | 58 +- src/views/base/cargo-type.vue | 6 +- src/views/base/common-address.vue | 6 +- src/views/base/currency.vue | 7 +- src/views/base/customer-type.vue | 2 - src/views/base/fee-item.vue | 2 - src/views/base/port-terminal.vue | 119 +- src/views/base/railway-station.vue | 53 +- src/views/base/region.vue | 6 +- src/views/business/common-cargo.vue | 15 +- src/views/business/common-route.vue | 5 +- .../components/business-crud-page.vue | 29 +- src/views/business/process-config.vue | 8 +- src/views/business/project-apply.vue | 1551 ++++++++- src/views/flow/manager.vue | 3 - src/views/flow/model.vue | 3 - src/views/job/jobinfo.vue | 2 +- src/views/job/jobserver.vue | 2 +- src/views/report/reportlist.vue | 2 - src/views/resource/attach.vue | 1 - src/views/resource/oss.vue | 2 - src/views/resource/sms.vue | 2 - src/views/system/authlock.vue | 2 - src/views/system/authlog.vue | 1 - src/views/system/dept.vue | 1 - src/views/system/dict.vue | 2 - src/views/system/dictbiz.vue | 2 - src/views/system/menu.vue | 1 - src/views/system/param.vue | 5 +- src/views/system/tenant.vue | 2 - src/views/system/topmenu.vue | 1 - src/views/system/user.vue | 12 +- src/views/tool/code.vue | 2 - src/views/tool/codesetting.vue | 1 - src/views/tool/formsetting.vue | 2 +- src/views/tool/model.vue | 1 - src/views/transportCapacity/driver.vue | 5 +- src/views/transportCapacity/ship.vue | 6 +- src/views/transportCapacity/vehicle.vue | 6 +- src/views/util/crud-form.vue | 2 +- src/views/util/demo/dict-classic.vue | 1 - src/views/util/demo/dict.vue | 1 - src/views/util/demo/dictbiz.vue | 1 - src/views/vehicle/accident-record.vue | 6 +- .../vehicle/annual-inspection-record.vue | 6 +- .../vehicle/credit-score-quantification.vue | 421 ++- src/views/vehicle/customer-archive.vue | 3054 ++++++++++++++--- src/views/vehicle/etc-record.vue | 9 +- src/views/vehicle/insurance-record.vue | 6 +- src/views/vehicle/maintenance-plan.vue | 6 +- src/views/vehicle/maintenance-record.vue | 6 +- src/views/vehicle/mileage-record.vue | 6 +- src/views/vehicle/oil-electric-record.vue | 6 +- src/views/vehicle/other-expense-record.vue | 6 +- src/views/vehicle/tire-replacement-record.vue | 6 +- src/views/vehicle/transport-change-record.vue | 6 +- src/views/vehicle/violation-record.vue | 6 +- src/views/work/claim.vue | 3 - src/views/work/done.vue | 2 - src/views/work/send.vue | 2 - src/views/work/start.vue | 2 - src/views/work/todo.vue | 3 - vite.config.mjs | 15 +- 77 files changed, 4883 insertions(+), 711 deletions(-) diff --git a/AGENTS.md b/AGENTS.md index ff0870d..a200e7f 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -168,6 +168,7 @@ Avue 表格/表单配置独立存放于 `src/option/` 目录,与 `views` 和 ` - 表格线条颜色需统一使用 `#EFF1F7`,包括表格外边框、单元格分割线和固定列边线。 - 表格偶数行需统一使用 `#FAFAFA` 背景色,固定列单元格必须与对应行背景保持一致。 - 表格操作列同时展示“查看、编辑、删除”等三个按钮时,操作列宽度统一不小于 `220px`,禁止出现按钮裁切或显示不全。 +- 表格操作列按钮统一仅展示文字,禁止配置 `icon` / `:icon` 或在操作按钮、操作下拉项中嵌入图标;顶部工具栏按钮不受此条限制。 - `.avue-crud__header` 顶部间距统一为 `12px`。 - 分页组件整体靠右展示,必须展示接口返回的数据总条数,`X条/页` 的页容量选择器必须放在总条数右侧。 - `.basic-container__card` 的直接子级 `.el-card__body` 内边距统一去除,保持 `padding: 0` diff --git a/src/api/common.js b/src/api/common.js index 3c2e7f8..b89c0e5 100644 --- a/src/api/common.js +++ b/src/api/common.js @@ -1,17 +1,37 @@ import request from '@/axios'; +import { ElLoading, ElMessage } from 'element-plus'; /** * 文件流返回 * @param url 接口地址 * @param params 接口参数 */ -export const exportBlob = (url, params) => { +export const exportBlob = (url, params, options = {}) => { + const { feedback = false, loadingText = '导出中', successText = '导出完成' } = options; + const loading = feedback + ? ElLoading.service({ + lock: true, + text: loadingText, + background: 'rgba(255, 255, 255, 0.7)', + }) + : null; return request({ url: url, params: params, method: 'get', responseType: 'blob', - }); + }) + .then(res => { + if (feedback) { + ElMessage.success(successText); + } + return res; + }) + .finally(() => { + if (loading) { + loading.close(); + } + }); }; export const importBlob = (url, file) => { diff --git a/src/components/empty-pagination/main.vue b/src/components/empty-pagination/main.vue index a71cfe2..bc6d59d 100644 --- a/src/components/empty-pagination/main.vue +++ b/src/components/empty-pagination/main.vue @@ -1,5 +1,5 @@ + @@ -562,7 +559,7 @@ export default { type: 'warning', }).then(() => { NProgress.start(); - exportBlob(this.config.exportUrl, this.buildExportParams()) + exportBlob(this.config.exportUrl, this.buildExportParams(), { feedback: true }) .then(res => { downloadXls(res.data, `${this.config.exportName || this.config.title}${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); }) @@ -573,9 +570,13 @@ export default { }, handleTemplate() { NProgress.start(); - exportBlob(this.config.templateUrl, { - [this.website.tokenHeader]: getToken(), - }) + exportBlob( + this.config.templateUrl, + { + [this.website.tokenHeader]: getToken(), + }, + { feedback: true } + ) .then(res => { downloadXls(res.data, `${this.config.title}模板.xlsx`); }) diff --git a/src/views/business/process-config.vue b/src/views/business/process-config.vue index 7f7b5c2..7f21472 100644 --- a/src/views/business/process-config.vue +++ b/src/views/business/process-config.vue @@ -336,7 +336,6 @@ @@ -345,7 +344,6 @@ @@ -354,7 +352,6 @@ @@ -363,7 +360,6 @@ @@ -372,7 +368,6 @@ @@ -381,7 +376,6 @@ @@ -952,7 +946,7 @@ export default { type: 'warning', }).then(() => { NProgress.start(); - exportBlob(config.exportUrl, this.buildExportParams()) + exportBlob(config.exportUrl, this.buildExportParams(), { feedback: true }) .then(res => { downloadXls( res.data, diff --git a/src/views/business/project-apply.vue b/src/views/business/project-apply.vue index 55d2064..fe264d8 100644 --- a/src/views/business/project-apply.vue +++ b/src/views/business/project-apply.vue @@ -1,20 +1,1563 @@ + + diff --git a/src/views/flow/manager.vue b/src/views/flow/manager.vue index 8fe4e19..46e4a1d 100644 --- a/src/views/flow/manager.vue +++ b/src/views/flow/manager.vue @@ -26,7 +26,6 @@ 变更状态 @@ -34,7 +33,6 @@ 流程图 @@ -42,7 +40,6 @@ 删除 diff --git a/src/views/flow/model.vue b/src/views/flow/model.vue index bef2f28..2b56e0d 100644 --- a/src/views/flow/model.vue +++ b/src/views/flow/model.vue @@ -40,7 +40,6 @@ type="primary" text size="default" - icon="el-icon-setting" v-if="permission.flow_model_update" @click.stop="handleUpdate(scope.row, scope.index)" >配置 @@ -49,7 +48,6 @@ type="primary" text size="default" - icon="el-icon-upload" v-if="permission.flow_model_deploy" @click.stop="handleDeploy(scope.row, scope.index)" >部署 @@ -58,7 +56,6 @@ type="primary" text size="default" - icon="el-icon-delete" v-if="permission.flow_model_delete" @click.stop="handleSlotDelete(scope.row, scope.index)" >删除 diff --git a/src/views/job/jobinfo.vue b/src/views/job/jobinfo.vue index 01f007b..d237025 100644 --- a/src/views/job/jobinfo.vue +++ b/src/views/job/jobinfo.vue @@ -35,7 +35,7 @@ diff --git a/src/views/job/jobserver.vue b/src/views/job/jobserver.vue index 22d93ac..f6fbbe0 100644 --- a/src/views/job/jobserver.vue +++ b/src/views/job/jobserver.vue @@ -35,7 +35,7 @@ diff --git a/src/views/report/reportlist.vue b/src/views/report/reportlist.vue index 314cc0c..2fcc7fc 100644 --- a/src/views/report/reportlist.vue +++ b/src/views/report/reportlist.vue @@ -26,7 +26,6 @@ 设计 @@ -34,7 +33,6 @@ 预览 diff --git a/src/views/resource/attach.vue b/src/views/resource/attach.vue index 31e1085..0c4870b 100644 --- a/src/views/resource/attach.vue +++ b/src/views/resource/attach.vue @@ -40,7 +40,6 @@ 下载 diff --git a/src/views/resource/oss.vue b/src/views/resource/oss.vue index 14f8cc1..6365752 100644 --- a/src/views/resource/oss.vue +++ b/src/views/resource/oss.vue @@ -34,7 +34,6 @@ 调试 @@ -42,7 +41,6 @@ 启用 diff --git a/src/views/resource/sms.vue b/src/views/resource/sms.vue index a97e924..043793f 100644 --- a/src/views/resource/sms.vue +++ b/src/views/resource/sms.vue @@ -34,7 +34,6 @@ 调试 @@ -42,7 +41,6 @@ 启用 diff --git a/src/views/system/authlock.vue b/src/views/system/authlock.vue index 4bca7d8..4c7db05 100644 --- a/src/views/system/authlock.vue +++ b/src/views/system/authlock.vue @@ -49,7 +49,6 @@ 查看 @@ -57,7 +56,6 @@ v-if="(row.lockStatus === 'LOCKED' || row.lockStatus === 'PRE_LOCKED') && !row.expired" text type="primary" - icon="el-icon-key" @click.stop="handleAuthLockUnlock(row)" >解锁 diff --git a/src/views/system/authlog.vue b/src/views/system/authlog.vue index 5a44537..22ab38f 100644 --- a/src/views/system/authlog.vue +++ b/src/views/system/authlog.vue @@ -21,7 +21,6 @@ 查看 diff --git a/src/views/system/dept.vue b/src/views/system/dept.vue index 5f3b684..c78e94e 100644 --- a/src/views/system/dept.vue +++ b/src/views/system/dept.vue @@ -35,7 +35,6 @@ 新增子项 diff --git a/src/views/system/dict.vue b/src/views/system/dict.vue index 6914445..9dc8956 100644 --- a/src/views/system/dict.vue +++ b/src/views/system/dict.vue @@ -35,7 +35,6 @@ 字典配置 @@ -83,7 +82,6 @@ 新增子项 diff --git a/src/views/system/dictbiz.vue b/src/views/system/dictbiz.vue index 3b31529..e77df2b 100644 --- a/src/views/system/dictbiz.vue +++ b/src/views/system/dictbiz.vue @@ -35,7 +35,6 @@ 字典配置 @@ -83,7 +82,6 @@ 新增子项 diff --git a/src/views/system/menu.vue b/src/views/system/menu.vue index 31d6f62..dd54e05 100644 --- a/src/views/system/menu.vue +++ b/src/views/system/menu.vue @@ -35,7 +35,6 @@ 新增子项 diff --git a/src/views/system/param.vue b/src/views/system/param.vue index cb0a975..a5355e7 100644 --- a/src/views/system/param.vue +++ b/src/views/system/param.vue @@ -13,7 +13,7 @@ 搜 索 - 清 空 + 重 置 @@ -87,7 +87,6 @@ v-if="this.permissionList.viewBtn" type="primary" text - icon="el-icon-view" @click="handleView(row)" >查看 @@ -95,7 +94,6 @@ v-if="this.permissionList.editBtn" type="primary" text - icon="el-icon-edit" @click="handleEdit(row)" >编辑 @@ -103,7 +101,6 @@ v-if="this.permissionList.delBtn" type="primary" text - icon="el-icon-delete" @click="rowDel(row)" >删除 diff --git a/src/views/system/tenant.vue b/src/views/system/tenant.vue index ccc54b9..ea7e2ab 100644 --- a/src/views/system/tenant.vue +++ b/src/views/system/tenant.vue @@ -119,7 +119,6 @@ v-if="userInfo.authority.includes('administrator') && !recycleMode" type="primary" text - icon="el-icon-coin" @click.stop="handleRowDatasource(scope.row)" >数据源 @@ -127,7 +126,6 @@ v-if="userInfo.authority.includes('administrator') && !recycleMode" type="primary" text - icon="el-icon-notebook" @click.stop="handleRowPackage(scope.row)" >产品包 diff --git a/src/views/system/topmenu.vue b/src/views/system/topmenu.vue index a67eeb7..867f4ac 100644 --- a/src/views/system/topmenu.vue +++ b/src/views/system/topmenu.vue @@ -42,7 +42,6 @@ v-if="permission.topmenu_setting" type="primary" text - icon="el-icon-setting" @click.stop="handleRowMenuSetting(scope.row)" >配置 diff --git a/src/views/system/user.vue b/src/views/system/user.vue index 905ae90..4760c1d 100644 --- a/src/views/system/user.vue +++ b/src/views/system/user.vue @@ -128,7 +128,6 @@ 查看 @@ -136,48 +135,39 @@ 编辑 - 更 多 + 更 多 diff --git a/src/views/tool/model.vue b/src/views/tool/model.vue index 35b5974..f25228b 100644 --- a/src/views/tool/model.vue +++ b/src/views/tool/model.vue @@ -29,7 +29,6 @@ @@ -104,7 +103,6 @@ @@ -113,7 +111,6 @@ @@ -917,7 +914,7 @@ export default { type: 'warning', }).then(() => { NProgress.start(); - exportBlob('/blade-transport/driver/export-driver', this.buildExportParams()) + exportBlob('/blade-transport/driver/export-driver', this.buildExportParams(), { feedback: true }) .then(res => { downloadXls(res.data, `司机管理${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); }) diff --git a/src/views/transportCapacity/ship.vue b/src/views/transportCapacity/ship.vue index dce55fa..8a0a8c8 100644 --- a/src/views/transportCapacity/ship.vue +++ b/src/views/transportCapacity/ship.vue @@ -90,7 +90,6 @@ @@ -99,7 +98,6 @@ @@ -108,7 +106,6 @@ @@ -945,7 +942,8 @@ export default { NProgress.start(); exportBlob( '/blade-transport/transport-ship/export-transport-ship', - this.buildExportParams() + this.buildExportParams(), + { feedback: true } ) .then(res => { downloadXls(res.data, `船舶管理${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); diff --git a/src/views/transportCapacity/vehicle.vue b/src/views/transportCapacity/vehicle.vue index 2df4fc8..d72b645 100644 --- a/src/views/transportCapacity/vehicle.vue +++ b/src/views/transportCapacity/vehicle.vue @@ -82,7 +82,6 @@ @@ -91,7 +90,6 @@ @@ -100,7 +98,6 @@ @@ -894,7 +891,8 @@ export default { NProgress.start(); exportBlob( '/blade-transport/transport-vehicle/export-transport-vehicle', - this.buildExportParams() + this.buildExportParams(), + { feedback: true } ) .then(res => { downloadXls(res.data, `车辆管理${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); diff --git a/src/views/util/crud-form.vue b/src/views/util/crud-form.vue index b875e93..87550c4 100644 --- a/src/views/util/crud-form.vue +++ b/src/views/util/crud-form.vue @@ -6,7 +6,7 @@ add diff --git a/src/views/util/demo/dict-classic.vue b/src/views/util/demo/dict-classic.vue index 6cff805..29af2da 100644 --- a/src/views/util/demo/dict-classic.vue +++ b/src/views/util/demo/dict-classic.vue @@ -37,7 +37,6 @@ 新增子项 diff --git a/src/views/util/demo/dict.vue b/src/views/util/demo/dict.vue index 4b7df10..0332252 100644 --- a/src/views/util/demo/dict.vue +++ b/src/views/util/demo/dict.vue @@ -91,7 +91,6 @@ 新增子项 diff --git a/src/views/util/demo/dictbiz.vue b/src/views/util/demo/dictbiz.vue index 30316c0..2e1c6e1 100644 --- a/src/views/util/demo/dictbiz.vue +++ b/src/views/util/demo/dictbiz.vue @@ -91,7 +91,6 @@ 新增子项 diff --git a/src/views/vehicle/accident-record.vue b/src/views/vehicle/accident-record.vue index c6122c6..b53628a 100644 --- a/src/views/vehicle/accident-record.vue +++ b/src/views/vehicle/accident-record.vue @@ -439,7 +439,8 @@ export default { NProgress.start(); exportBlob( '/blade-transport/accident-record/export-accident-record', - this.buildExportParams() + this.buildExportParams(), + { feedback: true } ) .then(res => { downloadXls(res.data, `事故记录${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); @@ -461,7 +462,8 @@ export default { }, handleTemplate() { exportBlob( - `/blade-transport/accident-record/export-template?${this.website.tokenHeader}=${getToken()}` + `/blade-transport/accident-record/export-template?${this.website.tokenHeader}=${getToken()}`, + { feedback: true } ).then(res => { downloadXls(res.data, '事故记录模板.xlsx'); }); diff --git a/src/views/vehicle/annual-inspection-record.vue b/src/views/vehicle/annual-inspection-record.vue index b14e039..7a769d7 100644 --- a/src/views/vehicle/annual-inspection-record.vue +++ b/src/views/vehicle/annual-inspection-record.vue @@ -422,7 +422,8 @@ export default { NProgress.start(); exportBlob( '/blade-transport/annual-inspection-record/export-annual-inspection-record', - this.buildExportParams() + this.buildExportParams(), + { feedback: true } ) .then(res => { downloadXls(res.data, `年检记录${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); @@ -443,7 +444,8 @@ export default { exportBlob( `/blade-transport/annual-inspection-record/export-template?${ this.website.tokenHeader - }=${getToken()}` + }=${getToken()}`, + { feedback: true } ).then(res => { downloadXls(res.data, '年检记录模板.xlsx'); }); diff --git a/src/views/vehicle/credit-score-quantification.vue b/src/views/vehicle/credit-score-quantification.vue index 74132d2..8f75f81 100644 --- a/src/views/vehicle/credit-score-quantification.vue +++ b/src/views/vehicle/credit-score-quantification.vue @@ -72,7 +72,6 @@ @@ -81,8 +80,7 @@ 发布 @@ -90,7 +88,6 @@ @@ -99,7 +96,6 @@ @@ -147,7 +143,7 @@
评分表
- + @@ -166,7 +162,7 @@
- + - - - - - - - - - - - - - - + + +
+ + + + + + +
+ + + - +
- - - + +
+ + +
删除
- +添加选项 +
+ + +添加选项 + +
@@ -274,12 +295,23 @@
- + - + index !== currentIndex && String(item.itemName || '').trim() === name + ); + }, saveItem() { if (!this.itemForm.itemName || !this.itemForm.itemName.trim()) { this.$message.warning('请输入评分项目'); return; } + if (this.hasDuplicateItemName(this.itemForm.itemName, this.currentItemIndex)) { + this.$message.warning('评分项目名称不能重复'); + return; + } + if ( + this.itemForm.score === undefined || + this.itemForm.score === null || + this.itemForm.score === '' + ) { + this.$message.warning('请输入分值'); + return; + } if (!this.itemForm.options.length) { this.$message.warning('至少添加1条档位选项'); return; } + const invalidOption = this.itemForm.options.some( + option => + !String(option.optionName || '').trim() || + option.score === undefined || + option.score === null || + option.score === '' + ); + if (invalidOption) { + this.$message.warning('请完整填写档位选项'); + return; + } const item = JSON.parse(JSON.stringify(this.itemForm)); + item.itemName = String(item.itemName || '').trim(); + item.options = item.options.map(option => ({ + ...option, + optionName: String(option.optionName || '').trim(), + })); if (this.currentItemIndex >= 0) { this.currentCategory.items.splice(this.currentItemIndex, 1, item); } else { @@ -629,6 +699,10 @@ export default { this.itemBox = false; }, removeItem(index) { + if (this.currentCategory.items.length <= 1) { + this.$message.warning('评分类目详情至少保留1条评分项目'); + return; + } this.currentCategory.items.splice(index, 1); }, addOption() { @@ -648,6 +722,13 @@ export default { (item, index) => index !== currentIndex && String(item.creditLevel || '').trim() === level ); }, + handleStandardCreditLevelChange(value) { + if (!value) return; + if (this.hasDuplicateCreditLevel(value, this.currentStandardIndex)) { + this.$message.warning('信用等级不能重复'); + this.standardForm.creditLevel = ''; + } + }, isValidCreditLevel(creditLevel) { return this.creditLevelOptions.some(item => item.value === String(creditLevel || '').trim()); }, @@ -681,8 +762,28 @@ export default { this.$message.warning('得分率下限必须小于上限'); return; } + if ( + Number(this.standardForm.creditLimitLower) >= Number(this.standardForm.creditLimitUpper) + ) { + this.$message.warning('授信额度下限必须小于上限'); + return; + } const standard = JSON.parse(JSON.stringify(this.standardForm)); standard.creditLevel = String(standard.creditLevel || '').trim(); + const nextStandards = JSON.parse(JSON.stringify(this.configForm.standards)); + if (this.currentStandardIndex >= 0) { + nextStandards.splice(this.currentStandardIndex, 1, standard); + } else { + nextStandards.push(standard); + } + if (this.hasRangeOverlap(nextStandards, 'scoreRateLower', 'scoreRateUpper')) { + this.$message.warning('评估标准中的得分率区间不能重叠'); + return; + } + if (this.hasRangeOverlap(nextStandards, 'creditLimitLower', 'creditLimitUpper')) { + this.$message.warning('评估标准中的授信额度区间不能重叠'); + return; + } if (this.currentStandardIndex >= 0) { this.configForm.standards.splice(this.currentStandardIndex, 1, standard); } else { @@ -693,6 +794,21 @@ export default { removeStandard(index) { this.configForm.standards.splice(index, 1); }, + isBlankValue(value) { + return value === undefined || value === null || value === ''; + }, + hasRangeOverlap(list, lowerProp, upperProp) { + const ranges = list + .map(item => ({ + lower: Number(item[lowerProp]), + upper: Number(item[upperProp]), + })) + .sort((a, b) => a.lower - b.lower); + return ranges.some((range, index) => { + const next = ranges[index + 1]; + return next && range.upper > next.lower; + }); + }, validateConfig() { if (!this.configForm.name || !this.configForm.name.trim()) { this.$message.warning('请输入评定表名称'); @@ -704,6 +820,13 @@ export default { return false; } for (const category of this.configForm.categories) { + const itemNames = (category.items || []) + .map(item => String(item.itemName || '').trim()) + .filter(Boolean); + if (new Set(itemNames).size !== itemNames.length) { + this.$message.warning(`${category.categoryName}的评分项目名称不能重复`); + return false; + } for (const item of category.items) { if (!item.options || item.options.length === 0) { this.$message.warning(`${item.itemName}至少存在1条档位选项`); @@ -724,9 +847,90 @@ export default { } return true; }, + validatePublishConfig(config) { + const detail = this.normalizeDetail(config || {}); + const basic = detail.categories.find(item => item.categoryCode === 'basic'); + if (!basic || !basic.items || basic.items.length === 0) { + this.$message.warning('发布前至少配置1条基础得分项目'); + return false; + } + for (const category of detail.categories) { + for (const item of category.items || []) { + if (!String(item.itemName || '').trim()) { + this.$message.warning('发布前请完整填写评分项目名称'); + return false; + } + if (!item.options || item.options.length === 0) { + this.$message.warning(`${item.itemName || '评分项目'}至少配置1个档位选项`); + return false; + } + const invalidOption = item.options.some( + option => !String(option.optionName || '').trim() || this.isBlankValue(option.score) + ); + if (invalidOption) { + this.$message.warning(`${item.itemName || '评分项目'}的档位选项未填写完整`); + return false; + } + } + } + + const standards = detail.standards || []; + if (standards.length === 0) { + this.$message.warning('发布前至少配置1条信用等级评估标准'); + return false; + } + const requiredFields = [ + 'scoreRateLower', + 'scoreRateUpper', + 'scoreRateIncrease', + 'creditLimitLower', + 'creditLimitUpper', + 'creditLimitIncrease', + ]; + for (const standard of standards) { + if (!standard.creditLevel) { + this.$message.warning('评估标准中的信用等级不能为空'); + return false; + } + if (!this.isValidCreditLevel(standard.creditLevel)) { + this.$message.warning('评估标准中的信用等级只能选择A/B/C/D/E/F'); + return false; + } + if (requiredFields.some(field => this.isBlankValue(standard[field]))) { + this.$message.warning(`${standard.creditLevel}信用等级评估标准必填项未填写完整`); + return false; + } + if (Number(standard.scoreRateLower) >= Number(standard.scoreRateUpper)) { + this.$message.warning(`${standard.creditLevel}信用等级得分率下限必须小于上限`); + return false; + } + if (Number(standard.creditLimitLower) >= Number(standard.creditLimitUpper)) { + this.$message.warning(`${standard.creditLevel}信用等级授信额度下限必须小于上限`); + return false; + } + } + + const creditLevels = standards.map(item => String(item.creditLevel || '').trim()); + if (new Set(creditLevels).size !== creditLevels.length) { + this.$message.warning('评估标准中的信用等级不能重复'); + return false; + } + if (this.hasRangeOverlap(standards, 'scoreRateLower', 'scoreRateUpper')) { + this.$message.warning('评估标准中的得分率区间不能重叠'); + return false; + } + if (this.hasRangeOverlap(standards, 'creditLimitLower', 'creditLimitUpper')) { + this.$message.warning('评估标准中的授信额度区间不能重叠'); + return false; + } + return true; + }, saveConfig() { if (!this.validateConfig()) return; - submit(this.configForm).then(() => { + submit({ + ...this.configForm, + status: 3, + }).then(() => { this.configBox = false; this.onLoad(this.page); this.$message({ type: 'success', message: '操作成功!' }); @@ -767,8 +971,16 @@ export default { cancelButtonText: '取消', type: 'warning', }) - .then(() => publish(row.id)) - .then(() => { + .then(() => getDetail(row.id)) + .then(res => { + const detail = this.normalizeDetail(res.data.data || {}); + if (!this.validatePublishConfig(detail)) { + return false; + } + return publish(row.id).then(() => true); + }) + .then(published => { + if (!published) return; this.onLoad(this.page); this.$message({ type: 'success', message: '发布成功!' }); }); @@ -776,7 +988,7 @@ export default { handleStatus(row) { const nextStatus = row.status === 1 ? 2 : 1; const actionName = nextStatus === 1 ? '启用' : '停用'; - this.$confirm(`是否确认${actionName}该量表?`, { + this.$confirm(`是否确认${actionName}该评分量化表?`, { confirmButtonText: '确定', cancelButtonText: '取消', type: 'warning', @@ -830,7 +1042,8 @@ export default { NProgress.start(); exportBlob( '/blade-transport/credit-score-quantification/export-credit-score-quantification', - this.buildExportParams() + this.buildExportParams(), + { feedback: true } ) .then(res => { downloadXls(res.data, `评分量化表${this.$dayjs().format('YYYY-MM-DD HH:mm:ss')}.xlsx`); @@ -854,7 +1067,8 @@ export default { exportBlob( `/blade-transport/credit-score-quantification/export-template?${ this.website.tokenHeader - }=${getToken()}` + }=${getToken()}`, + { feedback: true } ).then(res => { downloadXls(res.data, '评分量化表模板.xlsx'); }); @@ -907,18 +1121,105 @@ export default { color: #606266; } +.score-item-form { + width: 100%; + max-width: 1400px; + margin: 0 auto; + padding: 4px 0 6px; + + :deep(.el-form-item) { + margin-bottom: 18px; + } + + :deep(.el-form-item__label) { + padding-right: 10px; + color: #606266; + font-size: 14px; + line-height: 32px; + } + + :deep(.el-input), + :deep(.el-input-number) { + width: 100%; + } + + :deep(.el-input__wrapper), + :deep(.el-input-number .el-input__wrapper) { + min-height: 32px; + border-radius: 0; + box-shadow: 0 0 0 1px #dcdfe6 inset; + } + + :deep(.el-input__inner) { + height: 32px; + color: #303133; + font-size: 14px; + font-weight: 400; + text-align: center; + } + + &__top { + display: grid; + grid-template-columns: 360px 360px; + column-gap: 112px; + + :deep(.el-form-item) { + margin-bottom: 18px; + } + } +} + .option-editor { width: 100%; } .option-row { display: grid; - grid-template-columns: minmax(260px, 1fr) 190px 32px 70px; - gap: 12px; + grid-template-columns: minmax(420px, 1fr) 315px 74px; + gap: 54px; align-items: center; margin-bottom: 14px; } +.option-score { + position: relative; + + .score-unit { + position: absolute; + top: 50%; + right: 12px; + z-index: 1; + margin: 0; + color: #303133; + font-size: 14px; + line-height: 1; + transform: translateY(-50%); + } + + :deep(.el-input__inner) { + padding-right: 42px; + } +} + +.option-delete { + justify-self: start; + min-height: 32px; + padding: 0; + font-size: 14px; +} + +.option-add { + display: flex; + justify-content: center; + margin-top: 6px; + + :deep(.el-button) { + min-height: 32px; + font-size: 16px; + font-weight: 600; + } +} + .range-input { display: flex; align-items: center; @@ -934,4 +1235,42 @@ export default { max-height: 70vh; overflow: auto; } + +:deep(.score-item-dialog) { + .el-dialog__header { + padding: 20px 24px 10px; + } + + .el-dialog__title { + color: #303133; + font-size: 20px; + font-weight: 700; + line-height: 1; + } + + .el-dialog__body { + padding: 12px 24px 14px; + } + + .el-dialog__footer { + padding: 12px 24px 20px; + } + + .dialog-footer, + .el-dialog__footer { + text-align: right; + } + + .el-dialog__footer .el-button { + min-width: 88px; + min-height: 32px; + border-radius: 4px; + font-size: 14px; + font-weight: 400; + } + + .el-dialog__footer .el-button + .el-button { + margin-left: 12px; + } +} diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue index b074f27..f71abc8 100644 --- a/src/views/vehicle/customer-archive.vue +++ b/src/views/vehicle/customer-archive.vue @@ -66,7 +66,6 @@ @@ -75,7 +74,6 @@ @@ -84,7 +82,6 @@ @@ -105,7 +101,6 @@ @@ -114,7 +109,6 @@ @@ -123,7 +117,6 @@ @@ -152,36 +145,22 @@ :model="archiveForm" :rules="formRules" label-position="right" + label-width="auto" :disabled="readonly" class="archive-form" >
基本信息
- - + - - - 临时客商 - 正式客商 - - - - - - + + - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - - + + - + + + + + + + + + + + + + @@ -261,83 +240,101 @@ + + +
+ + + 无固定期限 + +
+
+
- - - - - - - - - - - - - - - - - - - - - - - - + + + + + - + - + - - - - - - - - - - - + + +
+ + +
+
+
+
-
-
资质附件
-
- OCR上传识别 - 添加附件 - 批量下载 -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - -
@@ -437,90 +355,271 @@ 添加评分记录
- - - + + - - - - + - + - - - -