From 39f537d3dd0e9405b29217514997a0db31f98c6b Mon Sep 17 00:00:00 2001 From: zch Date: Tue, 28 Apr 2026 15:13:25 +0800 Subject: [PATCH 1/3] =?UTF-8?q?feat(=E8=BD=AE=E8=83=8E=E8=AF=A6=E6=83=85):?= =?UTF-8?q?=20=E6=96=B0=E5=A2=9EWeb=E8=AF=A6=E6=83=85=E6=8A=BD=E5=B1=89?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=E5=B9=B6=E4=BC=98=E5=8C=96=E8=BD=AE=E4=BD=8D?= =?UTF-8?q?=E8=A7=86=E5=9B=BE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 新增轮胎Web详情抽屉接口,复用PDA时间线结构并补充里程和花纹统计字段。重构车辆轮位视图为固定6个轮位展示最新维护数据,替代原维保前后对比方案。优化轮胎详情页增加总里程和当前花纹显示,完善装卸记录归属信息展示。调整生命周期抽屉交互,支持从轮位视图跳转维保工单页签。 - 新增selectTyreDetailForWeb接口聚合里程和花纹数据 - 重构轮位视图SQL和前端展示逻辑 - 优化轮胎详情页信息展示和交互 - 调整生命周期抽屉与父窗口页签联动 --- .../controller/tyre/BaseCarController.java | 6 +- .../controller/tyre/BaseTyreController.java | 4 +- .../resources/templates/tyre/car/car.html | 6 + .../templates/tyre/car/lifecycle.html | 80 +++++------ .../templates/tyre/tyre/typreDetill2.html | 63 +++++++-- .../domain/CarLatestMaintenanceDTO.java | 57 -------- .../mapper/BizOrderTireDetailMapper.java | 9 ++ .../service/IBaseCarLifecycleService.java | 8 +- .../system/service/IBaseTyreService.java | 8 ++ .../impl/BaseCarLifecycleServiceImpl.java | 100 +++++++------ .../service/impl/BaseTyreServiceImpl.java | 131 +++++++++++++++++- .../ruoyi/system/util/TyreLifecycleCalc.java | 36 ++++- .../mapper/tyre/BizOrderTireDetailMapper.xml | 29 +++- 13 files changed, 365 insertions(+), 172 deletions(-) delete mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLatestMaintenanceDTO.java diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseCarController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseCarController.java index ce519511..839b7d86 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseCarController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseCarController.java @@ -1,6 +1,7 @@ package com.ruoyi.web.controller.tyre; import java.util.List; +import java.util.Map; import com.ruoyi.common.utils.ShiroUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; @@ -13,7 +14,6 @@ import com.ruoyi.common.annotation.Log; import com.ruoyi.common.enums.BusinessType; import com.ruoyi.system.domain.BaseCar; import com.ruoyi.system.domain.CarCheckLifecycleDTO; -import com.ruoyi.system.domain.CarLatestMaintenanceDTO; import com.ruoyi.system.domain.CarLifecycleDTO; import com.ruoyi.system.domain.CarLifecycleQuery; import com.ruoyi.system.domain.CarMileageLifecycleDTO; @@ -206,14 +206,14 @@ public class BaseCarController extends BaseController } /** - * 查询车辆最近一次维保前后对比。 + * 查询车辆轮位最新维护数据。 */ @RequiresPermissions("system:car:view") @GetMapping("/lifecycle/{carNo}/latest-maintenance") @ResponseBody public AjaxResult latestMaintenance(@PathVariable("carNo") String carNo) { - CarLatestMaintenanceDTO latestMaintenance = baseCarLifecycleService.selectLatestMaintenance(buildLifecycleQuery(carNo)); + List latestMaintenance = baseCarLifecycleService.selectLatestWheelPositionMaintenance(buildLifecycleQuery(carNo)); return AjaxResult.success(latestMaintenance); } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseTyreController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseTyreController.java index 84136f6a..07a036e8 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseTyreController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseTyreController.java @@ -406,8 +406,8 @@ public class BaseTyreController extends BaseController return "error/404"; } - // 与 PDA 时间线接口保持同一个 service 返回结构;列表页传 tyreId,PDA 仍可传 keyParam。 - Map resultMap = baseTyreService.pdaQueryTyreTimeLine(baseTyre); + // Web 详情抽屉在 PDA 原时间线外补充里程/花纹统计,避免改动老 PDA 接口返回契约。 + Map resultMap = baseTyreService.selectTyreDetailForWeb(baseTyre); if (resultMap == null || resultMap.isEmpty()) { return "error/404"; } diff --git a/ruoyi-admin/src/main/resources/templates/tyre/car/car.html b/ruoyi-admin/src/main/resources/templates/tyre/car/car.html index 801f4f6b..0a55db13 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/car/car.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/car.html @@ -247,6 +247,12 @@ $("#lifecycleFrame").attr("src", "about:blank"); } + function openMaintenanceOrderTabFromLifecycle() { + // 子 iframe 不直接创建页签:由车辆列表页所在主 iframe 调用 RuoYi openTab,才能正确挂到后台页签容器。 + $.modal.openTab("维保工单列表", ctx + "tyre/order"); + closeLifecycleDrawer(); + } + function escapeHtml(value) { return String(value) .replace(/&/g, "&") diff --git a/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html index 991706b7..42228078 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html @@ -187,8 +187,8 @@ .compare-tyre-card { position: relative; - width: 66px; - min-height: 126px; + width: 90px; + min-height: 174px; padding: 24px 6px 8px; border-radius: 8px 8px 16px 16px; background: #2f4050; @@ -448,7 +448,7 @@
-
最近一次维保
+
轮位视图
正在加载...
@@ -456,12 +456,12 @@
- 保养信息 - 按时间倒序展示维保工单 + 保养信息 + 按时间倒序展示维保工单,点击记录打开维保工单列表页签
    @@ -472,11 +472,11 @@ diff --git a/ruoyi-admin/src/main/resources/templates/tyre/tyre/typreDetill2.html b/ruoyi-admin/src/main/resources/templates/tyre/tyre/typreDetill2.html index a57ffdf3..cf7843a9 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/tyre/typreDetill2.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/tyre/typreDetill2.html @@ -277,10 +277,13 @@
    + recordWarehousingList=${resultMap['recordWarehousingList']}, + recordTyreInstallList=${resultMap['recordTyreInstallList']}, + recordTyreMileageList=${resultMap['recordTyreMileageList']}, + totalMileage=${resultMap['totalMileage']}, + currentPatternDepth=${resultMap['currentPatternDepth']}, + bizMaintenanceOrder=${resultMap['bizMaintenanceOrder']}, + bizOrderTireDetailList=${resultMap['bizMaintenanceOrder'] == null ? null : resultMap['bizMaintenanceOrder'].bizOrderTireDetailList}">
    @@ -316,14 +319,24 @@
    轮胎花纹
    -
    -
    -
    轮胎类别
    -
    -
    -
    + + + +
    初始花纹深度
    -
    +
    +
    轮胎总行驶里程
    + +
    -
    +
    +
    +
    当前剩余花纹
    + +
    -
    +
    标准气压
    -
    @@ -374,6 +387,7 @@
    出入库记录:0 装卸车记录:0 + 里程使用记录:0 维保工单:0 维保轮胎明细:0
    @@ -392,6 +406,7 @@
    RFID:-
    品牌:-
    规格:-
    +
    入库场站:-
    备注:-
    @@ -415,13 +430,40 @@
    轮位:-
    里程:-
    花纹深度:-
    -
    车队:-
    + +
    + 修理厂:- + / 分公司:- + / 车队:- +
    备注:-
    +
    +
    里程使用记录
    +
      +
    • + +
      +
      单程行驶里程:-
      +
      -
      +
      +
      +
      卸下时间:-
      +
      该程行驶里程:-
      +
      本程剩余花纹:-
      +
      该程花纹磨损:-
      +
      记录人:-
      +
      记录时间:-
      +
      备注:-
      +
      +
    • +
    +
    +
    维保工单
      @@ -462,6 +504,7 @@
      完成操作人:-
      补充说明:-
      备注:-
      +
      如该工单涉及多条轮胎明细,请以维保工单详情页为完整明细来源。
      轮胎执行明细
      @@ -481,7 +524,7 @@
    -
    +
    暂无生命周期记录
    diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLatestMaintenanceDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLatestMaintenanceDTO.java deleted file mode 100644 index c1f04d55..00000000 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLatestMaintenanceDTO.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.ruoyi.system.domain; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.List; -import java.util.Map; - -/** - * 车辆最近一次维保对比DTO。 - *

    - * 用于车辆生命周期抽屉展示最近一条维保工单的“维保前/维保后”轮位快照。 - * 明细直接复用工单详情页既有 Map 结构,避免新建一套字段口径。 - *

    - */ -public class CarLatestMaintenanceDTO implements Serializable -{ - private static final long serialVersionUID = 1L; - - /** 最近一次维保工单概要;车辆无维保记录时为空。 */ - private CarMaintenanceLifecycleDTO order; - - /** 维保前轮胎布局,字段同 BizOrderTireDetailMapper.selectBaseTrieInstall / selectBizOrderTireDetail。 */ - private List tireDetailsBefore = new ArrayList<>(); - - /** 维保后轮胎布局,字段同 BizOrderTireDetailMapper.selectBizOrderTireDetail。 */ - private List tireDetailsAfter = new ArrayList<>(); - - public CarMaintenanceLifecycleDTO getOrder() - { - return order; - } - - public void setOrder(CarMaintenanceLifecycleDTO order) - { - this.order = order; - } - - public List getTireDetailsBefore() - { - return tireDetailsBefore; - } - - public void setTireDetailsBefore(List tireDetailsBefore) - { - this.tireDetailsBefore = tireDetailsBefore; - } - - public List getTireDetailsAfter() - { - return tireDetailsAfter; - } - - public void setTireDetailsAfter(List tireDetailsAfter) - { - this.tireDetailsAfter = tireDetailsAfter; - } -} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BizOrderTireDetailMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BizOrderTireDetailMapper.java index 7276ffa2..69926499 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BizOrderTireDetailMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BizOrderTireDetailMapper.java @@ -4,6 +4,7 @@ import java.util.List; import java.util.Map; import com.ruoyi.system.domain.BizOrderTireDetail; +import org.apache.ibatis.annotations.Param; /** * 工单轮胎执行明细Mapper接口 @@ -64,4 +65,12 @@ public interface BizOrderTireDetailMapper List selectBizOrderTireDetail(BizOrderTireDetail bizOrderTireDetail); List selectBaseTrieInstall(String plateNumber); + + /** + * 查询车辆全部维保轮胎明细,Service 层按轮位截取最新一条。 + * + * @param plateNumber 车牌号 + * @return 车辆维保轮胎明细列表 + */ + List selectCarMaintenanceTireDetails(@Param("plateNumber") String plateNumber); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseCarLifecycleService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseCarLifecycleService.java index b6533a08..9ded12d5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseCarLifecycleService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseCarLifecycleService.java @@ -1,8 +1,8 @@ package com.ruoyi.system.service; import java.util.List; +import java.util.Map; import com.ruoyi.system.domain.CarCheckLifecycleDTO; -import com.ruoyi.system.domain.CarLatestMaintenanceDTO; import com.ruoyi.system.domain.CarLifecycleDTO; import com.ruoyi.system.domain.CarLifecycleQuery; import com.ruoyi.system.domain.CarMileageLifecycleDTO; @@ -46,10 +46,10 @@ public interface IBaseCarLifecycleService public List selectMileageList(CarLifecycleQuery query); /** - * 查询车辆最近一次维保工单的维保前后轮胎对比。 + * 查询车辆 6 个轮位各自最新一条维护数据。 * * @param query 生命周期查询参数 - * @return 最近一次维保对比数据;无维保时返回空壳DTO + * @return 固定轮位维护数据列表 */ - public CarLatestMaintenanceDTO selectLatestMaintenance(CarLifecycleQuery query); + public List selectLatestWheelPositionMaintenance(CarLifecycleQuery query); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseTyreService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseTyreService.java index 4e6de736..7e3dd4cc 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseTyreService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseTyreService.java @@ -86,4 +86,12 @@ public interface IBaseTyreService Map pdaQueryTyreTimeLine(BaseTyre baseTyre); + + /** + * 查询 Web 详情抽屉数据。 + *

    + * 先复用 PDA 原时间线结构,再补充 Web 专用的里程/花纹统计字段,避免影响老 PDA 客户端。 + *

    + */ + Map selectTyreDetailForWeb(BaseTyre baseTyre); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseCarLifecycleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseCarLifecycleServiceImpl.java index 9c4aa11c..91ebb5f7 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseCarLifecycleServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseCarLifecycleServiceImpl.java @@ -1,15 +1,16 @@ package com.ruoyi.system.service.impl; import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashSet; +import java.util.LinkedHashMap; import java.util.List; import java.util.Map; +import java.util.Set; import com.ruoyi.common.annotation.DataScope; import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.StringUtils; -import com.ruoyi.system.domain.BizMaintenanceOrder; -import com.ruoyi.system.domain.BizOrderTireDetail; import com.ruoyi.system.domain.CarCheckLifecycleDTO; -import com.ruoyi.system.domain.CarLatestMaintenanceDTO; import com.ruoyi.system.domain.CarLifecycleDTO; import com.ruoyi.system.domain.CarLifecycleQuery; import com.ruoyi.system.domain.CarLifecycleSummaryDTO; @@ -17,7 +18,6 @@ import com.ruoyi.system.domain.CarMaintenanceLifecycleDTO; import com.ruoyi.system.domain.CarMileageLifecycleDTO; import com.ruoyi.system.domain.CarTyreInstallLifecycleDTO; import com.ruoyi.system.mapper.BaseCarLifecycleMapper; -import com.ruoyi.system.mapper.BizMaintenanceOrderMapper; import com.ruoyi.system.mapper.BizOrderTireDetailMapper; import com.ruoyi.system.service.IBaseCarLifecycleService; import org.springframework.beans.factory.annotation.Autowired; @@ -34,11 +34,13 @@ import org.springframework.stereotype.Service; @Service public class BaseCarLifecycleServiceImpl implements IBaseCarLifecycleService { - @Autowired - private BaseCarLifecycleMapper baseCarLifecycleMapper; + /** + * 生命周期轮位视图固定按 WheelPosition 字典的 6 个业务轮位展示。 + */ + private static final List WHEEL_POSITION_ORDER = Arrays.asList("左前轮", "右前轮", "右内轮", "右外轮", "左内轮", "左外轮"); @Autowired - private BizMaintenanceOrderMapper bizMaintenanceOrderMapper; + private BaseCarLifecycleMapper baseCarLifecycleMapper; @Autowired private BizOrderTireDetailMapper bizOrderTireDetailMapper; @@ -63,16 +65,27 @@ public class BaseCarLifecycleServiceImpl implements IBaseCarLifecycleService @DataScope(deptAlias = "d", userAlias = "u") public CarLifecycleDTO selectLifecycle(CarLifecycleQuery query) { + // 1. 校验权限并回填 carId,确保后续查询已授权且使用精确主键 CarLifecycleSummaryDTO car = buildAuthorizedCar(query); + // 2. 初始化生命周期 DTO 容器 CarLifecycleDTO dto = new CarLifecycleDTO(); + // 3. 写入车辆主档概要信息 dto.setCar(car); + // 4. 查询当前装车的轮胎列表 dto.setMountedTyres(baseCarLifecycleMapper.selectMountedTyres(query)); + // 5. 查询最近发生的事件时间线 dto.setRecentEvents(baseCarLifecycleMapper.selectRecentEvents(query)); + // 6. 查询维保工单历史列表 dto.setMaintenanceList(baseCarLifecycleMapper.selectMaintenanceList(query)); + // 7. 统计装卸记录总条数 dto.setInstallCount(baseCarLifecycleMapper.countInstallRecords(query)); + // 8. 统计维保工单总条数 dto.setMaintenanceCount(baseCarLifecycleMapper.countMaintenanceOrders(query)); + // 9. 统计质检记录总条数 dto.setCheckCount(baseCarLifecycleMapper.countCheckRecords(query)); + // 10. 统计里程记录总条数 dto.setMileageCount(baseCarLifecycleMapper.countMileageRecords(query)); + // 11. 返回聚合后的生命周期数据 return dto; } @@ -96,50 +109,51 @@ public class BaseCarLifecycleServiceImpl implements IBaseCarLifecycleService } /** - * 查询车辆最近一次维保的前后轮胎对比。 + * 查询车辆 6 个轮位各自最新一条维护数据。 *

    - * 先走 buildAuthorizedCar 统一权限闸口,再复用维保列表排序和工单详情页的轮胎明细SQL,避免重复造查询口径。 + * 轮位视图只服务车辆生命周期抽屉,不改维保工单详情页;SQL 拉取该车全部维保轮胎明细, + * Java 按固定轮位顺序截取每个轮位第一条,避免在 SQL 中使用 TOP / LIMIT / ROW_NUMBER 等方言差异写法。 *

    */ @Override @DataScope(deptAlias = "d", userAlias = "u") - public CarLatestMaintenanceDTO selectLatestMaintenance(CarLifecycleQuery query) + public List selectLatestWheelPositionMaintenance(CarLifecycleQuery query) { buildAuthorizedCar(query); - CarLatestMaintenanceDTO dto = new CarLatestMaintenanceDTO(); - List maintenanceList = baseCarLifecycleMapper.selectMaintenanceList(query); - if (maintenanceList == null || maintenanceList.isEmpty()) + List detailRows = bizOrderTireDetailMapper.selectCarMaintenanceTireDetails(query.getCarNo()); + Map latestByPosition = new LinkedHashMap<>(); + Set expectedPositions = new HashSet<>(WHEEL_POSITION_ORDER); + if (detailRows != null) { - return dto; - } - - CarMaintenanceLifecycleDTO latest = maintenanceList.get(0); - dto.setOrder(latest); - if (latest.getOrderId() != null) - { - BizOrderTireDetail afterQuery = new BizOrderTireDetail(); - afterQuery.setOrderId(latest.getOrderId()); - dto.setTireDetailsAfter(emptyIfNull(bizOrderTireDetailMapper.selectBizOrderTireDetail(afterQuery))); - } - - if (latest.getOrderId() != null && !StringUtils.isBlank(latest.getPlateNumber())) - { - BizMaintenanceOrder probe = new BizMaintenanceOrder(); - probe.setOrderId(latest.getOrderId()); - // 上一条工单SQL同时依赖 orderId 与 plateNumber,缺车牌会导致无法命中上一条记录。 - probe.setPlateNumber(latest.getPlateNumber()); - BizMaintenanceOrder previousOrder = bizMaintenanceOrderMapper.selectBizMaintenanceOrderByOrderIdBefore(probe); - if (previousOrder != null && previousOrder.getOrderId() != null) + for (Map row : detailRows) { - BizOrderTireDetail beforeQuery = new BizOrderTireDetail(); - beforeQuery.setOrderId(previousOrder.getOrderId()); - dto.setTireDetailsBefore(emptyIfNull(bizOrderTireDetailMapper.selectBizOrderTireDetail(beforeQuery))); - return dto; + String position = row == null || row.get("position") == null ? null : String.valueOf(row.get("position")); + if (!expectedPositions.contains(position) || latestByPosition.containsKey(position)) + { + continue; + } + latestByPosition.put(position, row); } } - dto.setTireDetailsBefore(emptyIfNull(bizOrderTireDetailMapper.selectBaseTrieInstall(latest.getPlateNumber()))); - return dto; + List result = new ArrayList<>(); + for (String position : WHEEL_POSITION_ORDER) + { + Map row = latestByPosition.get(position); + if (row == null) + { + row = new LinkedHashMap(); + row.put("position", position); + row.put("status", "empty"); + } + else if (row.get("status") == null) + { + // 维保后视图只关心该轮位最后一次维护快照;状态为空按普通维护数据展示。 + row.put("status", "normal"); + } + result.add(row); + } + return result; } /** @@ -223,21 +237,21 @@ public class BaseCarLifecycleServiceImpl implements IBaseCarLifecycleService */ private void validateQuery(CarLifecycleQuery query) { + // 1. 校验查询对象和车牌号不能为空 if (query == null || StringUtils.isBlank(query.getCarNo())) { throw new ServiceException("车牌号不能为空"); } + // 2. 去除车牌号前后空格,规范化输入 String carNo = query.getCarNo().trim(); + // 3. 校验车牌号长度不超过数据库字段定义(varchar(50)) if (carNo.length() > 50) { // base_car.car_no 当前按 varchar(50) 设计,超长路径参数直接拒绝更利于定位异常调用。 throw new ServiceException("车牌号长度超过限制"); } + // 4. 将规范化后的车牌号写回查询对象,供后续SQL使用 query.setCarNo(carNo); } - private List emptyIfNull(List list) - { - return list == null ? new ArrayList<>() : list; - } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseTyreServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseTyreServiceImpl.java index c4ec6e0b..4e01403f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseTyreServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseTyreServiceImpl.java @@ -18,18 +18,15 @@ import com.ruoyi.system.mapper.BaseTyreMapper; import com.ruoyi.system.mapper.RecordTyreInstallMapper; import com.ruoyi.system.mapper.RecordWarehousingMapper; import com.ruoyi.system.service.IBaseTyreService; -import com.sun.jna.platform.mac.SystemB; +import com.ruoyi.system.util.TyreLifecycleCalc; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; +import java.math.BigDecimal; +import java.util.*; import java.util.stream.Collectors; import static com.ruoyi.common.utils.ShiroUtils.getLoginName; @@ -57,6 +54,10 @@ public class BaseTyreServiceImpl implements IBaseTyreService @Autowired private BizMaintenanceOrderMapper bizMaintenanceOrderMapper; private static final Logger log = LoggerFactory.getLogger(BaseTyreServiceImpl.class); + + @Autowired + private RecordTyreMileageMapper recordTyreMileageMapper; + /** * 查询轮胎基础信息 * @@ -304,4 +305,122 @@ public class BaseTyreServiceImpl implements IBaseTyreService return map; } } + + @Override + public Map selectTyreDetailForWeb(BaseTyre baseTyre) + { + // 1. 调用 PDA 查询方法获取轮胎时间线基础数据(包含入库、安装等流转记录) + Map map = pdaQueryTyreTimeLine(baseTyre); + // 2. 若基础数据为空,直接返回,避免后续空指针异常 + if (map == null || map.isEmpty()) + { + return map; + } + + // 3. 初始化里程相关字段默认值,确保返回结构完整 + map.put("recordTyreMileageList", new ArrayList<>()); + map.put("totalMileage", null); + map.put("currentPatternDepth", null); + + // 4. 获取轮胎基础信息对象,并校验类型正确性 + Object resultBaseObj = map.get("resultBase"); + if (!(resultBaseObj instanceof BaseTyre)) + { + return map; + } + + // 5. 提取轮胎实体和 RFID(EPC)编码 + BaseTyre resultBase = (BaseTyre) resultBaseObj; + String tyreRfid = resultBase.getTyreEpc(); + // 6. RFID 为空时清空流转列表并返回,避免展示错误数据 + if (StringUtils.isBlank(tyreRfid)) + { + // 原 PDA 方法历史上会在 EPC 为空时按空条件查流转表;Web 详情必须置空,避免误把全量历史展示给用户。 + map.put("recordWarehousingList", new ArrayList<>()); + map.put("recordTyreInstallList", new ArrayList<>()); + return map; + } + + // 7. 转换安装记录列表并计算当前花纹深度 + List installList = castInstallList(map.get("recordTyreInstallList")); + map.put("currentPatternDepth", TyreLifecycleCalc.currentPatternDepth(installList)); + + // 8. 构造里程查询对象并执行查询 + RecordTyreMileage query = new RecordTyreMileage(); + query.setTyreRfid(tyreRfid); + List mileageList = recordTyreMileageMapper.selectRecordTyreMileageList(query); + // 9. 若无里程记录,直接返回当前已组装的数据 + if (mileageList == null || mileageList.isEmpty()) + { + return map; + } + + // 10. 解析初始花纹深度,并计算各段磨损量 + BigDecimal initialDepth = TyreLifecycleCalc.parseDepth(resultBase.getPatternDepth()); + Map wearMap = TyreLifecycleCalc.computeSegmentWears(initialDepth, mileageList); + // 11. 初始化总里程累加器和标志位 + BigDecimal totalMileage = BigDecimal.ZERO; + boolean hasMileage = false; + + // 12. 按开始时间降序、ID 降序对里程记录排序,确保时间线正确 + mileageList.sort(Comparator + .comparing(RecordTyreMileage::getStartTime, Comparator.nullsLast(Comparator.reverseOrder())) + .thenComparing(RecordTyreMileage::getId, Comparator.nullsLast(Comparator.reverseOrder()))); + + // 13. 遍历里程记录,构造前端展示用的 VO 列表 + List> mileageVoList = new ArrayList<>(mileageList.size()); + for (RecordTyreMileage item : mileageList) + { + Map vo = new HashMap<>(); + vo.put("id", item.getId()); // 记录主键 + vo.put("tyreRfid", item.getTyreRfid()); // 轮胎 RFID + vo.put("startTime", item.getStartTime()); // 里程开始时间 + vo.put("endTime", item.getEndTime()); // 里程结束时间 + vo.put("mileage", item.getMileage()); // 行驶里程数 + vo.put("patternDepth", item.getPatternDepth()); // 当时花纹深度 + vo.put("createBy", item.getCreateBy()); // 创建人 + vo.put("createTime", item.getCreateTime()); // 创建时间 + vo.put("updateBy", item.getUpdateBy()); // 更新人 + vo.put("updateTime", item.getUpdateTime()); // 更新时间 + vo.put("remark", item.getRemark()); // 备注信息 + vo.put("tyreBrand", item.getTyreBrand()); // 轮胎品牌 + vo.put("tyreNo", item.getTyreNo()); // 轮胎编号 + vo.put("wearDepth", item.getId() == null ? null : wearMap.get(item.getId())); // 磨损深度(从计算结果取) + // 14. 累加有效里程值(mileage 为 Long 类型,表示该段 km 差值) + if (item.getMileage() != null) + { + // mileage 实体类型是 Long,表示该程 km 差值,直接累加可避免 varchar 花纹解析逻辑误入里程路径。 + totalMileage = totalMileage.add(BigDecimal.valueOf(item.getMileage())); + hasMileage = true; + } + mileageVoList.add(vo); + } + + // 15. 将组装好的里程列表和总里程写入返回 Map + map.put("recordTyreMileageList", mileageVoList); + map.put("totalMileage", hasMileage ? totalMileage.stripTrailingZeros().toPlainString() : null); + // 16. 返回完整的轮胎详情数据 + return map; + } + + private List castInstallList(Object value) + { + // 1. 初始化空结果列表,用于存放转换后的安装记录 + List result = new ArrayList<>(); + // 2. 校验入参是否为 List 类型,若不是则直接返回空列表 + if (!(value instanceof List)) + { + return result; + } + // 3. 遍历列表,筛选出 RecordTyreInstall 类型的元素并加入结果 + for (Object item : (List) value) + { + if (item instanceof RecordTyreInstall) + { + result.add((RecordTyreInstall) item); + } + } + // 4. 返回类型安全的安装记录列表 + return result; + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/util/TyreLifecycleCalc.java b/ruoyi-system/src/main/java/com/ruoyi/system/util/TyreLifecycleCalc.java index ae5f5778..55ac3fe7 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/util/TyreLifecycleCalc.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/util/TyreLifecycleCalc.java @@ -24,6 +24,7 @@ public final class TyreLifecycleCalc private TyreLifecycleCalc() { + // 私有构造器,禁止外部实例化,工具类保持静态方法调用 } /** @@ -34,22 +35,28 @@ public final class TyreLifecycleCalc */ public static String currentPatternDepth(List installRecords) { + // 1. 空列表校验,无记录时返回 null if (installRecords == null || installRecords.isEmpty()) { return null; } + // 2. 初始化最新记录变量 RecordTyreInstall latest = null; + // 3. 遍历所有装卸记录,寻找最新一条有效花纹深度 for (RecordTyreInstall item : installRecords) { + // 跳过空对象或无花纹深度的记录 if (item == null || isBlank(item.getPatternDepth())) { continue; } + // 4. 比较时间先后,保留更晚的记录 if (latest == null || after(item, latest)) { latest = item; } } + // 5. 返回最新记录的花纹深度,去除前后空格 return latest == null ? null : latest.getPatternDepth().trim(); } @@ -63,12 +70,15 @@ public final class TyreLifecycleCalc public static Map computeSegmentWears(BigDecimal initialDepth, List mileageList) { + // 1. 初始化磨损结果 Map,用于存储每条记录的磨损值 Map wearMap = new HashMap<>(); + // 2. 空列表校验,直接返回空 Map if (mileageList == null || mileageList.isEmpty()) { return wearMap; } + // 3. 过滤掉空对象,构建待排序列表 List sortedList = new ArrayList<>(); for (RecordTyreMileage item : mileageList) { @@ -77,29 +87,37 @@ public final class TyreLifecycleCalc sortedList.add(item); } } + // 4. 按开始时间升序、ID 升序排序,确保时间线正确 sortedList.sort(Comparator .comparing(RecordTyreMileage::getStartTime, Comparator.nullsLast(Comparator.naturalOrder())) .thenComparing(RecordTyreMileage::getId, Comparator.nullsLast(Comparator.naturalOrder()))); + // 5. 初始化前一段花纹深度为初始深度 BigDecimal previousDepth = initialDepth; + // 6. 遍历排序后的里程记录,逐段计算磨损 for (RecordTyreMileage item : sortedList) { + // 解析当前记录的花纹深度 BigDecimal currentDepth = parseDepth(item.getPatternDepth()); String wearDepth = null; + // 7. 若前后深度均有效,计算差值作为本段磨损 if (previousDepth != null && currentDepth != null) { wearDepth = formatDecimal(previousDepth.subtract(currentDepth)); } + // 8. 将磨损值存入 Map,以记录 ID 为键 if (item.getId() != null) { wearMap.put(item.getId(), wearDepth); } + // 9. 更新前一段深度为当前深度(脏数据不更新,避免污染后续计算) if (currentDepth != null) { // 当前段脏数据不更新 prev,避免一条坏花纹深度污染后续所有段。 previousDepth = currentDepth; } } + // 10. 返回各段磨损值映射 return wearMap; } @@ -112,17 +130,21 @@ public final class TyreLifecycleCalc */ public static BigDecimal parseDepth(String value) { + // 1. 空值校验,空白字符串直接返回 null if (isBlank(value)) { return null; } + // 2. 去除前后空格,规范化输入 String trimmed = value.trim(); try { + // 3. 尝试将字符串解析为 BigDecimal return new BigDecimal(trimmed); } catch (NumberFormatException ex) { + // 4. 解析失败时记录警告日志,返回 null 避免异常传播 log.warn("轮胎花纹深度无法解析,已按空值处理:{}", trimmed); return null; } @@ -136,56 +158,68 @@ public final class TyreLifecycleCalc */ public static BigDecimal sumMileage(List mileageList) { + // 1. 空列表校验,直接返回 null if (mileageList == null || mileageList.isEmpty()) { return null; } + // 2. 初始化累加器和有效数据标志 BigDecimal total = BigDecimal.ZERO; boolean hasMileage = false; + // 3. 遍历里程记录,累加有效里程值 for (RecordTyreMileage item : mileageList) { + // 跳过空对象和空里程值,仅累加有效数据 if (item != null && item.getMileage() != null) { total = total.add(BigDecimal.valueOf(item.getMileage())); hasMileage = true; } } + // 4. 返回累加结果,无有效数据时返回 null return hasMileage ? total : null; } private static boolean after(RecordTyreInstall left, RecordTyreInstall right) { + // 1. 优先比较创建时间,两者均不为空时按时间先后判断 if (left.getCreateTime() != null && right.getCreateTime() != null) { int compare = left.getCreateTime().compareTo(right.getCreateTime()); if (compare != 0) { - return compare > 0; + return compare > 0; // 大于 0 表示 left 时间更晚 } } + // 2. 仅 left 有创建时间,说明 left 更晚 else if (left.getCreateTime() != null) { return true; } + // 3. 仅 right 有创建时间,说明 right 更晚 else if (right.getCreateTime() != null) { return false; } + // 4. 创建时间相同或无创建时间时,比较 ID 作为兜底,ID 大者视为更晚 if (left.getId() != null && right.getId() != null) { return left.getId().compareTo(right.getId()) > 0; } + // 5. 仅 left 有 ID 时,left 视为更晚 return left.getId() != null && right.getId() == null; } private static String formatDecimal(BigDecimal value) { + // 空值直接返回 null,非空时去除末尾零并转为纯文本字符串(避免科学计数法) return value == null ? null : value.stripTrailingZeros().toPlainString(); } private static boolean isBlank(String value) { + // 校验字符串是否为 null 或去除空格后为空 return value == null || value.trim().isEmpty(); } } diff --git a/ruoyi-system/src/main/resources/mapper/tyre/BizOrderTireDetailMapper.xml b/ruoyi-system/src/main/resources/mapper/tyre/BizOrderTireDetailMapper.xml index f494ec87..79f05729 100644 --- a/ruoyi-system/src/main/resources/mapper/tyre/BizOrderTireDetailMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/tyre/BizOrderTireDetailMapper.xml @@ -140,4 +140,31 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" - \ No newline at end of file + + + + + + + + From 29c115b2a16f95968522f95faa505bd87fceff73 Mon Sep 17 00:00:00 2001 From: zch Date: Tue, 28 Apr 2026 15:24:10 +0800 Subject: [PATCH 2/3] =?UTF-8?q?change(=E8=BD=A6=E8=BE=86=E5=85=A8=E7=94=9F?= =?UTF-8?q?=E5=91=BD=E5=91=A8=E6=9C=9F):=20=E6=9B=B4=E6=96=B0=E8=BD=A6?= =?UTF-8?q?=E8=BE=86=E8=AF=A6=E6=83=85=E6=A0=87=E9=A2=98=E6=96=87=E6=A1=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-admin/src/main/resources/templates/tyre/car/car.html | 4 ++-- .../src/main/resources/templates/tyre/car/lifecycle.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/ruoyi-admin/src/main/resources/templates/tyre/car/car.html b/ruoyi-admin/src/main/resources/templates/tyre/car/car.html index 0a55db13..8d777c19 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/car/car.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/car.html @@ -152,7 +152,7 @@
    -
    车辆全生命周期
    +
    车辆详情
    @@ -234,7 +234,7 @@ $.modal.alertWarning("车牌号为空,无法查看生命周期报表"); return; } - $("#lifecycleDrawerTitle").text("车辆全生命周期 - " + carNo); + $("#lifecycleDrawerTitle").text("车辆详情 - " + carNo); $("#lifecycleFrame").attr("src", prefix + "/lifecycle/view/" + encodeURIComponent(carNo)); $("#lifecycleDrawerMask").show(); $("#lifecycleDrawer").addClass("open"); diff --git a/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html index 42228078..4c0ebd18 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html @@ -1,7 +1,7 @@ - +