diff --git a/src/api/business/waybill-manage.js b/src/api/business/waybill-manage.js index 2ab51d8..5c7f99c 100644 --- a/src/api/business/waybill-manage.js +++ b/src/api/business/waybill-manage.js @@ -67,6 +67,16 @@ export const getImportDetails = params => request({ url: `${baseUrl}/import-batc export const removeImportBatches = ids => request({ url: `${baseUrl}/import-batch/remove`, method: 'post', params: { ids } }); export const getImportOptions = () => request({ url: `${baseUrl}/import-batch/options`, method: 'get' }); export const exportImportTemplate = () => request({ url: `${baseUrl}/import-batch/export-template`, method: 'get', responseType: 'blob' }); -export const saveImportDraft = data => request({ url: `${baseUrl}/import-batch/draft`, method: 'post', data }); -export const validateImport = data => request({ url: `${baseUrl}/import-batch/validate`, method: 'post', data, responseType: 'blob' }); -export const confirmImport = data => request({ url: `${baseUrl}/import-batch/confirm`, method: 'post', data }); +export const saveImportDraft = data => request({ url: `${baseUrl}/import-batch/draft`, method: 'post', data, timeout: 120000 }); +export const validateImport = data => + request({ url: `${baseUrl}/import-batch/validate`, method: 'post', data, timeout: 120000 }); +export const exportImportFailures = data => + request({ + url: `${baseUrl}/import-batch/export-failures`, + method: 'post', + data, + responseType: 'blob', + timeout: 120000, + }); +export const confirmImport = data => + request({ url: `${baseUrl}/import-batch/confirm`, method: 'post', data, timeout: 120000 }); diff --git a/src/components/address-map-picker/main.vue b/src/components/address-map-picker/main.vue index ac8800f..3e14d8a 100644 --- a/src/components/address-map-picker/main.vue +++ b/src/components/address-map-picker/main.vue @@ -24,10 +24,12 @@ diff --git a/src/views/business/components/waybill-manage-page.vue b/src/views/business/components/waybill-manage-page.vue index 71ea562..12259ef 100644 --- a/src/views/business/components/waybill-manage-page.vue +++ b/src/views/business/components/waybill-manage-page.vue @@ -3173,9 +3173,11 @@ const AMAP_KEY = '653b7cf105ad7fb8ec9b2f5198ade315'; const AMAP_SECURITY_CODE = '5aab65c632e48ebae0d0e28f5b28e21a'; let amapLoader; const standaloneWaybillFormRoute = '/business/waybill-manage/form'; -const standaloneWaybillFormPaths = ['/business/waybill-manage', standaloneWaybillFormRoute]; +const standaloneWaybillListRoute = '/business/waybill-manage'; +const standaloneWaybillFormPaths = [standaloneWaybillListRoute, standaloneWaybillFormRoute]; const standaloneWaybillDetailRoute = '/business/waybill-manage/detail'; const loadingCreateWaybillsStorageKey = 'loading-manage-create-waybills'; +const waybillManageListRefreshKey = 'waybill-manage-list-refresh'; const attachmentViewerPlugins = [ imagePlugin(), @@ -3692,6 +3694,14 @@ export default { deactivated() { this.closeInnerDialogs(); }, + activated() { + // 列表实例被 keep-alive 重新激活时,按标记拉取最新数据 + if (this.formPageLocked || this.detailPageLocked) return; + if (sessionStorage.getItem(waybillManageListRefreshKey)) { + sessionStorage.removeItem(waybillManageListRefreshKey); + this.onLoad(this.page, this.query); + } + }, beforeUnmount() { this.closeInnerDialogs(); }, @@ -3999,7 +4009,19 @@ export default { }, watch: { $route(to, from) { - if (!this.isStandaloneWaybillFormPage) return; + // 列表实例:从表单/详情返回时刷新,避免 keep-alive 仍显示旧数据 + if (!this.formPageLocked && !this.detailPageLocked) { + if ( + to.path === standaloneWaybillListRoute && + (from?.path?.includes('/waybill-manage/form') || + from?.path?.includes('/waybill-manage/detail')) + ) { + sessionStorage.removeItem(waybillManageListRefreshKey); + this.onLoad(this.page, this.query); + } + return; + } + if (!this.formPageLocked || !this.isStandaloneWaybillFormPage) return; if ( to.query.mode !== from?.query?.mode || String(to.query.id || '') !== String(from?.query?.id || '') @@ -4708,8 +4730,9 @@ export default { this.waybillTrackInfo = null; this.waybillTrackHint = ''; if (this.isStandaloneWaybillDetailPage) { + this.markWaybillListNeedRefresh(); this.$router.$avueRouter?.closeTag?.(); - this.$router.push({ path: '/business/waybill-manage', query: {} }); + this.$router.push({ path: standaloneWaybillListRoute, query: {} }); return; } this.detailBox = false; @@ -5438,6 +5461,12 @@ export default { if (this.config.saveAsDraft && saveAsDraft) { submitRow[this.config.draftStatusProp || 'approvalStatus'] = this.config.draftStatus || 'draft'; + } else if ( + this.config.draftStatusProp === 'businessStatus' && + submitRow.businessStatus === (this.config.draftStatus || 'draft') + ) { + // 正式提交:清空草稿态,由后端按过程配置校正为待执行/进行中 + submitRow.businessStatus = ''; } delete submitRow.basicInfoTitle; delete submitRow.templateInfoTitle; @@ -5675,6 +5704,7 @@ export default { }) : Promise.resolve(); return after.then(() => { + this.markWaybillListNeedRefresh(); this.onLoad(this.page); this.$message({ type: 'success', message: '提交成功!' }); done(); @@ -5713,6 +5743,7 @@ export default { }); return after.then(() => { this.attachmentUploadMode = false; + this.markWaybillListNeedRefresh(); this.onLoad(this.page); this.$message({ type: 'success', message: skipMk ? '操作成功!' : '提交成功!' }); done(); @@ -5729,6 +5760,9 @@ export default { getSaveRequest() { return this.api.submit; }, + markWaybillListNeedRefresh() { + sessionStorage.setItem(waybillManageListRefreshKey, '1'); + }, handleDraftSave() { const request = typeof this.api.saveDraft === 'function' ? this.api.saveDraft : this.api.submit; @@ -5739,6 +5773,7 @@ export default { request(submitRow) .then(() => { this.$message.success(`${this.config.draftSaveText || '保存'}成功`); + this.markWaybillListNeedRefresh(); this.onLoad(this.page, this.query); this.closeCrudDialog(); }) @@ -5748,8 +5783,10 @@ export default { }, closeCrudDialog() { if (this.isStandaloneWaybillPage) { + // 关闭独立表单/详情页时标记列表需刷新(含直接点关闭未保存的场景) + this.markWaybillListNeedRefresh(); this.$router.$avueRouter?.closeTag?.(); - this.$router.push({ path: '/business/waybill-manage', query: {} }); + this.$router.push({ path: standaloneWaybillListRoute, query: {} }); return; } const crud = this.$refs.crud; diff --git a/src/views/business/contract-manage.vue b/src/views/business/contract-manage.vue index 36c3819..2b53bf1 100644 --- a/src/views/business/contract-manage.vue +++ b/src/views/business/contract-manage.vue @@ -1034,6 +1034,11 @@ import { fallbackPlugin, imagePlugin, officePlugin, textPlugin } from '@open-fil import '@open-file-viewer/core/style.css'; import pdfWorkerSrc from 'pdfjs-dist/build/pdf.worker.mjs?url'; +const contractManageListRoute = '/business/contract-manage'; +const contractManageFormRoute = '/business/contract-manage/form'; +const contractManageDetailRoute = '/business/contract-manage/detail'; +const contractManageListRefreshKey = 'contract-manage-list-refresh'; + const clone = value => JSON.parse(JSON.stringify(value)); const normalizeOptionalInteger = (value, emptyValue = null) => { if (value === undefined || value === null || value === '' || Number(value) < 0) { @@ -1296,6 +1301,9 @@ export default { flowBox: false, flowUrl: '', processInstanceId: '', + // 页面形态在实例创建时锁定,避免 keep-alive 缓存后随全局 $route 翻转 + formPageLocked: false, + detailPageLocked: false, }; }, computed: { @@ -1313,15 +1321,13 @@ export default { return this.hasPermission(`${this.config.permission}_add`); }, isListPage() { - return !this.isFormPage && !this.isDetailPage; + return !this.formPageLocked && !this.detailPageLocked && !this.isPublicViewPage; }, isFormPage() { - return this.$route.path === '/business/contract-manage/form'; + return this.formPageLocked; }, isDetailPage() { - return ( - this.$route.path === '/business/contract-manage/detail' || this.isPublicViewPage - ); + return this.detailPageLocked || this.isPublicViewPage; }, isPublicViewPage() { return this.$route.path === '/business/contract-manage/public-view'; @@ -1484,9 +1490,21 @@ export default { }, }, watch: { - '$route.fullPath'() { - if (this.isFormPage) this.initFormPage(); - if (this.isDetailPage) this.initDetailPage(); + $route(to, from) { + if (this.isListPage) { + if ( + to.path === contractManageListRoute && + (from?.path?.includes('/contract-manage/form') || + from?.path?.includes('/contract-manage/detail') || + from?.path?.includes('/contract-manage/change')) + ) { + sessionStorage.removeItem(contractManageListRefreshKey); + this.onLoad(this.page, this.query); + } + return; + } + if (this.formPageLocked && to.path === contractManageFormRoute) this.initFormPage(); + if (this.detailPageLocked && to.path === contractManageDetailRoute) this.initDetailPage(); }, settlementConfigTab(tab, oldTab) { if (tab === oldTab) return; @@ -1498,6 +1516,9 @@ export default { }, }, created() { + this.formPageLocked = this.$route.path === contractManageFormRoute; + this.detailPageLocked = + this.$route.path === contractManageDetailRoute || this.isPublicViewPage; if (!this.isPublicViewPage) { this.loadProjectOptions(); this.loadSettlementDictionaries(); @@ -1506,7 +1527,17 @@ export default { if (this.isFormPage) this.initFormPage(); if (this.isDetailPage) this.initDetailPage(); }, + activated() { + if (!this.isListPage) return; + if (sessionStorage.getItem(contractManageListRefreshKey)) { + sessionStorage.removeItem(contractManageListRefreshKey); + this.onLoad(this.page, this.query); + } + }, methods: { + markContractManageListNeedRefresh() { + sessionStorage.setItem(contractManageListRefreshKey, '1'); + }, buildTableOption() { return { ...option, @@ -1648,7 +1679,7 @@ export default { }, openForm(mode, row = {}) { this.$router.push({ - path: '/business/contract-manage/form', + path: contractManageFormRoute, query: mode === 'edit' ? { mode, id: row.id, name: '编辑合同管理' } @@ -1741,8 +1772,9 @@ export default { this.$nextTick(() => this.$refs.contractForm?.clearValidate()); }, closeForm() { + this.markContractManageListNeedRefresh(); this.$router.$avueRouter?.closeTag?.(); - this.$router.push('/business/contract-manage'); + this.$router.push(contractManageListRoute); }, validateBase(action) { if (action === 'temporary') { @@ -2532,8 +2564,9 @@ export default { }); }, closeDetail() { + this.markContractManageListNeedRefresh(); this.$router.$avueRouter?.closeTag?.(); - this.$router.push('/business/contract-manage'); + this.$router.push(contractManageListRoute); }, applyDetailState(detail = {}) { this.detailRow = { @@ -2876,7 +2909,7 @@ export default { }, handleCopy(row) { this.$router.push({ - path: '/business/contract-manage/form', + path: contractManageFormRoute, query: { mode: 'add', copyId: row.id, name: '新增合同管理' }, }); }, diff --git a/src/views/business/loading-manage.vue b/src/views/business/loading-manage.vue index 7fc4461..80138c7 100644 --- a/src/views/business/loading-manage.vue +++ b/src/views/business/loading-manage.vue @@ -3009,6 +3009,8 @@ export default { this.cargoRows = (cargoRows.length ? cargoRows : this.buildCargoRows(this.selectedWaybillRows)).map( row => sanitizeCargoRow(row) ); + // 运单回填时 routeNodes 尚为空会清空发到货地,路线恢复后需再同步 + this.syncRouteAddressFields(); }, restoreRouteChangeRecords() { try { @@ -3644,7 +3646,8 @@ export default { try { const query = { ...this.buildQueryParams(this.candidateQuery), - businessStatus: 'pending', + // 待执行(需接单未接)与进行中(无需接单或已接单)均可配载 + businessStatus: 'pending,running', onlyUnassignedLoading: 1, // 仅查当前账户所属组织及子组织下的运单 allDept: 0, @@ -3764,7 +3767,10 @@ export default { this.routeNodes = this.buildRouteNodes(rows); } this.cargoRows = this.buildCargoRows(rows); - this.syncRouteAddressFields(); + // 编辑回填阶段 routeNodes 尚未恢复时跳过,避免清空已有发到货地 + if (rebuildRoute || this.routeNodes.length) { + this.syncRouteAddressFields(); + } }, buildRouteNodes(rows) { const nodeMap = new Map(); diff --git a/src/views/business/project-apply.vue b/src/views/business/project-apply.vue index a4a10f4..e436ee7 100644 --- a/src/views/business/project-apply.vue +++ b/src/views/business/project-apply.vue @@ -1008,6 +1008,10 @@ const attachmentViewerPlugins = [ fallbackPlugin(), ]; +const projectApplyListRoute = '/business/project-apply'; +const projectApplyFormRoute = '/business/project-apply/form'; +const projectApplyListRefreshKey = 'project-apply-list-refresh'; + const otherAttachmentType = { label: '其他附件', value: '其他附件' }; const normalProjectAttachmentTypeOptions = [ @@ -1367,7 +1371,7 @@ export default { this.loadCargoTypeOptions(); this.loadTransportTypeOptions(); this.loadSettlementModeOptions(); - if (this.$route.path === '/business/project-apply/form') { + if (this.$route.path === projectApplyFormRoute) { this.isFormPageInstance = true; this.openProjectFormPage(); } @@ -1377,10 +1381,32 @@ export default { deactivated() { this.closeInnerDialogs(); }, + activated() { + if (this.isFormPageInstance || this.isPublicViewPage) return; + if (sessionStorage.getItem(projectApplyListRefreshKey)) { + sessionStorage.removeItem(projectApplyListRefreshKey); + this.onLoad(this.page, this.query); + } + }, beforeUnmount() { this.closeInnerDialogs(); }, + watch: { + $route(to, from) { + if (this.isFormPageInstance || this.isPublicViewPage) return; + if ( + to.path === projectApplyListRoute && + from?.path?.includes('/project-apply/form') + ) { + sessionStorage.removeItem(projectApplyListRefreshKey); + this.onLoad(this.page, this.query); + } + }, + }, methods: { + markProjectApplyListNeedRefresh() { + sessionStorage.setItem(projectApplyListRefreshKey, '1'); + }, closeInnerDialogs() { this.changeRecordDetailVisible = false; this.attachmentDocumentPreviewVisible = false; @@ -1506,7 +1532,9 @@ export default { }, closeProjectForm() { if (this.isProjectFormPage) { - this.$router.push('/business/project-apply'); + this.markProjectApplyListNeedRefresh(); + this.$router.$avueRouter?.closeTag?.(); + this.$router.push(projectApplyListRoute); } else { this.projectBox = false; } @@ -1736,7 +1764,7 @@ export default { else if (type === 'view') query.name = `查看${this.config.title}`; else if (type === 'majorSupplement') query.name = '重大项目补录'; else if (type === 'change') query.name = '项目变更'; - this.$router.push({ path: '/business/project-apply/form', query }); + this.$router.push({ path: projectApplyFormRoute, query }); }, resetProjectDialog() { this.$refs.projectForm?.clearValidate(); diff --git a/src/views/vehicle/accident-record.vue b/src/views/vehicle/accident-record.vue index 91b56e0..e5c446f 100644 --- a/src/views/vehicle/accident-record.vue +++ b/src/views/vehicle/accident-record.vue @@ -332,15 +332,34 @@ export default { ? values.vehicleNo.trim() : values.vehicleNo.trim().toUpperCase(); } + // 非必填金额未填写时不要提交 -1 占位值 + values.directEconomicLoss = this.normalizeOptionalAmount(values.directEconomicLoss); + values.insuranceClaimAmount = this.normalizeOptionalAmount(values.insuranceClaimAmount); + values.accidentLocation = this.normalizeOptionalText(values.accidentLocation); + values.accidentReasonDamage = this.normalizeOptionalText(values.accidentReasonDamage); + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { - if (Number(row.directEconomicLoss) < 0) { + const directEconomicLoss = this.normalizeOptionalAmount(row.directEconomicLoss); + const insuranceClaimAmount = this.normalizeOptionalAmount(row.insuranceClaimAmount); + if (directEconomicLoss !== null && Number(directEconomicLoss) < 0) { this.$message.warning('直接经济损失不能小于 0'); return false; } - if (Number(row.insuranceClaimAmount) < 0) { + if (insuranceClaimAmount !== null && Number(insuranceClaimAmount) < 0) { this.$message.warning('保险理赔金额不能小于 0'); return false; } @@ -353,13 +372,9 @@ export default { return false; } if ( - row.directEconomicLoss !== undefined && - row.directEconomicLoss !== null && - row.directEconomicLoss !== '' && - row.insuranceClaimAmount !== undefined && - row.insuranceClaimAmount !== null && - row.insuranceClaimAmount !== '' && - Number(row.insuranceClaimAmount) > Number(row.directEconomicLoss) + directEconomicLoss !== null && + insuranceClaimAmount !== null && + Number(insuranceClaimAmount) > Number(directEconomicLoss) ) { this.$message.warning('保险理赔金额不能超过直接经济损失金额'); return false; @@ -448,6 +463,11 @@ export default { const detail = res.data.data; detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = detail.vehicleType || '车辆'; + detail.directEconomicLoss = this.normalizeOptionalAmount(detail.directEconomicLoss); + detail.insuranceClaimAmount = this.normalizeOptionalAmount(detail.insuranceClaimAmount); + detail.accidentLocation = this.normalizeOptionalText(detail.accidentLocation) || ''; + detail.accidentReasonDamage = this.normalizeOptionalText(detail.accidentReasonDamage) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.updateVehicleTypeDisplays(detail.vehicleType); this.vehicleOptions = []; diff --git a/src/views/vehicle/annual-inspection-record.vue b/src/views/vehicle/annual-inspection-record.vue index 1a81cd5..961c068 100644 --- a/src/views/vehicle/annual-inspection-record.vue +++ b/src/views/vehicle/annual-inspection-record.vue @@ -367,11 +367,33 @@ export default { } else { values.shipInspectionType = undefined; } + // 费用必填,-1 转 null 后由校验拦截;非必填文本清除 "-1" + values.fee = this.normalizeOptionalAmount(values.fee); + values.inspectionUnit = this.normalizeOptionalText(values.inspectionUnit); + values.assessmentUnit = this.normalizeOptionalText(values.assessmentUnit); + values.passengerTypeLevel = this.normalizeOptionalText(values.passengerTypeLevel); + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { - if (Number(row.fee) < 0) { + const fee = this.normalizeOptionalAmount(row.fee); + if (fee === null) { + this.$message.warning('请输入费用'); + return false; + } + if (Number(fee) < 0) { this.$message.warning('费用不能小于 0'); return false; } @@ -465,6 +487,11 @@ export default { getDetail(this.form.id).then(res => { const detail = res.data.data; detail.attachments = this.parseAttachments(detail.attachments); + detail.fee = this.normalizeOptionalAmount(detail.fee); + detail.inspectionUnit = this.normalizeOptionalText(detail.inspectionUnit) || ''; + detail.assessmentUnit = this.normalizeOptionalText(detail.assessmentUnit) || ''; + detail.passengerTypeLevel = this.normalizeOptionalText(detail.passengerTypeLevel) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.updateVehicleTypeDisplays(detail.vehicleType); this.vehicleOptions = []; diff --git a/src/views/vehicle/customer-archive.vue b/src/views/vehicle/customer-archive.vue index cefecfc..55575dd 100644 --- a/src/views/vehicle/customer-archive.vue +++ b/src/views/vehicle/customer-archive.vue @@ -1549,6 +1549,10 @@ import SectionCard from '@/components/section-card/main.vue'; import PdfPreview from '@/components/pdf-preview/main.vue'; import ChangeRecordDetailDialog from '@/components/change-record-detail-dialog/main.vue'; +const customerArchiveListRoute = '/vehicle/customer-archive'; +const customerArchiveFormRoute = '/vehicle/customer-archive/form'; +const customerArchiveListRefreshKey = 'customer-archive-list-refresh'; + const createTimeRangeMap = { createTimeRange: ['createTimeStart', 'createTimeEnd'], }; @@ -1646,6 +1650,8 @@ export default { readonly: false, reviewMode: false, listActivated: false, + // 表单页实例标记:创建时按路由落定,避免 keep-alive 缓存后随全局 $route 翻转 + isFormPageInstance: false, originalAccessType: '', activeTab: 'scores', archiveForm: this.emptyArchive(), @@ -2033,6 +2039,7 @@ export default { this.openArchive({ id }, true); return; } + this.isFormPageInstance = this.$route.path === customerArchiveFormRoute; this.initDeptTree(); this.initRegionOptions(); this.initBusinessDictionaries(); @@ -2046,7 +2053,13 @@ export default { } }, activated() { - if (this.isArchivePage || this.isPublicViewPage) return; + if (this.isFormPageInstance || this.isPublicViewPage) return; + if (sessionStorage.getItem(customerArchiveListRefreshKey)) { + sessionStorage.removeItem(customerArchiveListRefreshKey); + this.onLoad(this.page, this.query); + this.listActivated = true; + return; + } if (!this.listActivated) { this.listActivated = true; return; @@ -2065,9 +2078,7 @@ export default { }; }, isArchivePage() { - return ( - this.$route.path === '/vehicle/customer-archive/form' || this.isPublicViewPage - ); + return this.isFormPageInstance || this.isPublicViewPage; }, isPublicViewPage() { return ( @@ -2256,6 +2267,16 @@ export default { }, }, watch: { + $route(to, from) { + if (this.isFormPageInstance || this.isPublicViewPage) return; + if ( + to.path === customerArchiveListRoute && + from?.path?.includes('/customer-archive/form') + ) { + sessionStorage.removeItem(customerArchiveListRefreshKey); + this.onLoad(this.page, this.query); + } + }, 'archiveForm.registeredDetailAddress'() { this.$nextTick(() => this.checkOverflow('registeredDetailInput', 'registeredDetailOverflow')); }, @@ -2264,6 +2285,9 @@ export default { }, }, methods: { + markCustomerArchiveListNeedRefresh() { + sessionStorage.setItem(customerArchiveListRefreshKey, '1'); + }, hasPermission(code) { return this.isAdmin || this.validData(this.permission[code], false); }, @@ -4016,27 +4040,28 @@ export default { openArchivePage(row) { const isEdit = Boolean(row?.id); this.$router.push({ - path: '/vehicle/customer-archive/form', + path: customerArchiveFormRoute, query: isEdit ? { id: row.id, name: '编辑客商档案' } : { name: '新增客商档案' }, }); }, viewArchive(row) { this.$router.push({ - path: '/vehicle/customer-archive/form', + path: customerArchiveFormRoute, query: { id: row.id, name: '查看客商档案', view: '1' }, }); }, openReview(row) { this.$router.push({ - path: '/vehicle/customer-archive/form', + path: customerArchiveFormRoute, query: { id: row.id, name: '客商复评', review: '1' }, }); }, closeArchive() { if (this.isPublicViewPage) return; this.archiveBox = false; + this.markCustomerArchiveListNeedRefresh(); this.$router.$avueRouter?.closeTag?.(); - this.$router.push('/vehicle/customer-archive'); + this.$router.push(customerArchiveListRoute); }, openArchive(row, readonly = false) { this.readonly = readonly; diff --git a/src/views/vehicle/insurance-record.vue b/src/views/vehicle/insurance-record.vue index 4c090eb..f8c756e 100644 --- a/src/views/vehicle/insurance-record.vue +++ b/src/views/vehicle/insurance-record.vue @@ -381,8 +381,26 @@ export default { if (values.policyNo) { values.policyNo = values.policyNo.trim(); } + // 非必填项未填写时不要提交 -1 占位值 + values.insuredAmount = this.normalizeOptionalAmount(values.insuredAmount); + values.premium = this.normalizeOptionalAmount(values.premium); + values.invoiceNo = this.normalizeOptionalText(values.invoiceNo); + values.invoiceDate = this.normalizeOptionalText(values.invoiceDate); + values.remark = this.normalizeOptionalText(values.remark); + values.policyFile = this.normalizeOptionalText(values.policyFile); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, normalizeDecimalInput(prop, value) { const sanitized = String(value ?? '').replace(/[^\d.]/g, ''); const [integerPart, ...decimalParts] = sanitized.split('.'); @@ -398,8 +416,18 @@ export default { this.$message.warning('结束日期不能早于开始日期'); return false; } - if (Number(row.insuredAmount) < 0 || Number(row.premium) < 0) { - this.$message.warning('保额、保费不能小于 0'); + const insuredAmount = this.normalizeOptionalAmount(row.insuredAmount); + const premium = this.normalizeOptionalAmount(row.premium); + if (insuredAmount !== null && Number(insuredAmount) < 0) { + this.$message.warning('保额不能小于 0'); + return false; + } + if (premium === null) { + this.$message.warning('请输入保费'); + return false; + } + if (Number(premium) < 0) { + this.$message.warning('保费不能小于 0'); return false; } if (row.remark && row.remark.length > 200) { @@ -479,15 +507,25 @@ export default { this.vehicleOptions = []; this.loadVehicleOptions(''); this.form.vehicleType = '车辆'; + this.form.insuredAmount = ''; + this.form.invoiceNo = ''; + this.form.invoiceDate = ''; + this.form.remark = ''; this.initOcrTemplateOptions('车辆', true); } if (['edit', 'view'].includes(type)) { this.isDetailLoading = true; getDetail(this.form.id) .then(res => { + const detail = res.data.data || {}; this.form = { - ...res.data.data, - vehicleType: res.data.data.vehicleType || '车辆', + ...detail, + vehicleType: detail.vehicleType || '车辆', + insuredAmount: this.normalizeOptionalAmount(detail.insuredAmount), + premium: this.normalizeOptionalAmount(detail.premium), + invoiceNo: this.normalizeOptionalText(detail.invoiceNo) || '', + invoiceDate: this.normalizeOptionalText(detail.invoiceDate) || '', + remark: this.normalizeOptionalText(detail.remark) || '', }; this.vehicleOptions = []; this.loadVehicleOptions(this.form.vehicleNo || ''); diff --git a/src/views/vehicle/maintenance-plan.vue b/src/views/vehicle/maintenance-plan.vue index 9c05143..03c6bbf 100644 --- a/src/views/vehicle/maintenance-plan.vue +++ b/src/views/vehicle/maintenance-plan.vue @@ -620,11 +620,11 @@ export default { }); }, formatMileage(value, unit) { - if (value === undefined || value === null || value === '') return ''; + if (value === undefined || value === null || value === '' || Number(value) === -1) return ''; return `${Math.max(Number(value), 0)} ${unit || '公里'}`; }, isUnsetNextMaintenanceMileage(value) { - return Number(value) === -1; + return value === undefined || value === null || value === '' || Number(value) === -1; }, formatNextMaintenanceMileage(value, unit) { if (this.isUnsetNextMaintenanceMileage(value)) return ''; @@ -647,7 +647,7 @@ export default { } }, isEmpty(value) { - return value === undefined || value === null || value === ''; + return value === undefined || value === null || value === '' || Number(value) === -1; }, toNumber(value) { return this.isEmpty(value) ? null : Number(value); @@ -686,12 +686,34 @@ export default { const values = { ...row }; values.vehicleType = values.vehicleType || '车辆'; values.mileageUnit = values.vehicleType === '船舶' ? '海里' : '公里'; + // 非必填里程未填写时不要提交 -1 占位值 + values.mileage = this.normalizeOptionalAmount(values.mileage); + values.nextMaintenanceMileage = this.normalizeOptionalAmount(values.nextMaintenanceMileage); + values.maintainer = this.normalizeOptionalText(values.maintainer); + values.maintenanceItem = this.normalizeOptionalText(values.maintenanceItem); + values.storeName = this.normalizeOptionalText(values.storeName); + values.contactPhone = this.normalizeOptionalText(values.contactPhone); + values.address = this.normalizeOptionalText(values.address); + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { - const mileage = this.toNumber(row.mileage); - const nextMaintenanceMileage = this.toNumber(row.nextMaintenanceMileage); + const mileage = this.toNumber(this.normalizeOptionalAmount(row.mileage)); + const nextMaintenanceMileage = this.toNumber( + this.normalizeOptionalAmount(row.nextMaintenanceMileage) + ); if ( mileage !== null && nextMaintenanceMileage !== null && @@ -782,12 +804,16 @@ export default { detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = detail.vehicleType || '车辆'; detail.mileageUnit = detail.vehicleType === '船舶' ? '海里' : '公里'; - if (type === 'edit') { - if (Number(detail.mileage) === -1) detail.mileage = ''; - if (Number(detail.nextMaintenanceMileage) === -1) { - detail.nextMaintenanceMileage = ''; - } - } + detail.mileage = this.normalizeOptionalAmount(detail.mileage); + detail.nextMaintenanceMileage = this.normalizeOptionalAmount( + detail.nextMaintenanceMileage + ); + detail.maintainer = this.normalizeOptionalText(detail.maintainer) || ''; + detail.maintenanceItem = this.normalizeOptionalText(detail.maintenanceItem) || ''; + detail.storeName = this.normalizeOptionalText(detail.storeName) || ''; + detail.contactPhone = this.normalizeOptionalText(detail.contactPhone) || ''; + detail.address = this.normalizeOptionalText(detail.address) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.updateVehicleType(detail.vehicleType); this.vehicleOptions = []; diff --git a/src/views/vehicle/mileage-record.vue b/src/views/vehicle/mileage-record.vue index 1343493..c68e527 100644 --- a/src/views/vehicle/mileage-record.vue +++ b/src/views/vehicle/mileage-record.vue @@ -345,7 +345,7 @@ export default { return JSON.stringify(value); }, isEmpty(value) { - return value === undefined || value === null || value === ''; + return value === undefined || value === null || value === '' || Number(value) === -1; }, toNumber(value) { return this.isEmpty(value) ? null : Number(value); @@ -356,6 +356,15 @@ export default { normalizeIntegerInput(prop, value) { this.form[prop] = String(value ?? '').replace(/\D/g, ''); }, + normalizeOptionalAmount(value) { + if (this.isEmpty(value)) return null; + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, normalizeRow(row) { const values = { ...row }; values.vehicleType = '车辆'; @@ -363,6 +372,12 @@ export default { if (values.vehicleNo) { values.vehicleNo = values.vehicleNo.trim().toUpperCase(); } + // 非必填里程未填写时不要提交 -1 占位值 + values.previousMonthMileage = this.normalizeOptionalAmount(values.previousMonthMileage); + values.currentMonthMileage = this.normalizeOptionalAmount(values.currentMonthMileage); + values.monthlyMileage = this.normalizeOptionalAmount(values.monthlyMileage); + values.totalMileage = this.normalizeOptionalAmount(values.totalMileage); + values.remark = this.normalizeOptionalText(values.remark); const previousMonthMileage = this.toNumber(values.previousMonthMileage); const currentMonthMileage = this.toNumber(values.currentMonthMileage); if ( @@ -503,6 +518,11 @@ export default { detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = '车辆'; detail.mileageUnit = '公里'; + detail.previousMonthMileage = this.normalizeOptionalAmount(detail.previousMonthMileage); + detail.currentMonthMileage = this.normalizeOptionalAmount(detail.currentMonthMileage); + detail.monthlyMileage = this.normalizeOptionalAmount(detail.monthlyMileage); + detail.totalMileage = this.normalizeOptionalAmount(detail.totalMileage); + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.vehicleOptions = []; this.loadVehicleOptions(this.form.vehicleNo || ''); diff --git a/src/views/vehicle/oil-electric-record.vue b/src/views/vehicle/oil-electric-record.vue index 9fb5fd9..97ffaef 100644 --- a/src/views/vehicle/oil-electric-record.vue +++ b/src/views/vehicle/oil-electric-record.vue @@ -337,7 +337,7 @@ export default { return JSON.stringify(value); }, isEmpty(value) { - return value === undefined || value === null || value === ''; + return value === undefined || value === null || value === '' || Number(value) === -1; }, normalizeDecimalInput(prop, value) { const sanitized = String(value ?? '').replace(/[^\d.]/g, ''); @@ -346,6 +346,15 @@ export default { ? `${integerPart || '0'}.${decimalParts.join('').slice(0, 2)}` : integerPart; }, + normalizeOptionalAmount(value) { + if (this.isEmpty(value)) return null; + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, normalizeRow(row) { const values = { ...row }; values.vehicleType = values.vehicleType || '车辆'; @@ -359,6 +368,16 @@ export default { if (values.feeType === '充电') { values.oilProduct = undefined; } + // 非必填数值未填写时不要提交 -1;交易金额必填,-1 转 null 后由校验拦截 + values.quantity = this.normalizeOptionalAmount(values.quantity); + values.unitPrice = this.normalizeOptionalAmount(values.unitPrice); + values.transactionAmount = this.normalizeOptionalAmount(values.transactionAmount); + values.balance = this.normalizeOptionalAmount(values.balance); + values.cardNo = this.normalizeOptionalText(values.cardNo); + values.cardHolder = this.normalizeOptionalText(values.cardHolder); + values.station = this.normalizeOptionalText(values.station); + values.oilProduct = this.normalizeOptionalText(values.oilProduct); + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, @@ -472,6 +491,15 @@ export default { const detail = res.data.data; detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = detail.vehicleType || '车辆'; + detail.quantity = this.normalizeOptionalAmount(detail.quantity); + detail.unitPrice = this.normalizeOptionalAmount(detail.unitPrice); + detail.transactionAmount = this.normalizeOptionalAmount(detail.transactionAmount); + detail.balance = this.normalizeOptionalAmount(detail.balance); + detail.cardNo = this.normalizeOptionalText(detail.cardNo) || ''; + detail.cardHolder = this.normalizeOptionalText(detail.cardHolder) || ''; + detail.station = this.normalizeOptionalText(detail.station) || ''; + detail.oilProduct = this.normalizeOptionalText(detail.oilProduct) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.updateVehicleType(detail.vehicleType); this.vehicleOptions = []; diff --git a/src/views/vehicle/tire-replacement-record.vue b/src/views/vehicle/tire-replacement-record.vue index ad88d81..7d4d238 100644 --- a/src/views/vehicle/tire-replacement-record.vue +++ b/src/views/vehicle/tire-replacement-record.vue @@ -298,19 +298,41 @@ export default { if (values.vehicleNo) { values.vehicleNo = values.vehicleNo.trim().toUpperCase(); } + // 非必填数量未填写时不要提交 -1;费用必填,-1 转 null 后由校验拦截 + values.tireQuantity = this.normalizeOptionalAmount(values.tireQuantity); + values.replacementCost = this.normalizeOptionalAmount(values.replacementCost); + values.handler = this.normalizeOptionalText(values.handler); + values.tireBrand = this.normalizeOptionalText(values.tireBrand); + values.replacementDescription = this.normalizeOptionalText(values.replacementDescription); + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { - if (Number(row.replacementCost) < 0) { + const replacementCost = this.normalizeOptionalAmount(row.replacementCost); + const tireQuantity = this.normalizeOptionalAmount(row.tireQuantity); + if (replacementCost === null) { + this.$message.warning('请输入换胎费用'); + return false; + } + if (Number(replacementCost) < 0) { this.$message.warning('换胎费用不能小于 0'); return false; } if ( - row.tireQuantity !== undefined && - row.tireQuantity !== null && - row.tireQuantity !== '' && - (!Number.isInteger(Number(row.tireQuantity)) || Number(row.tireQuantity) <= 0) + tireQuantity !== null && + (!Number.isInteger(Number(tireQuantity)) || Number(tireQuantity) <= 0) ) { this.$message.warning('换胎数量必须为正整数'); return false; @@ -391,9 +413,16 @@ export default { } if (['edit', 'view'].includes(type)) { getDetail(this.form.id).then(res => { - const detail = res.data.data; - detail.attachments = this.parseAttachments(detail.attachments); - this.form = detail; + const detail = res.data.data; + detail.attachments = this.parseAttachments(detail.attachments); + detail.tireQuantity = this.normalizeOptionalAmount(detail.tireQuantity); + detail.replacementCost = this.normalizeOptionalAmount(detail.replacementCost); + detail.handler = this.normalizeOptionalText(detail.handler) || ''; + detail.tireBrand = this.normalizeOptionalText(detail.tireBrand) || ''; + detail.replacementDescription = + this.normalizeOptionalText(detail.replacementDescription) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; + this.form = detail; this.vehicleOptions = []; this.loadVehicleOptions(this.form.vehicleNo || ''); }); diff --git a/src/views/vehicle/transport-change-record.vue b/src/views/vehicle/transport-change-record.vue index 140c368..207d344 100644 --- a/src/views/vehicle/transport-change-record.vue +++ b/src/views/vehicle/transport-change-record.vue @@ -289,15 +289,20 @@ export default { normalizeRow(row) { const values = { ...row }; values.vehicleType = values.vehicleType || '车辆'; - if (values.vehicleNo) { - values.vehicleNo = - values.vehicleType === '船舶' - ? values.vehicleNo.trim() - : values.vehicleNo.trim().toUpperCase(); + // 非必填文本未填写时不要提交 "-1" 占位值 + values.vehicleNo = this.normalizeOptionalText(values.vehicleNo); + if (values.vehicleNo && values.vehicleType !== '船舶') { + values.vehicleNo = values.vehicleNo.toUpperCase(); } + values.remark = this.normalizeOptionalText(values.remark); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { if (row.changeContent && row.changeContent.length > 200) { this.$message.warning('变更内容不能超过 200 字'); @@ -389,6 +394,8 @@ export default { const detail = res.data.data; detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = detail.vehicleType || '车辆'; + detail.vehicleNo = this.normalizeOptionalText(detail.vehicleNo) || ''; + detail.remark = this.normalizeOptionalText(detail.remark) || ''; this.form = detail; this.updateVehicleType(detail.vehicleType); this.vehicleOptions = []; diff --git a/src/views/vehicle/violation-record.vue b/src/views/vehicle/violation-record.vue index bb3d1e6..3e7fa5a 100644 --- a/src/views/vehicle/violation-record.vue +++ b/src/views/vehicle/violation-record.vue @@ -448,9 +448,25 @@ export default { } else { values.violationItem = undefined; } + // 非必填项未填写时不要提交 -1 占位值 + values.fineAmount = this.normalizeOptionalAmount(values.fineAmount); + values.deductPoints = this.normalizeOptionalAmount(values.deductPoints); + values.penaltyUnit = this.normalizeOptionalText(values.penaltyUnit); + values.processResult = this.normalizeOptionalText(values.processResult); values.attachments = this.stringifyAttachments(values.attachments); return values; }, + normalizeOptionalAmount(value) { + if (value === undefined || value === null || value === '' || Number(value) === -1) { + return null; + } + return value; + }, + normalizeOptionalText(value) { + if (value === undefined || value === null) return null; + const text = String(value).trim(); + return !text || text === '-1' ? null : text; + }, validateRow(row) { if (row.vehicleType === '船舶' && !row.violationItem) { this.$message.warning('请输入事项'); @@ -467,17 +483,17 @@ export default { this.$message.warning('日期不能超过当前时间'); return false; } - if (Number(row.fineAmount) < 0) { + const fineAmount = this.normalizeOptionalAmount(row.fineAmount); + const deductPoints = this.normalizeOptionalAmount(row.deductPoints); + if (fineAmount !== null && Number(fineAmount) < 0) { this.$message.warning('被罚金额不能小于 0'); return false; } if ( - row.deductPoints !== undefined && - row.deductPoints !== null && - row.deductPoints !== '' && - (!Number.isInteger(Number(row.deductPoints)) || - Number(row.deductPoints) < 0 || - Number(row.deductPoints) > 15) + deductPoints !== null && + (!Number.isInteger(Number(deductPoints)) || + Number(deductPoints) < 0 || + Number(deductPoints) > 15) ) { this.$message.warning('被扣分数范围为 0-15 分'); return false; @@ -570,6 +586,10 @@ export default { detail.attachments = this.parseAttachments(detail.attachments); detail.vehicleType = detail.vehicleType || '车辆'; detail.processStatus = detail.processStatus || '未处理'; + detail.fineAmount = this.normalizeOptionalAmount(detail.fineAmount); + detail.deductPoints = this.normalizeOptionalAmount(detail.deductPoints); + detail.penaltyUnit = this.normalizeOptionalText(detail.penaltyUnit) || ''; + detail.processResult = this.normalizeOptionalText(detail.processResult) || ''; this.form = detail; this.updateVehicleTypeDisplays(detail.vehicleType); this.vehicleOptions = [];