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

10 KiB
Raw Permalink Blame History

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/detailname 配载单详情,meta.keepAlive:false, activeMenu:'/business/loading-manage'),组件仍是 loading-manage.vue
    2. src/views/business/loading-manage.vue
      • computed 新增 isStandaloneDetailPagepath==='/business/loading-manage/detail')、isStandalonePageform|detail 并集,作为隐藏列表容器的统一开关)、detailPageTitleformPageDefaultTitleadd/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/reassignopenLoadingDialog 对 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.vueopenLoadingDetail/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"> 顶层写 // 注释会让该样式模块编译 500Unexpected '/'. 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 === falsestatusName === '未打卡' 直接返回 null(防止后端返回计划时间造成误序);优先 this.$dayjs(text).valueOf(),失败兜底 new Date(text.replace(/-/g,'/'))(兼容 Safari)。
    3. 模板 el-timelinev-for 改用 orderedWaybillPunchRecordskeyrecord.nodeCode || record.id || index 改为 ${nodeCode||id||'punch'}-${index},避免同节点多次打卡(在途)时 key 重复。
  • 校验:项目根目录临时脚本 _verify-sfc.mjs@vue/compiler-sfc parse + compileScript + compileTemplate)通过,已删除脚本。
  • 注意:getPunchRecordssrc/api/business/waybill-manage.js/punch-records)后端未提供节点排序字段,排序只能在前端做。

保险记录批量导入:前端归一化日期格式

  • 文件:src/views/vehicle/insurance-record.vue(仅此一个文件)
  • 背景:保险记录批量导入是后端驱动——前端 handleImportimportBlob 把原始 Excel 直接 POST 到 /blade-transport/insurance-record/import-insurance-record,前端不解析行。后端只认 2026-09-012026-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.xlsxK/M 列单元格无 <v> 节点(值 null),E/F/J 日期列是数值 46266.0(带 numFmt yyyy-MM-ddWPS 显示为日期)。
  • 根因:Service 用 BladeX org.springblade.core.tool.utils.BeanUtil继承 Spring BeanUtils)做 copyProperties。实体 TenantEntity.createTime/updateTimejava.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-apiblade-transport 模块):在 13 个导出方法里补显式赋值(Date→LocalDateTime 用 BladeX DateUtil.fromDateFunc.isEmpty 判空),不改 Excel 类字段类型(避免影响自定义 converter 与导入模板)。
    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 不一致,可顺手统一。