Files
gxwebsoft 5bb072223f feat(loading-manage): 配载管理详情及重新派单改用独立页面
- 新增 `/business/loading-manage/detail` 路由,详情页由独立页面承载
- 统一将新增、编辑、详情和重新派单均采用独立表单页/详情页显示
- 修改组件内逻辑,新增 `isStandalonePage` 计算属性统一控制页面与弹窗切换
- 修改列表页链接及操作行为,详情和重新派单按钮跳转至对应独立页面
- 去除旧详情弹窗模式,相关样式调整支持独立页面自然滚动
- 添加路由监听,支持页面刷新和切换时正确初始化详情或表单数据
- 兼容老链接 `/business/loading-manage?detailId=x` 自动跳详情新路由
- 修正弹窗底栏样式,去除写死间距,统一由全局规则控制
- 代码中禁止顶层 scoped style 使用 `//` 注释,改用 `/* */` 避免编译错误
2026-09-17 22:40:41 +08:00

64 lines
10 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 2026-09-17 工作日志
## 配载管理(loading-manage):弹窗全部改为独立表单页/详情页
- 需求:`/business/loading-manage` 不再用弹窗,改成与新增合同(`/business/contract-manage/form?mode=add&name=新增合同管理`)一致的独立页面。
- 现状:新增/编辑**已经**是独立页(组件内 `isStandaloneFormPage` + `/business/loading-manage/form` 路由),但「详情」和「重新派单」仍是 el-dialog(用户截图即详情弹窗)。
- 改动(3 个文件):
1. `src/router/views/index.js`:新增 `/business/loading-manage/detail`name 配载单详情,`meta.keepAlive:false, activeMenu:'/business/loading-manage'`),组件仍是 `loading-manage.vue`
2. `src/views/business/loading-manage.vue`
- computed 新增 `isStandaloneDetailPage`path==='/business/loading-manage/detail')、`isStandalonePage`form|detail 并集,作为隐藏列表容器的统一开关)、`detailPageTitle``formPageDefaultTitle`add/edit/reassign 映射);`isStandaloneFormPage` 放行 `mode=reassign`
- 模板中所有控制「是否独立页/是否弹窗」的 `isStandaloneFormPage` 改为 `isStandalonePage`;顶部标题按详情/表单取 `detailPageTitle`/`formPageTitle`
- 新增 `gotoLoadingDetail(row)`push `/detail?id=&name=配载单详情`,替换「配载单号」链接与操作列「详情」)、`gotoLoadingReassign(row)`push `/form?mode=reassign&id=&name=重新派单`)、`initStandaloneDetailPage()``initStandaloneFormPage` 模式透传 edit/reassign`openLoadingDialog` 对 add/edit/reassign 一律转独立页;`closeLoadingDialog` 判据改 `isStandalonePage`
- `mounted` / `watch $route` 增加详情页分支(直接打开与页内切换都要 init);detail 分支除 id 变化外,`dialogMode !== 'view'` 也重新 init(防止从表单页切详情时残留表单态)。
- 兼容旧链接:`/business/loading-manage?detailId=x` 仍可用,会 replace 到详情页。
- 样式:底栏去掉写死的 `gap:8px`(全站统一 12px);页面模式的内容区解除 `max-height:78vh` 内嵌滚动盒 —— 原 `:global(.loading-manage-form-page .loading-manage-dialog__body)` 权重 (0,2,0) 低于 scoped 规则 (0,3,0) 一直没生效,改为 `.loading-manage-page .loading-manage-form-dialog.loading-manage-form-page .loading-manage-dialog__body` (0,4,0),内容改随 `#avue-view` 自然滚动(与合同页一致)。
3. `src/views/business/components/waybill-manage-page.vue``openLoadingDetail``/business/loading-manage?detailId=` 改为 push `/business/loading-manage/detail?id=&name=配载单详情`
- 校验:dev server2889)单独编译 4 个模块均 HTTP 200(含 scoped scss);`vite build` 仍会在无关文件 `src/page/login/facelogin.vue` 被沙箱敏感内容保护中断。
- 踩坑:**`<style scoped lang="scss">` 顶层写 `//` 注释**会让该样式模块编译 500`Unexpected '/'. Escaping special characters with \ may help.`),已实测确认;顶层必须用 `/* */`
- 未做:登录态无法在浏览器实测(无测试账号),需用户点 `/business/loading-manage` → 详情/重新派单 自测;`voucher-manage-detail` 跳配载时带的 `?loadingNo=` 参数本来就未被列表消费(历史遗留)。
## 运单管理详情:打卡时间轴改为按打卡顺序展示
- 文件:`src/views/business/components/waybill-manage-page.vue`(详情页「执行详情 → 打卡详情」tab)
- 需求:时间轴不再固定按流程节点顺序(发货/在途/到货/卸货/签收/回单),改为按打卡时间先后展示。
- 实现(不改后端、不改原始数据):
1. 新增 computed `orderedWaybillPunchRecords`:映射出 `punchedAt`(毫秒时间戳)后排序 —— **已打卡记录按打卡时间升序排在前**,未打卡记录保持后端返回的节点顺序排在其后;时间相同用原索引稳定排序。
2. 新增 method `waybillPunchRecordTimestamp(record)``punched === false``statusName === '未打卡'` 直接返回 null(防止后端返回计划时间造成误序);优先 `this.$dayjs(text).valueOf()`,失败兜底 `new Date(text.replace(/-/g,'/'))`(兼容 Safari)。
3. 模板 `el-timeline``v-for` 改用 `orderedWaybillPunchRecords``key``record.nodeCode || record.id || index` 改为 `${nodeCode||id||'punch'}-${index}`,避免同节点多次打卡(在途)时 key 重复。
- 校验:项目根目录临时脚本 `_verify-sfc.mjs`@vue/compiler-sfc parse + compileScript + compileTemplate)通过,已删除脚本。
- 注意:`getPunchRecords``src/api/business/waybill-manage.js``/punch-records`)后端未提供节点排序字段,排序只能在前端做。
## 保险记录批量导入:前端归一化日期格式
- 文件:`src/views/vehicle/insurance-record.vue`(仅此一个文件)
- 背景:保险记录批量导入是**后端驱动**——前端 `handleImport``importBlob` 把原始 Excel 直接 POST 到 `/blade-transport/insurance-record/import-insurance-record`,前端不解析行。后端只认 `2026-09-01``2026-9-1` 导入失败。
- 决策:用户选择**前端归一化**(不动后端)。把 `openImportDialog` 改为自写 `httpRequest`:用 `xlsx` 读取 Excel → 把日期列(开始日期/结束日期/开票日期)`2026-9-1` 归一为 `2026-09-01` → 重写成新 File 再交给 `handleImportExcel` 上传;复用其失败明细下载与成功刷新逻辑。无日期列时回退为原文件(行为不变)。
- 关键方法:`normalizeExcelDates` / `readExcelRows` / `writeExcelFile` / `normalizeDateString`(正则 `^(\d{4})[-/.年](\d{1,2})[-/.月](\d{1,2})日?$`,用 `new Date` 校验合法性后补零;非法/已标准格式返回 null 保持原值)。
- 校验:本机 devlocalhost:2889)待用户部署自测。注意所有单元格经 `sheet_to_json(raw:false)` 后均为字符串,与 transport-plan-import 的客户端解析模式一致。
## 车/船务模块导出 xlsx「创建时间/更新时间」为空(后端 tms-api 修复)
- 现象:`/vehicle/insurance-record` 批量导出的 xlsx 里「创建时间」「更新时间」两列空白,「更新人」有值。用户要求车/船务模块所有页面统一修。
- 定位:导出由**后端**生成(前端只传查询参数,`exportColumns` 参数后端未使用)。实测 `~/Downloads/保险记录2026-09-17 20_46_08.xlsx`K/M 列单元格无 `<v>` 节点(值 null),E/F/J 日期列是数值 46266.0(带 numFmt `yyyy-MM-dd`WPS 显示为日期)。
- 根因:Service 用 BladeX `org.springblade.core.tool.utils.BeanUtil`**继承 Spring `BeanUtils`**)做 `copyProperties`。实体 `TenantEntity.createTime/updateTime``java.util.Date`,导出类字段是 `java.time.LocalDateTime` → Spring BeanUtils **类型不兼容静默跳过**,值为 null。而「更新人」是手动 `UserCache.getUserRealName(...)` 赋值的,所以有值。(Hutool 的 BeanUtil 能转 Date→LocalDateTime,但本项目用的是 BladeX 版本,不能。)
- 佐证:项目里正常的导出(Waybill / LoadingManage / CustomerArchive / CommonCargo)时间字段一律用 `java.util.Date`,并在 Service 里手动 `excel.setCreateTime(record.getCreateTime())`
- 修复(后端仓库 `/Users/gxwebsoft/JAVA/tms-api`blade-transport 模块):在 13 个导出方法里补显式赋值(Date→LocalDateTime 用 BladeX `DateUtil.fromDate``Func.isEmpty` 判空),不改 Excel 类字段类型(避免影响自定义 converter 与导入模板)。
```java
excel.setCreateTime(Func.isEmpty(x.getCreateTime()) ? null : DateUtil.fromDate(x.getCreateTime()));
excel.setUpdateTime(Func.isEmpty(x.getUpdateTime()) ? null : DateUtil.fromDate(x.getUpdateTime()));
```
- 涉及文件(13 个 Service + 1 新建 Excel 类 + 设备台账 controller/接口):InsuranceRecord / ViolationRecord / MaintenanceRecord / MaintenancePlan / TireReplacementRecord / AccidentRecord / AnnualInspectionRecord / MileageRecord / TransportChangeRecord / EtcRecord / OilElectricRecord / OtherExpenseRecord / EquipmentLedger。
- 设备台账特殊:原 `EquipmentLedgerExcel` 根本没有审计列(前端列表有),新建 `EquipmentLedgerExportExcel extends EquipmentLedgerExcel`(创建时间/更新人/更新时间),导出链路改用新类,**导入模板仍用旧类不受影响**。
- 未验证:本机无 mvn(仅 IDEA 内置),且离线模式缺 `blade-bom` 无法编译;用 javap 确认 `DateUtil.fromDate(Date)` 存在 + 逐行 grep 复核代替。需用户在 IDEA 里编译并重新部署后自测。
- 同类隐患(本次未改,其他模块):TemporaryCreditLimit、ProcessConfig、CommonRoute、CommonAddress、ContractManage、ProjectApply、ShippingTemplate 的导出 Excel 也是 LocalDateTime 且未手动 set 时间。
## 保险记录保额 -1 问题排查(未结案,待用户验证 DB 环境)
- 症状:新增弹窗保额不填 → 再开编辑弹窗显示 -1,触发「不能小于 0」校验。
- 已排除:前端(源码/dist 构建/git 全历史)、后端 tms-api + tms-erp-api-ws(源码/编译产物 javap/git 历史)均无任何 -1 赋值逻辑;保额为 formslot el-input,空值传 ''。
- 关键链路:编辑弹窗 beforeOpen 走 `/detail` 接口(getOne 原生查询),**不经过**列表 SQL 的 `CASE WHEN insured_amount<0 THEN 0` 兜底——所以表格显示 0、弹窗显示原始值。
- 数据库截图(用户 Navicat):该行 insured_amount=NULL,全表无负数 → 说明用户浏览的库与后端实际连接的库**不是同一个/DDL 不一致**。系统存在「空数值=-1」惯例(MaintenanceRecordMapper 里程 `CASE WHEN mileage=-1 THEN NULL`;前端 waybill-manage.js/process-config.js 均有 `Number(v)===-1?'':v` 掩码)→ 后端真实库的 insured_amount 列默认值很可能是 -1,MP 插入排除 null 列 → 默认值 -1 入库。
- 待验证:在后端 Nacos 数据源指向的库执行 `SHOW CREATE TABLE blade_insurance_record` + `SELECT insured_amount FROM blade_insurance_record WHERE policy_no='11111' AND vehicle_no='沪AE31312'`。
- 修复方案(待确认):1) ALTER 列默认值改 NULL + UPDATE 存量负数为 NULL2) 前端 beforeOpen 对 insuredAmount/premium 做 null/-1 → '' 归一(参照 waybill-manage normalizeNumericDisplayValue);3) 列表 SQL 的 CASE 兜底与 detail 不一致,可顺手统一。