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 51149ba5..06765bc9 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 @@ -12,6 +12,13 @@ import org.springframework.web.bind.annotation.*; 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.CarLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleQuery; +import com.ruoyi.system.domain.CarMaintenanceLifecycleDTO; +import com.ruoyi.system.domain.CarMileageLifecycleDTO; +import com.ruoyi.system.domain.CarTyreInstallLifecycleDTO; +import com.ruoyi.system.service.IBaseCarLifecycleService; import com.ruoyi.system.service.IBaseCarService; import com.ruoyi.common.core.controller.BaseController; import com.ruoyi.common.core.domain.AjaxResult; @@ -34,6 +41,9 @@ public class BaseCarController extends BaseController @Autowired private IBaseCarService baseCarService; + @Autowired + private IBaseCarLifecycleService baseCarLifecycleService; + @RequiresPermissions("system:car:view") @GetMapping() public String car() @@ -169,4 +179,91 @@ public class BaseCarController extends BaseController return baseCarService.queryCarByRfid(baseCar); } + + + /** + * 车辆全生命周期报表页面 + */ + @RequiresPermissions("system:car:view") + @GetMapping("/lifecycle/view/{carNo}") + public String lifecycleView(@PathVariable("carNo") String carNo, ModelMap mmap) + { + // 弹窗页面只保存车牌入口,明细统一由后端授权后的接口加载。 + mmap.put("carNo", carNo); + return prefix + "/lifecycle"; + } + + /** + * 查询车辆全生命周期概要 + */ + @RequiresPermissions("system:car:view") + @GetMapping("/lifecycle/{carNo}") + @ResponseBody + public AjaxResult lifecycle(@PathVariable("carNo") String carNo) + { + CarLifecycleDTO lifecycle = baseCarLifecycleService.selectLifecycle(buildLifecycleQuery(carNo)); + return AjaxResult.success(lifecycle); + } + + /** + * 查询车辆装卸历史 + */ + @RequiresPermissions("system:car:view") + @PostMapping("/lifecycle/{carNo}/install/list") + @ResponseBody + public TableDataInfo lifecycleInstallList(@PathVariable("carNo") String carNo) + { + startPage(); + List list = baseCarLifecycleService.selectInstallList(buildLifecycleQuery(carNo)); + return getDataTable(list); + } + + /** + * 查询车辆维保工单历史 + */ + @RequiresPermissions("system:car:view") + @PostMapping("/lifecycle/{carNo}/maintenance/list") + @ResponseBody + public TableDataInfo lifecycleMaintenanceList(@PathVariable("carNo") String carNo) + { + startPage(); + List list = baseCarLifecycleService.selectMaintenanceList(buildLifecycleQuery(carNo)); + return getDataTable(list); + } + + /** + * 查询车辆关联轮胎质检历史 + */ + @RequiresPermissions("system:car:view") + @PostMapping("/lifecycle/{carNo}/check/list") + @ResponseBody + public TableDataInfo lifecycleCheckList(@PathVariable("carNo") String carNo) + { + startPage(); + List list = baseCarLifecycleService.selectCheckList(buildLifecycleQuery(carNo)); + return getDataTable(list); + } + + /** + * 查询车辆关联轮胎里程历史 + */ + @RequiresPermissions("system:car:view") + @PostMapping("/lifecycle/{carNo}/mileage/list") + @ResponseBody + public TableDataInfo lifecycleMileageList(@PathVariable("carNo") String carNo) + { + startPage(); + List list = baseCarLifecycleService.selectMileageList(buildLifecycleQuery(carNo)); + return getDataTable(list); + } + + private CarLifecycleQuery buildLifecycleQuery(String carNo) + { + CarLifecycleQuery query = new CarLifecycleQuery(); + // DataScope 依赖 BaseEntity 入参承接 params.dataScope,因此 Controller 统一构造查询对象。 + query.setCarNo(carNo); + return query; + } + + } diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseInventoryController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseInventoryController.java index f287f8c9..4e74141a 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseInventoryController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tyre/BaseInventoryController.java @@ -6,9 +6,11 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.page.TableDataInfo; import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.BaseInventory; import com.ruoyi.system.domain.BaseTyre; +import com.ruoyi.system.domain.vo.InboundBatchPreviewVo; import com.ruoyi.system.service.IBaseInventoryService; import org.apache.shiro.authz.annotation.RequiresPermissions; import org.springframework.beans.factory.annotation.Autowired; @@ -137,4 +139,64 @@ public class BaseInventoryController extends BaseController { return baseInventoryService.OutInventoryByPda(baseInventory,baseTyre); } + + /** + * 批量入库预览接口:按入库编码查询批次下的轮胎列表,并统计已入库 / 待入库数量。 + * + * @param inboundCode 入库编码 + * @return 批次预览结果 + */ + @RequiresPermissions("tyre:inventory:add") + @PostMapping("/batchInbound/preview") + @ResponseBody + public AjaxResult batchInboundPreview(@RequestParam("inboundCode") String inboundCode) + { + InboundBatchPreviewVo data = baseInventoryService.previewBatchByCode(inboundCode); + return AjaxResult.success("批次预览成功", data); + } + + /** + * 批量入库执行接口:按入库编码将批次内所有待入库轮胎写入库存,逐条独立事务保证失败隔离。 + * + * @param inboundCode 入库编码 + * @return 入库处理结果 + */ + @RequiresPermissions("tyre:inventory:add") + @Log(title = "轮胎批量入库", businessType = BusinessType.IMPORT) + @PostMapping("/batchInbound") + @ResponseBody + public AjaxResult batchInboundSave(@RequestParam("inboundCode") String inboundCode) + { + int rows = baseInventoryService.batchInboundByCode(inboundCode, ShiroUtils.getLoginName()); + return rows > 0 ? AjaxResult.success("批量入库完成,成功处理 " + rows + " 条", rows) : AjaxResult.error("批量入库失败或无可入库轮胎"); + } + + /** + * 批量入库撤回接口:按入库编码撤回批次入库,仅处理当前仍在库状态的记录。 + * + * @param inboundCode 入库编码 + * @return 撤回处理结果 + */ + @RequiresPermissions("tyre:inventory:add") + @Log(title = "轮胎批量入库撤回", businessType = BusinessType.UPDATE) + @PostMapping("/batchInbound/rollback") + @ResponseBody + public AjaxResult batchInboundRollback(@RequestParam("inboundCode") String inboundCode) + { + int rows = baseInventoryService.rollbackBatchInboundByCode(inboundCode, ShiroUtils.getLoginName()); + return rows > 0 ? AjaxResult.success("批量撤回完成,成功处理 " + rows + " 条", rows) : AjaxResult.error("批量撤回失败或无可撤回轮胎"); + } + + /** + * 批量入库页面路由:返回批量入库 Thymeleaf 模板视图名。 + * + * @return 模板路径 + */ + @RequiresPermissions("tyre:inventory:add") + @GetMapping("/batchInbound") + public String batchInbound() + { + return prefix + "/batchInbound"; + } + } 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 eb5b15e9..a9223211 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 @@ -12,6 +12,13 @@ import com.ruoyi.common.utils.ShiroUtils; import com.ruoyi.common.utils.poi.ExcelUtil; import com.ruoyi.system.domain.*; import com.ruoyi.system.domain.vo.BaseTyreVo; +import com.ruoyi.system.service.IBaseInventoryService; +import com.ruoyi.system.service.IBaseTyreService; +import com.ruoyi.system.service.IRecordCheckService; +import com.ruoyi.system.service.IRecordTyreInstallService; +import com.ruoyi.system.service.IRecordWarehousingService; +import com.ruoyi.system.service.ITyreStatDetailService; +import com.ruoyi.system.domain.vo.InboundBatchPreviewVo; import com.ruoyi.system.service.*; import org.apache.commons.lang3.StringUtils; import org.apache.shiro.authz.annotation.RequiresPermissions; @@ -53,6 +60,10 @@ public class BaseTyreController extends BaseController //“库存盘点详情”对话框和“轮胎详情”页签 @Autowired private ITyreStatDetailService tyreStatDetailService; + + @Autowired + private IBaseInventoryService baseInventoryService; + @Autowired private IBizOrderTireDetailService bizOrderTireDetailService; @Autowired @@ -72,8 +83,11 @@ public class BaseTyreController extends BaseController } /** - * 获取轮胎库存统计报表 + * 获取轮胎库存统计报表(模拟数据) */ + + + @GetMapping("/detail/{tyreId}") public String tyreDetil(@PathVariable("tyreId") Long tyreId, Model model) { @@ -113,12 +127,15 @@ public class BaseTyreController extends BaseController timelineItem.setColor("primary"); // 蓝色,代表进入 timelineItem.setTime(item.getCreateTime()); } + timelineItem.setType("warehousing"); timelineItem.setDetail("仓库:" + "轮胎仓库"); // 如果有仓库名称字段,可以替换 "轮胎仓库" + timelineItems.add(timelineItem); } } + // --- 2.2 查询并转换安装记录 --- RecordTyreInstall installQuery = new RecordTyreInstall(); installQuery.setTyreRfid(tyre.getTyreEpc()); @@ -137,27 +154,18 @@ public class BaseTyreController extends BaseController } } - //保养记录 - BizOrderTireDetail bizOrderTireDetail = new BizOrderTireDetail(); - bizOrderTireDetail.setTireId(tyre.getTyreId()); - List bizOrderTireDetailList = bizOrderTireDetailService.selectBizOrderTireDetailList(bizOrderTireDetail); - if (bizOrderTireDetailList != null) { - for (BizOrderTireDetail item : bizOrderTireDetailList) { - //查询质检单信息 - Long orderID = item.getOrderId(); - BizMaintenanceOrder bizMaintenanceOrder = iBizMaintenanceOrderService.selectBizMaintenanceOrderByOrderId(orderID); + // --- 2.3 查询并转换检查记录 --- + RecordCheck checkQuery = new RecordCheck(); + checkQuery.setTyreRfid(tyre.getTyreEpc()); + List checkList = recordCheckService.selectRecordCheckList(checkQuery); + if (checkList != null) { + for (RecordCheck item : checkList) { TimelineItem timelineItem = new TimelineItem(); - timelineItem.setId(item.getDetailId()); - timelineItem.setTitle("轮胎检查保养"+item.getCreateBy()); + timelineItem.setId(item.getId()); + timelineItem.setTitle("轮胎检查"+item.getCreateBy()); timelineItem.setType("check"); // timelineItem.setDetail(buildCheckDetail(item)); - timelineItem.setDetail("场站:" + bizMaintenanceOrder.getFactoryName()+ - "|车牌:"+bizMaintenanceOrder.getPlateNumber()+ - "|轮位:"+item.getPositionName()+ - "|花纹深度:"+item.getTreadDepth()+ - "|气压:"+item.getTirePress()+ - "|备注:"+item.getRemark() - ); + timelineItem.setDetail("深度:" + "17.8mm"); timelineItem.setTime(item.getCreateTime()); timelineItem.setIcon("fa-check-circle"); timelineItem.setColor("warning"); @@ -302,14 +310,6 @@ public class BaseTyreController extends BaseController return info; } - /** - * PDA查询轮胎生命周期数据 - * @param baseTyre - * @return - */ - - - @PostMapping("/setRfidBarcode") @ResponseBody public AjaxResult setRfidBarcode(@Validated BaseTyre baseTyre) @@ -500,6 +500,57 @@ public class BaseTyreController extends BaseController // 库存盘点链路统一切到新版详情模板,保留旧模板文件给其他场景继续观察或回退。 return prefix + "/typreDetill2"; } + + /** + * 收货弹窗页面入口 + */ + @RequiresPermissions("tyre:tyre:receive") + @GetMapping("/receive") + public String receive() + { + return prefix + "/receive"; + } + + /** + * 收货预览:按入库编码查询批次下的轮胎列表并统计已入库/待入库数量 + */ + @RequiresPermissions("tyre:tyre:receive") + @PostMapping("/receive/preview") + @ResponseBody + public AjaxResult receivePreview(@RequestParam("inboundCode") String inboundCode) + { + InboundBatchPreviewVo data = baseInventoryService.previewBatchByCode(inboundCode); + return AjaxResult.success("批次预览成功", data); + } + + /** + * 收货确认入库:按入库编码将批次内所有待入库轮胎一次性写入库存 + */ + @RequiresPermissions("tyre:tyre:receive") + @Log(title = "轮胎收货", businessType = BusinessType.IMPORT) + @PostMapping("/receive") + @ResponseBody + public AjaxResult receiveSubmit(@RequestParam("inboundCode") String inboundCode) + { + int rows = baseInventoryService.batchInboundByCode(inboundCode, ShiroUtils.getLoginName()); + return rows > 0 ? AjaxResult.success("收货完成,成功处理 " + rows + " 条", rows) + : AjaxResult.error("收货失败或无可入库轮胎"); + } + + /** + * 收货撤回:按入库编码撤回仍在库的轮胎(不提供页面入口,仅供管理员后端调用) + */ + @RequiresPermissions("tyre:tyre:receive") + @Log(title = "轮胎收货撤回", businessType = BusinessType.UPDATE) + @PostMapping("/receive/rollback") + @ResponseBody + public AjaxResult receiveRollback(@RequestParam("inboundCode") String inboundCode) + { + int rows = baseInventoryService.rollbackBatchInboundByCode(inboundCode, ShiroUtils.getLoginName()); + return rows > 0 ? AjaxResult.success("收货撤回完成,成功处理 " + rows + " 条", rows) + : AjaxResult.error("收货撤回失败或无可撤回轮胎"); + } + @PostMapping("/pdaQueryTyreTimeLine") @ResponseBody public AjaxResult pdaQueryTyreTimeLine(BaseTyre baseTyre) 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 73934429..801f4f6b 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/car/car.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/car.html @@ -2,6 +2,98 @@ +
@@ -57,6 +149,14 @@
+
+
+
+
车辆全生命周期
+ +
+ +
@@ -135,4 +272,4 @@ - \ No newline at end of file + diff --git a/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html new file mode 100644 index 00000000..5330e4b2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/tyre/car/lifecycle.html @@ -0,0 +1,594 @@ + + + + + + + +
+ + +
+
+
+
车辆:-
+
正在加载...
+
+
+
+
+ +
+
+
+
基本信息
+
+
+ +
+
当前装车轮胎
+
+
正在加载...
+
+
+
+ +
+
+
+ 生命周期时间轴 + 按时间倒序展示,包含装卸、维保、质检、里程记录 +
+
    + +
    +
    +
    +
    + + + + + diff --git a/ruoyi-admin/src/main/resources/templates/tyre/inventory/batchInbound.html b/ruoyi-admin/src/main/resources/templates/tyre/inventory/batchInbound.html new file mode 100644 index 00000000..0f6b6852 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/tyre/inventory/batchInbound.html @@ -0,0 +1,181 @@ + + + + + + + +
    +
    +
    +
    +
    + + +
    + +
    +
    + + +
    +
    + + + + diff --git a/ruoyi-admin/src/main/resources/templates/tyre/inventory/inventory.html b/ruoyi-admin/src/main/resources/templates/tyre/inventory/inventory.html index db030c94..19931038 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/inventory/inventory.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/inventory/inventory.html @@ -62,6 +62,9 @@ 导出 + + 批量入库 +
    @@ -154,6 +157,11 @@ $.table.init(options); }); + function openBatchInbound() { + // 批量入库归并在库存信息入口下,仍用独立页签承载预览/入库/撤回,避免挤占库存列表操作区。 + $.modal.openTab("轮胎批量入库", prefix + "/batchInbound"); + } + /* 用户管理-新增-选择部门树 */ function selectDeptTree() { var treeId = $("#treeId").val(); @@ -186,4 +194,4 @@ } - \ No newline at end of file + diff --git a/ruoyi-admin/src/main/resources/templates/tyre/tyre/receive.html b/ruoyi-admin/src/main/resources/templates/tyre/tyre/receive.html new file mode 100644 index 00000000..7f6eee43 --- /dev/null +++ b/ruoyi-admin/src/main/resources/templates/tyre/tyre/receive.html @@ -0,0 +1,115 @@ + + + + + + +
    +
    +
    +
    +
    + + +
    + 查询 +
    + + +
    +
    +
    + + + + diff --git a/ruoyi-admin/src/main/resources/templates/tyre/tyre/statDetail.html b/ruoyi-admin/src/main/resources/templates/tyre/tyre/statDetail.html index 8fbd0d22..f56ed5d6 100644 --- a/ruoyi-admin/src/main/resources/templates/tyre/tyre/statDetail.html +++ b/ruoyi-admin/src/main/resources/templates/tyre/tyre/statDetail.html @@ -76,6 +76,7 @@ - \ No newline at end of file + diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BaseTyre.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BaseTyre.java index ae569569..2b3b2074 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/BaseTyre.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/BaseTyre.java @@ -35,6 +35,10 @@ public class BaseTyre extends BaseEntity @Excel(name = "RFID标签") private String tyreEpc; + /** 入库编码 */ + @Excel(name = "入库编码", prompt = "第一行必填;后续空行继承最近一次出现的编码;中途填写新编码则从该行开始切换批次。") + private String inboundCode; + /** 轮胎品牌 */ @Excel(name = "轮胎品牌") private String tyreBrand; @@ -52,8 +56,6 @@ public class BaseTyre extends BaseEntity private String tyrePattern; @Excel(name = "轮胎初始深度") private String patternDepth; - @Excel(name = "标准气压") - private String pressure; @Excel(name = "轮胎沟槽数") private String grooves; /** 轮胎类别 */ @@ -76,6 +78,11 @@ public class BaseTyre extends BaseEntity @Excel(name = "所在轮位") private String wheelPostion; + /** + * 库存状态(字典 inventory_status)。 + * 约定:批量导入保持为空;空值在页面统一展示为“已发货待入库”,非空按字典翻译。 + */ + private String inventoryStatus; public String getPressure() { return pressure; } @@ -136,6 +143,15 @@ public class BaseTyre extends BaseEntity this.selfNo = selfNo; } + public String getInboundCode() { + return inboundCode; + } + + public void setInboundCode(String inboundCode) { + // 供应商 Excel 容易带前后空格,统一收口避免同一批次因空格拆成两个编码。 + this.inboundCode = inboundCode == null ? null : inboundCode.trim(); + } + public Long getDeptId() { return deptId; } @@ -160,6 +176,14 @@ public class BaseTyre extends BaseEntity this.wheelPostion = wheelPostion; } + public String getInventoryStatus() { + return inventoryStatus; + } + + public void setInventoryStatus(String inventoryStatus) { + this.inventoryStatus = inventoryStatus; + } + public void setTyreId(Long tyreId) { this.tyreId = tyreId; @@ -261,7 +285,9 @@ public class BaseTyre extends BaseEntity .append("tyreNo", getTyreNo()) .append("tyreEpc", getTyreEpc()) - + + .append("inboundCode", getInboundCode()) + .append("tyreBrand", getTyreBrand()) .append("tyreModel", getTyreModel()) @@ -275,7 +301,9 @@ public class BaseTyre extends BaseEntity .append("team", getTeam()) .append("deptName", getDeptName()) - + + .append("inventoryStatus", getInventoryStatus()) + .append("createBy", getCreateBy()) .append("createTime", getCreateTime()) diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarCheckLifecycleDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarCheckLifecycleDTO.java new file mode 100644 index 00000000..7596334a --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarCheckLifecycleDTO.java @@ -0,0 +1,146 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * 车辆生命周期关联轮胎质检记录DTO。 + *

    + * 用于“车辆全生命周期”弹窗中【巡检/质检记录】Tab页的数据展示。 + * 车辆与质检记录无直接外键,数据通过“该车曾装过的轮胎”间接关联 record_check 表获取。 + *

    + */ +public class CarCheckLifecycleDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 质检记录主键ID,对应 record_check.id。 */ + private Long id; + + /** 轮胎RFID编码,唯一标识一条轮胎实物。 */ + private String tyreRfid; + + /** 轮胎自编号(轮胎编号),业务展示用。 */ + private String tyreNo; + + /** 轮胎品牌,例如:米其林、普利司通等。 */ + private String tyreBrand; + + /** 轮胎规格型号,例如:295/80R22.5。 */ + private String tyreModel; + + /** 质检结果,例如:合格、不合格、建议更换等字典值。 */ + private String result; + + /** 质检时的维保类型/检测类型,例如:一级保养、二级保养、日常巡检。 */ + private String maintenanceType; + + /** 质检时记录的行驶里程(字符串形式保留原始录入值)。 */ + private String mileage; + + /** 质检时测量的花纹深度(毫米),用于评估轮胎磨损程度。 */ + private String patternDepth; + + /** 质检记录创建时间,即质检实际发生时间。 */ + private Date createTime; + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getTyreRfid() + { + return tyreRfid; + } + + public void setTyreRfid(String tyreRfid) + { + this.tyreRfid = tyreRfid; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } + + public String getResult() + { + return result; + } + + public void setResult(String result) + { + this.result = result; + } + + public String getMaintenanceType() + { + return maintenanceType; + } + + public void setMaintenanceType(String maintenanceType) + { + this.maintenanceType = maintenanceType; + } + + public String getMileage() + { + return mileage; + } + + public void setMileage(String mileage) + { + this.mileage = mileage; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleDTO.java new file mode 100644 index 00000000..d7787117 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleDTO.java @@ -0,0 +1,109 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; + +/** + * 车辆生命周期聚合报表DTO。 + *

    + * 作为车辆全生命周期弹窗“首屏”的统一返回对象,承载车辆概要、当前装车轮胎快照、 + * 最近事件时间线以及各维度记录总数量。各明细列表(装卸、维保、质检、里程) + * 通过独立分页接口按需加载,避免首屏返回数据量过大导致性能问题。 + *

    + */ +public class CarLifecycleDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 车辆主档概要,用于弹窗头部确认当前报表对象。包含车牌号、所属车队、线路、车型及最近录入里程。 */ + private CarLifecycleSummaryDTO car; + + /** 当前装车轮胎快照,数量较少(通常不超过车辆轮位数),随概要一次返回用于首屏快速展示。 */ + private List mountedTyres = new ArrayList<>(); + + /** 最近事件时间线,聚合装卸与维保两类关键事件,按时间倒序排列,用于快速定位最新动作。 */ + private List recentEvents = new ArrayList<>(); + + /** 该车辆历史轮胎装卸记录总条数,用于前端分页组件初始化总页数。 */ + private Integer installCount; + + /** 该车辆关联维保工单总条数,用于前端分页组件初始化总页数。 */ + private Integer maintenanceCount; + + /** 该车辆关联轮胎质检记录总条数,用于前端分页组件初始化总页数。 */ + private Integer checkCount; + + /** 该车辆关联轮胎里程记录总条数,用于前端分页组件初始化总页数。 */ + private Integer mileageCount; + + public CarLifecycleSummaryDTO getCar() + { + return car; + } + + public void setCar(CarLifecycleSummaryDTO car) + { + this.car = car; + } + + public List getMountedTyres() + { + return mountedTyres; + } + + public void setMountedTyres(List mountedTyres) + { + this.mountedTyres = mountedTyres; + } + + public List getRecentEvents() + { + return recentEvents; + } + + public void setRecentEvents(List recentEvents) + { + this.recentEvents = recentEvents; + } + + public Integer getInstallCount() + { + return installCount; + } + + public void setInstallCount(Integer installCount) + { + this.installCount = installCount; + } + + public Integer getMaintenanceCount() + { + return maintenanceCount; + } + + public void setMaintenanceCount(Integer maintenanceCount) + { + this.maintenanceCount = maintenanceCount; + } + + public Integer getCheckCount() + { + return checkCount; + } + + public void setCheckCount(Integer checkCount) + { + this.checkCount = checkCount; + } + + public Integer getMileageCount() + { + return mileageCount; + } + + public void setMileageCount(Integer mileageCount) + { + this.mileageCount = mileageCount; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleEventDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleEventDTO.java new file mode 100644 index 00000000..b26edae6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleEventDTO.java @@ -0,0 +1,304 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 车辆生命周期统一事件DTO。 + *

    + * 作为“最近事件时间线”的数据载体,将轮胎装卸事件与维保工单事件抽象为统一结构, + * 便于前端以同一套模板按时间轴展示。事件类型(eventType)区分数据来源: + * INSTALL 表示轮胎装卸动作,MAINTENANCE 表示维保工单动作。 + *

    + */ +public class CarLifecycleEventDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 事件类型字典值,区分数据来源。例如:INSTALL(轮胎装卸)、MAINTENANCE(维保工单)。 */ + private String eventType; + + /** 事件发生时间,统一取各来源表中的操作/创建时间,用于时间轴排序。 */ + private Date eventTime; + + /** 轮胎RFID编码,仅在事件类型为轮胎装卸时有效。 */ + private String tyreRfid; + + /** 轮胎编号,业务展示用。 */ + private String tyreNo; + + /** 轮胎自编号,与 tyreNo 区分,用于内部管理。 */ + private String selfNo; + + /** 轮胎品牌。 */ + private String tyreBrand; + + /** 轮胎规格型号。 */ + private String tyreModel; + + /** 轮位名称,例如:左前轮、右后第二轴等,仅在装卸事件中有效。 */ + private String wheelPostion; + + /** 事件关联的行驶里程(字符串形式,保留原始录入格式)。 */ + private String mileage; + + /** 事件关联的花纹深度(毫米),用于磨损评估。 */ + private String patternDepth; + + /** 状态字典值,例如:工单状态、轮胎状态等,视 eventType 而定。 */ + private String status; + + /** 工单编号,仅在事件类型为维保工单时有效。 */ + private String orderNo; + + /** 类型编码,例如:维保类型字典值、操作类型字典值。 */ + private String typeCode; + + /** 修理厂/工厂名称,仅在维保工单事件中有效。 */ + private String factoryName; + + /** 录入里程(数值型),维保工单或质检记录中由用户录入的当前总里程。 */ + private BigDecimal inputMileage; + + /** 上次里程(数值型),维保工单中记录的上一次保养时的里程。 */ + private BigDecimal lastMileage; + + /** 保养/维修日期,维保工单事件中的计划或实际执行日期。 */ + private Date maintainDate; + + /** 事件描述/故障描述,维保工单中的故障现象或备注信息。 */ + private String description; + + /** 质检结果,仅在轮胎质检相关事件中有效。 */ + private String result; + + /** 维保/检测类型字典值,例如:一级保养、二级保养、日常巡检。 */ + private String maintenanceType; + + /** 轮胎里程记录开始时间,仅在里程类事件中有效。 */ + private Date startTime; + + /** 轮胎里程记录结束时间,仅在里程类事件中有效。 */ + private Date endTime; + + public String getEventType() + { + return eventType; + } + + public void setEventType(String eventType) + { + this.eventType = eventType; + } + + public Date getEventTime() + { + return eventTime; + } + + public void setEventTime(Date eventTime) + { + this.eventTime = eventTime; + } + + public String getTyreRfid() + { + return tyreRfid; + } + + public void setTyreRfid(String tyreRfid) + { + this.tyreRfid = tyreRfid; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getSelfNo() + { + return selfNo; + } + + public void setSelfNo(String selfNo) + { + this.selfNo = selfNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } + + public String getWheelPostion() + { + return wheelPostion; + } + + public void setWheelPostion(String wheelPostion) + { + this.wheelPostion = wheelPostion; + } + + public String getMileage() + { + return mileage; + } + + public void setMileage(String mileage) + { + this.mileage = mileage; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public String getOrderNo() + { + return orderNo; + } + + public void setOrderNo(String orderNo) + { + this.orderNo = orderNo; + } + + public String getTypeCode() + { + return typeCode; + } + + public void setTypeCode(String typeCode) + { + this.typeCode = typeCode; + } + + public String getFactoryName() + { + return factoryName; + } + + public void setFactoryName(String factoryName) + { + this.factoryName = factoryName; + } + + public BigDecimal getInputMileage() + { + return inputMileage; + } + + public void setInputMileage(BigDecimal inputMileage) + { + this.inputMileage = inputMileage; + } + + public BigDecimal getLastMileage() + { + return lastMileage; + } + + public void setLastMileage(BigDecimal lastMileage) + { + this.lastMileage = lastMileage; + } + + public Date getMaintainDate() + { + return maintainDate; + } + + public void setMaintainDate(Date maintainDate) + { + this.maintainDate = maintainDate; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } + + public String getResult() + { + return result; + } + + public void setResult(String result) + { + this.result = result; + } + + public String getMaintenanceType() + { + return maintenanceType; + } + + public void setMaintenanceType(String maintenanceType) + { + this.maintenanceType = maintenanceType; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getEndTime() + { + return endTime; + } + + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleQuery.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleQuery.java new file mode 100644 index 00000000..439d287f --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleQuery.java @@ -0,0 +1,55 @@ +package com.ruoyi.system.domain; + +import com.ruoyi.common.core.domain.BaseEntity; + +/** + * 车辆生命周期查询参数。 + *

    + * 继承若依通用基础实体 {@link BaseEntity},天然支持分页参数(pageNum / pageSize) + * 以及标准的数据权限字段(deptAlias / userAlias)。 + * 本查询对象同时作为“权限校验载体”与“子查询条件载体”: + * 入口以 carNo 做初步过滤,校验通过后由 Service 层回填 carId,后续子查询优先使用 carId 做精确匹配,提升性能并避免字符串歧义。 + *

    + */ +public class CarLifecycleQuery extends BaseEntity +{ + private static final long serialVersionUID = 1L; + + /** + * 车牌号,生命周期报表的唯一业务入口。 + *

    + * 前端弹窗以车牌号为路径参数或查询参数传入,Service 层先通过该字段定位车辆主档, + * 并完成数据权限校验。不允许为空,且长度受数据库字段限制(varchar(50))。 + *

    + */ + private String carNo; + + /** + * 车辆主键ID,由 Service 层在权限校验后自动回填。 + *

    + * 不作为前端传入参数,仅用于后续子查询(装卸、维保、质检、里程)中做精确关联, + * 避免跨表仅依赖字符串车牌号可能导致的性能与一致性问题。 + *

    + */ + private Long carId; + + public String getCarNo() + { + return carNo; + } + + public void setCarNo(String carNo) + { + this.carNo = carNo; + } + + public Long getCarId() + { + return carId; + } + + public void setCarId(Long carId) + { + this.carId = carId; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleSummaryDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleSummaryDTO.java new file mode 100644 index 00000000..70848bc6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarLifecycleSummaryDTO.java @@ -0,0 +1,113 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.math.BigDecimal; + +/** + * 车辆生命周期头部概要DTO。 + *

    + * 作为弹窗顶部的“车辆名片”数据,展示用户最关心的车辆静态属性与最近动态指标。 + * 所有字段均来自 base_car 主档及其关联字典/部门表,通过 {@link BaseCarLifecycleMapper#selectLifecycleCar} 一次性查询返回。 + *

    + */ +public class CarLifecycleSummaryDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 车辆主键ID,base_car 表的唯一标识,用于后续子查询精确关联。 */ + private Long carId; + + /** 车牌号,车辆的唯一业务标识,例如:粤B12345。 */ + private String carNo; + + /** 所属部门ID,关联 sys_dept,用于数据权限过滤。 */ + private Long deptId; + + /** 所属车队名称,由部门ID关联翻译而来,前端直接展示。 */ + private String team; + + /** 线路名称,车辆运营的公交/客运线路。 */ + private String line; + + /** 车型,例如:纯电动大巴、混合动力公交等字典值。 */ + private String type; + + /** + * 最近工单录入里程。 + *

    + * 取自该车辆最近一次维保工单中的 input_mileage 字段,仅作为弹窗头部的展示快照。 + * 使用 BigDecimal 类型避免浮点精度问题,但不参与聚合统计,防止不同工单录入口径差异导致统计失真。 + *

    + */ + private BigDecimal inputMileage; + + public Long getCarId() + { + return carId; + } + + public void setCarId(Long carId) + { + this.carId = carId; + } + + public String getCarNo() + { + return carNo; + } + + public void setCarNo(String carNo) + { + this.carNo = carNo; + } + + public Long getDeptId() + { + return deptId; + } + + public void setDeptId(Long deptId) + { + this.deptId = deptId; + } + + public String getTeam() + { + return team; + } + + public void setTeam(String team) + { + this.team = team; + } + + public String getLine() + { + return line; + } + + public void setLine(String line) + { + this.line = line; + } + + public String getType() + { + return type; + } + + public void setType(String type) + { + this.type = type; + } + + public BigDecimal getInputMileage() + { + return inputMileage; + } + + public void setInputMileage(BigDecimal inputMileage) + { + this.inputMileage = inputMileage; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMaintenanceLifecycleDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMaintenanceLifecycleDTO.java new file mode 100644 index 00000000..d446035b --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMaintenanceLifecycleDTO.java @@ -0,0 +1,160 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.math.BigDecimal; +import java.util.Date; + +/** + * 车辆生命周期维保工单记录DTO。 + *

    + * 用于“车辆全生命周期”弹窗中【维保工单记录】Tab页的数据展示。 + * 数据来源为 biz_maintenance_order 表,通过 plate_number(车牌号)直接与车辆关联,无需额外表桥接。 + *

    + */ +public class CarMaintenanceLifecycleDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 工单主键ID,对应 biz_maintenance_order.order_id。 */ + private Long orderId; + + /** 工单编号,业务展示的唯一编号,例如:WB202401150001。 */ + private String orderNo; + + /** 车辆ID,对应工单表中的 vehicle_id 外键(若存在)。 */ + private Long vehicleId; + + /** 车牌号,工单中直接记录的车牌号,用于与车辆主档确认关联。 */ + private String plateNumber; + + /** 维保类型编码,字典值,例如:一级保养、二级保养、小修、大修。 */ + private String typeCode; + + /** 工单状态编码,字典值,例如:待派工、维修中、已完成、已结算。 */ + private String status; + + /** 录入里程,本次维保/保养时车辆的总行驶里程(数值型)。 */ + private BigDecimal inputMileage; + + /** 上次里程,上一次保养时记录的里程,用于计算两次保养间的行驶距离。 */ + private BigDecimal lastMileage; + + /** 保养/维修日期,工单的计划或实际执行日期。 */ + private Date maintainDate; + + /** 修理厂名称,执行本次维保的外部或内部修理厂。 */ + private String factoryName; + + /** 故障描述/备注,记录车辆故障现象、维修内容或用户补充说明。 */ + private String description; + + public Long getOrderId() + { + return orderId; + } + + public void setOrderId(Long orderId) + { + this.orderId = orderId; + } + + public String getOrderNo() + { + return orderNo; + } + + public void setOrderNo(String orderNo) + { + this.orderNo = orderNo; + } + + public Long getVehicleId() + { + return vehicleId; + } + + public void setVehicleId(Long vehicleId) + { + this.vehicleId = vehicleId; + } + + public String getPlateNumber() + { + return plateNumber; + } + + public void setPlateNumber(String plateNumber) + { + this.plateNumber = plateNumber; + } + + public String getTypeCode() + { + return typeCode; + } + + public void setTypeCode(String typeCode) + { + this.typeCode = typeCode; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } + + public BigDecimal getInputMileage() + { + return inputMileage; + } + + public void setInputMileage(BigDecimal inputMileage) + { + this.inputMileage = inputMileage; + } + + public BigDecimal getLastMileage() + { + return lastMileage; + } + + public void setLastMileage(BigDecimal lastMileage) + { + this.lastMileage = lastMileage; + } + + public Date getMaintainDate() + { + return maintainDate; + } + + public void setMaintainDate(Date maintainDate) + { + this.maintainDate = maintainDate; + } + + public String getFactoryName() + { + return factoryName; + } + + public void setFactoryName(String factoryName) + { + this.factoryName = factoryName; + } + + public String getDescription() + { + return description; + } + + public void setDescription(String description) + { + this.description = description; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMileageLifecycleDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMileageLifecycleDTO.java new file mode 100644 index 00000000..8600a845 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMileageLifecycleDTO.java @@ -0,0 +1,120 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * 车辆生命周期关联轮胎里程记录DTO。 + *

    + * 用于“车辆全生命周期”弹窗中【轮胎里程快照】Tab页的数据展示。 + * 数据通过轮胎RFID间接关联车辆:先找到该车历史上装过的轮胎,再关联 record_tyre_mileage 表获取各轮胎的里程消耗记录。 + *

    + */ +public class CarMileageLifecycleDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 里程记录主键ID,对应 record_tyre_mileage.id。 */ + private Long id; + + /** 轮胎RFID编码,唯一标识轮胎实物,关联 record_tyre_mileage 中的轮胎标识。 */ + private String tyreRfid; + + /** 轮胎编号,业务展示用。 */ + private String tyreNo; + + /** 轮胎品牌。 */ + private String tyreBrand; + + /** 里程统计开始时间,即该轮胎装车或本次统计周期的起始时间点。 */ + private Date startTime; + + /** 里程统计结束时间,即该轮胎卸车或本次统计周期的结束时间点。 */ + private Date endTime; + + /** 该统计周期内累计行驶里程(公里),数值型。 */ + private Long mileage; + + /** 统计结束时的花纹深度(毫米),用于与起始深度对比评估磨损速率。 */ + private String patternDepth; + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getTyreRfid() + { + return tyreRfid; + } + + public void setTyreRfid(String tyreRfid) + { + this.tyreRfid = tyreRfid; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public Date getStartTime() + { + return startTime; + } + + public void setStartTime(Date startTime) + { + this.startTime = startTime; + } + + public Date getEndTime() + { + return endTime; + } + + public void setEndTime(Date endTime) + { + this.endTime = endTime; + } + + public Long getMileage() + { + return mileage; + } + + public void setMileage(Long mileage) + { + this.mileage = mileage; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMountedTyreDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMountedTyreDTO.java new file mode 100644 index 00000000..0bdfe5c7 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarMountedTyreDTO.java @@ -0,0 +1,120 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; + +/** + * 当前装车轮胎快照DTO。 + *

    + * 用于“车辆全生命周期”弹窗首屏的【当前装车轮胎】区域展示。 + * 仅返回当前仍安装在该车辆上的轮胎列表(通常数量等于车辆轮位数), + * 数据来源于 record_tyre_install 中该车辆最新一次安装且尚未卸下(或卸下时间最新但已重新装上)的轮胎记录。 + *

    + */ +public class CarMountedTyreDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 轮胎主键ID,对应 base_tyre.id。 */ + private Long tyreId; + + /** 轮胎编号,业务展示的唯一编号。 */ + private String tyreNo; + + /** 轮胎自编号,与 tyreNo 区分,用于仓库或车队内部管理。 */ + private String selfNo; + + /** 轮胎RFID/EPC编码,物联网识别标签,用于RFID读写器扫描匹配。 */ + private String tyreEpc; + + /** 轮胎品牌,例如:米其林、固特异。 */ + private String tyreBrand; + + /** 轮胎规格型号,例如:12R22.5、295/80R22.5。 */ + private String tyreModel; + + /** 轮位名称,例如:左前转向轮、右后驱动轴第二轴等,指示轮胎安装在车辆的具体位置。 */ + private String wheelPostion; + + /** 当前花纹深度(毫米),反映轮胎剩余磨损寿命,用于安全预警。 */ + private String patternDepth; + + public Long getTyreId() + { + return tyreId; + } + + public void setTyreId(Long tyreId) + { + this.tyreId = tyreId; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getSelfNo() + { + return selfNo; + } + + public void setSelfNo(String selfNo) + { + this.selfNo = selfNo; + } + + public String getTyreEpc() + { + return tyreEpc; + } + + public void setTyreEpc(String tyreEpc) + { + this.tyreEpc = tyreEpc; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } + + public String getWheelPostion() + { + return wheelPostion; + } + + public void setWheelPostion(String wheelPostion) + { + this.wheelPostion = wheelPostion; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarTyreInstallLifecycleDTO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarTyreInstallLifecycleDTO.java new file mode 100644 index 00000000..abe4f335 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/CarTyreInstallLifecycleDTO.java @@ -0,0 +1,160 @@ +package com.ruoyi.system.domain; + +import java.io.Serializable; +import java.util.Date; + +/** + * 车辆生命周期装卸记录DTO。 + *

    + * 用于“车辆全生命周期”弹窗中【轮胎安装/卸胎记录】Tab页的数据展示。 + * 数据来源为 record_tyre_install 表,通过 car_no(车牌号)直接关联车辆, + * 展示该车辆历史上所有轮胎的安装与卸下动作,按操作时间倒序排列。 + *

    + */ +public class CarTyreInstallLifecycleDTO implements Serializable +{ + private static final long serialVersionUID = 1L; + + /** 装卸记录主键ID,对应 record_tyre_install.id。 */ + private Long id; + + /** 轮胎RFID编码,唯一标识被操作的轮胎实物。 */ + private String tyreRfid; + + /** 操作类型字典值,例如:INSTALL(安装)、UNINSTALL(卸下)、SWAP(换位)。 */ + private String installType; + + /** 操作时的车辆行驶里程(公里),数值型,记录动作发生瞬间的车辆总里程。 */ + private Long mileage; + + /** 操作发生时间,即装卸动作的实际执行时间/录入时间。 */ + private Date createTime; + + /** 轮位名称,例如:左前轮、右后第二轴,指示轮胎安装或卸下的具体位置。 */ + private String wheelPostion; + + /** 操作时的花纹深度(毫米),用于追溯轮胎在每次装卸时的磨损状态。 */ + private String patternDepth; + + /** 轮胎编号,被操作轮胎的业务展示编号。 */ + private String tyreNo; + + /** 轮胎自编号,被操作轮胎的内部管理编号。 */ + private String selfNo; + + /** 轮胎品牌。 */ + private String tyreBrand; + + /** 轮胎规格型号。 */ + private String tyreModel; + + public Long getId() + { + return id; + } + + public void setId(Long id) + { + this.id = id; + } + + public String getTyreRfid() + { + return tyreRfid; + } + + public void setTyreRfid(String tyreRfid) + { + this.tyreRfid = tyreRfid; + } + + public String getInstallType() + { + return installType; + } + + public void setInstallType(String installType) + { + this.installType = installType; + } + + public Long getMileage() + { + return mileage; + } + + public void setMileage(Long mileage) + { + this.mileage = mileage; + } + + public Date getCreateTime() + { + return createTime; + } + + public void setCreateTime(Date createTime) + { + this.createTime = createTime; + } + + public String getWheelPostion() + { + return wheelPostion; + } + + public void setWheelPostion(String wheelPostion) + { + this.wheelPostion = wheelPostion; + } + + public String getPatternDepth() + { + return patternDepth; + } + + public void setPatternDepth(String patternDepth) + { + this.patternDepth = patternDepth; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getSelfNo() + { + return selfNo; + } + + public void setSelfNo(String selfNo) + { + this.selfNo = selfNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BaseTyreVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BaseTyreVo.java index 43b2d4d7..2f4d66d1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BaseTyreVo.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/BaseTyreVo.java @@ -6,6 +6,7 @@ import jakarta.validation.constraints.Email; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; import jakarta.validation.constraints.Size; +import org.apache.poi.ss.usermodel.IndexedColors; public class BaseTyreVo { private static final long serialVersionUID = 1L; @@ -38,6 +39,12 @@ public class BaseTyreVo { @Excel(name = "轮胎沟槽数") private String grooves; + /** 入库编码 */ + @Excel(name = "入库编码", color = IndexedColors.RED, + prompt = "Excel 第一行必须填写默认入库编码,后续空行自动沿用最近一次出现的编码;" + + "如中途填写新编码,则从该行开始切换为新批次,直到再次填写其他编码。" ) + private String inboundCode; + public @NotBlank(message = "胎号不能为空") String getTyreNo() { return tyreNo; } @@ -54,6 +61,15 @@ public class BaseTyreVo { this.tyreEpc = tyreEpc; } + public String getInboundCode() { + return inboundCode; + } + + public void setInboundCode(String inboundCode) { + // 入库编码是批量入库的业务键,导入阶段先去空格,避免后续按编码查询不到。 + this.inboundCode = inboundCode == null ? null : inboundCode.trim(); + } + public String getTyreBrand() { return tyreBrand; } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewItemVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewItemVo.java new file mode 100644 index 00000000..52cbfb93 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewItemVo.java @@ -0,0 +1,69 @@ +package com.ruoyi.system.domain.vo; + +/** + * 批量入库预览明细。 + * + * @author zch + */ +public class InboundBatchPreviewItemVo +{ + private String tyreEpc; // 轮胎 RFID/EPC 唯一标识 + + private String tyreNo; // 轮胎外部编号 + + private String tyreBrand; // 轮胎品牌 + + private String tyreModel; // 轮胎型号 + + private String status; // 状态:待入库 / 已存在库存记录 + + public String getTyreEpc() + { + return tyreEpc; + } + + public void setTyreEpc(String tyreEpc) + { + this.tyreEpc = tyreEpc; + } + + public String getTyreNo() + { + return tyreNo; + } + + public void setTyreNo(String tyreNo) + { + this.tyreNo = tyreNo; + } + + public String getTyreBrand() + { + return tyreBrand; + } + + public void setTyreBrand(String tyreBrand) + { + this.tyreBrand = tyreBrand; + } + + public String getTyreModel() + { + return tyreModel; + } + + public void setTyreModel(String tyreModel) + { + this.tyreModel = tyreModel; + } + + public String getStatus() + { + return status; + } + + public void setStatus(String status) + { + this.status = status; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewVo.java new file mode 100644 index 00000000..4401348e --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/InboundBatchPreviewVo.java @@ -0,0 +1,71 @@ +package com.ruoyi.system.domain.vo; + +import java.util.List; + +/** + * 批量入库预览结果。 + * + * @author zch + */ +public class InboundBatchPreviewVo +{ + private String inboundCode; // 入库编码 + + private int total; // 批次轮胎总数 + + private int exists; // 已存在库存记录的数量 + + private int pending; // 待入库数量(total - exists) + + private List items; // 批次明细列表 + + public String getInboundCode() + { + return inboundCode; + } + + public void setInboundCode(String inboundCode) + { + this.inboundCode = inboundCode; + } + + public int getTotal() + { + return total; + } + + public void setTotal(int total) + { + this.total = total; + } + + public int getExists() + { + return exists; + } + + public void setExists(int exists) + { + this.exists = exists; + } + + public int getPending() + { + return pending; + } + + public void setPending(int pending) + { + this.pending = pending; + } + + public List getItems() + { + return items; + } + + public void setItems(List items) + { + this.items = items; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseCarLifecycleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseCarLifecycleMapper.java new file mode 100644 index 00000000..94d35571 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseCarLifecycleMapper.java @@ -0,0 +1,152 @@ +package com.ruoyi.system.mapper; + +import java.util.List; +import com.ruoyi.system.domain.CarCheckLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleEventDTO; +import com.ruoyi.system.domain.CarLifecycleQuery; +import com.ruoyi.system.domain.CarLifecycleSummaryDTO; +import com.ruoyi.system.domain.CarMaintenanceLifecycleDTO; +import com.ruoyi.system.domain.CarMileageLifecycleDTO; +import com.ruoyi.system.domain.CarMountedTyreDTO; +import com.ruoyi.system.domain.CarTyreInstallLifecycleDTO; + +/** + * 车辆全生命周期报表Mapper接口。 + *

    + * 承担车辆全生命周期弹窗所需的所有数据持久化查询职责。 + * 设计原则: + * 1. 以车牌号(carNo)为入口,通过 join sys_dept 等权限表支持 {@link DataScope} 拦截; + * 2. 首屏概要(selectLifecycleCar / selectMountedTyres / selectRecentEvents / count*)与明细分页(select*List)分离,避免大数据量拖慢首屏; + * 3. 各子查询优先使用回填后的 carId 做精确过滤,提升性能并减少字符串匹配歧义。 + *

    + */ +public interface BaseCarLifecycleMapper +{ + /** + * 查询车辆主档概要及最近录入里程。 + *

    + * SQL 需 join sys_dept 并预留 d/u 别名,供 {@link DataScope} 拦截器拼接部门/用户权限条件。 + * 若查询无结果,Service 层统一提示“车辆不存在或无权限访问”,防止接口探测攻击。 + *

    + * + * @param query 包含 carNo 的查询参数 + * @return 车辆概要DTO;无权限或不存在时返回 null + */ + public CarLifecycleSummaryDTO selectLifecycleCar(CarLifecycleQuery query); + + /** + * 查询车辆当前装车轮胎快照。 + *

    + * 仅返回当前仍安装在该车上的轮胎列表,数量通常较少(<= 车辆轮位数),随首屏一起返回。 + * 逻辑上取该车辆各轮位最近一次 installType='INSTALL' 且未后续卸下的记录。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 当前装车轮胎列表;无记录时返回空列表 + */ + public List selectMountedTyres(CarLifecycleQuery query); + + /** + * 查询车辆最近事件时间线(TopN)。 + *

    + * 聚合轮胎装卸记录与维保工单两类事件,取按时间倒序的最近 N 条(例如 10 条)。 + * 用于弹窗首屏快速展示最新动态,避免加载全量历史。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 最近事件列表;无记录时返回空列表 + */ + public List selectRecentEvents(CarLifecycleQuery query); + + /** + * 分页查询车辆轮胎装卸历史明细。 + *

    + * 返回该车辆所有轮胎的安装、卸下、换位等操作记录,支持按操作时间倒序分页。 + * 需配合前端分页参数(pageNum / pageSize)使用。 + *

    + * + * @param query 已回填 carId 且携带分页参数的查询对象 + * @return 装卸记录列表;无记录时返回空列表 + */ + public List selectInstallList(CarLifecycleQuery query); + + /** + * 分页查询车辆维保工单历史明细。 + *

    + * 通过 plate_number = carNo 直接关联 biz_maintenance_order 表,返回维保工单列表。 + * 支持按保养日期(maintain_date)倒序分页。 + *

    + * + * @param query 已回填 carId 且携带分页参数的查询对象 + * @return 维保工单列表;无记录时返回空列表 + */ + public List selectMaintenanceList(CarLifecycleQuery query); + + /** + * 分页查询车辆关联轮胎质检历史明细。 + *

    + * 车辆与质检记录无直接外键,需通过“该车曾装过的轮胎RFID”间接关联 record_check 表。 + * SQL 中通常使用子查询或 join record_tyre_install 做中间桥接。 + *

    + * + * @param query 已回填 carId 且携带分页参数的查询对象 + * @return 质检记录列表;无记录时返回空列表 + */ + public List selectCheckList(CarLifecycleQuery query); + + /** + * 分页查询车辆关联轮胎里程历史明细。 + *

    + * 通过轮胎RFID间接关联 record_tyre_mileage 表,获取该车历史上装过的各轮胎的里程记录。 + * 展示各轮胎在不同装车周期内的起止时间与累计行驶里程。 + *

    + * + * @param query 已回填 carId 且携带分页参数的查询对象 + * @return 轮胎里程记录列表;无记录时返回空列表 + */ + public List selectMileageList(CarLifecycleQuery query); + + /** + * 统计该车辆轮胎装卸记录总条数。 + *

    + * 用于弹窗首屏返回 installCount,供前端分页组件计算总页数。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 装卸记录总条数;无记录时返回 0 + */ + public int countInstallRecords(CarLifecycleQuery query); + + /** + * 统计该车辆维保工单总条数。 + *

    + * 用于弹窗首屏返回 maintenanceCount,供前端分页组件计算总页数。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 维保工单总条数;无记录时返回 0 + */ + public int countMaintenanceOrders(CarLifecycleQuery query); + + /** + * 统计该车辆关联轮胎质检记录总条数。 + *

    + * 用于弹窗首屏返回 checkCount,供前端分页组件计算总页数。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 质检记录总条数;无记录时返回 0 + */ + public int countCheckRecords(CarLifecycleQuery query); + + /** + * 统计该车辆关联轮胎里程记录总条数。 + *

    + * 用于弹窗首屏返回 mileageCount,供前端分页组件计算总页数。 + *

    + * + * @param query 已回填 carId 的查询参数 + * @return 里程记录总条数;无记录时返回 0 + */ + public int countMileageRecords(CarLifecycleQuery query); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseInventoryMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseInventoryMapper.java index bb821c18..97ddeb9d 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseInventoryMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseInventoryMapper.java @@ -4,6 +4,7 @@ package com.ruoyi.system.mapper; import com.ruoyi.common.core.domain.entity.SysDeptVo; import com.ruoyi.system.domain.BaseInventory; +import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; @@ -73,4 +74,14 @@ public interface BaseInventoryMapper int queryInCar(); int queryCarTotal(); + + + /** + * 根据轮胎RFID删除在库库存信息 + * + * @param tyreRfid 轮胎RFID + * @return 结果 + */ + int deleteInStockBaseInventoryByEpc(@Param("tyreRfid") String tyreRfid); + } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseTyreMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseTyreMapper.java index d414b88d..85b61fb5 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseTyreMapper.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/BaseTyreMapper.java @@ -5,6 +5,7 @@ package com.ruoyi.system.mapper; import com.ruoyi.common.core.domain.entity.SysDept; import com.ruoyi.system.domain.BaseTyre; import com.ruoyi.system.domain.vo.BaseTyreVo; +import org.apache.ibatis.annotations.Param; import java.util.List; import java.util.Map; @@ -73,5 +74,22 @@ public interface BaseTyreMapper List vTyreStockSummary(SysDept sysDept); + /** + * 根据入库编码查询批次下的轮胎基础信息列表 + * + * @param inboundCode 入库编码 + * @return 轮胎基础信息列表 + */ + List selectByInboundCode(@Param("inboundCode") String inboundCode); + + /** + * 根据入库编码统计批次下的轮胎数量 + * + * @param inboundCode 入库编码 + * @return 轮胎数量 + */ + int countBaseTyreByInboundCode(@Param("inboundCode") String inboundCode); + + BaseTyre selectBaseTyreByKeyParam(BaseTyre baseTyre); } 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 new file mode 100644 index 00000000..9e497ed6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseCarLifecycleService.java @@ -0,0 +1,55 @@ +package com.ruoyi.system.service; + +import java.util.List; +import com.ruoyi.system.domain.CarCheckLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleQuery; +import com.ruoyi.system.domain.CarMaintenanceLifecycleDTO; +import com.ruoyi.system.domain.CarMileageLifecycleDTO; +import com.ruoyi.system.domain.CarTyreInstallLifecycleDTO; + +/** + * 车辆全生命周期报表Service接口。 + */ +public interface IBaseCarLifecycleService +{ + /** + * 查询车辆生命周期概要。 + * + * @param query 生命周期查询参数 + * @return 车辆生命周期概要 + */ + public CarLifecycleDTO selectLifecycle(CarLifecycleQuery query); + + /** + * 查询车辆装卸历史。 + * + * @param query 生命周期查询参数 + * @return 装卸历史集合 + */ + public List selectInstallList(CarLifecycleQuery query); + + /** + * 查询车辆维保工单历史。 + * + * @param query 生命周期查询参数 + * @return 维保工单集合 + */ + public List selectMaintenanceList(CarLifecycleQuery query); + + /** + * 查询车辆关联轮胎质检历史。 + * + * @param query 生命周期查询参数 + * @return 质检历史集合 + */ + public List selectCheckList(CarLifecycleQuery query); + + /** + * 查询车辆关联轮胎里程历史。 + * + * @param query 生命周期查询参数 + * @return 里程历史集合 + */ + public List selectMileageList(CarLifecycleQuery query); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseInventoryService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseInventoryService.java index 09981f26..a1796326 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseInventoryService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IBaseInventoryService.java @@ -4,6 +4,7 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDeptVo; import com.ruoyi.system.domain.BaseInventory; import com.ruoyi.system.domain.BaseTyre; +import com.ruoyi.system.domain.vo.InboundBatchPreviewVo; import java.util.List; @@ -74,4 +75,31 @@ public interface IBaseInventoryService int queryInCar(); int queryCarTotal(); + + /** + * 按入库编码预览批次入库情况,返回批次轮胎总数、已入库数、待入库数及明细列表。 + * + * @param inboundCode 入库编码 + * @return 批量入库预览视图 + */ + InboundBatchPreviewVo previewBatchByCode(String inboundCode); + + /** + * 按入库编码执行批量入库,逐条使用独立事务写入库存并同步轮胎归属,失败条目不影响其他条目。 + * + * @param inboundCode 入库编码 + * @param operName 操作人登录名 + * @return 实际成功入库的条数 + */ + int batchInboundByCode(String inboundCode, String operName); + + /** + * 按入库编码撤回批量入库,仅删除在库状态的库存记录并写入撤回流水。 + * + * @param inboundCode 入库编码 + * @param operName 操作人登录名 + * @return 实际成功撤回的条数 + */ + int rollbackBatchInboundByCode(String inboundCode, String operName); + } 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 02e118cf..4e6de736 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 @@ -76,5 +76,14 @@ public interface IBaseTyreService List vTyreStockSummary(SysDept sysDept); + /** + * 根据入库编码查询该批次下的所有轮胎基础档案。 + * + * @param inboundCode 入库编码 + * @return 该批次下的轮胎基础档案列表 + */ + List selectBaseTyresByInboundCode(String inboundCode); + + Map pdaQueryTyreTimeLine(BaseTyre baseTyre); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IInboundBatchService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IInboundBatchService.java new file mode 100644 index 00000000..66af5e64 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IInboundBatchService.java @@ -0,0 +1,31 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.domain.BaseTyre; + +/** + * 批量入库单条事务服务接口 + * + * @author zch + */ +public interface IInboundBatchService +{ + /** + * 单条轮胎入库。 + * + * @param tyre 轮胎基础档案 + * @param operName 操作人登录名 + * @param inboundCode 入库编码 + * @return true=已入库,false=已存在需跳过 + */ + boolean inboundOne(BaseTyre tyre, String operName, String inboundCode); + + /** + * 单条轮胎撤回入库。 + * + * @param tyre 轮胎基础档案 + * @param operName 操作人登录名 + * @param inboundCode 入库编码 + * @return true=已撤回,false=无可撤回库存需跳过 + */ + boolean rollbackOne(BaseTyre tyre, String operName, String inboundCode); +} 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 new file mode 100644 index 00000000..beafbb06 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseCarLifecycleServiceImpl.java @@ -0,0 +1,196 @@ +package com.ruoyi.system.service.impl; + +import java.util.List; +import com.ruoyi.common.annotation.DataScope; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.StringUtils; +import com.ruoyi.system.domain.CarCheckLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleDTO; +import com.ruoyi.system.domain.CarLifecycleQuery; +import com.ruoyi.system.domain.CarLifecycleSummaryDTO; +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.service.IBaseCarLifecycleService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; + +/** + * 车辆全生命周期报表Service业务层处理。 + *

    + * 本服务以车牌号(carNo)为唯一入口,通过 {@link #buildAuthorizedCar(CarLifecycleQuery)} 完成: + * 1)参数校验;2)车辆存在性与数据权限校验;3)将 carId 回写到查询对象中,供后续聚合查询复用。 + * 所有对外查询方法均标注 {@link DataScope},确保与车辆列表页(system:car:view)保持一致的部门/用户权限过滤。 + *

    + */ +@Service +public class BaseCarLifecycleServiceImpl implements IBaseCarLifecycleService +{ + @Autowired + private BaseCarLifecycleMapper baseCarLifecycleMapper; + + /** + * 查询车辆生命周期概要。 + *

    + * 作为弹窗“首屏”数据,一次性返回: + * - 车辆主档概要(车牌号、车队、线路、车型、最近录入里程) + * - 当前装车轮胎快照(mountedTyres) + * - 最近事件时间线(recentEvents) + * - 各维度记录总数量(installCount / maintenanceCount / checkCount / mileageCount) + * 各子列表具体明细需调用对应的独立分页接口获取,避免首屏数据量过大。 + *

    + * + * @param query 查询参数,必须包含非空且长度合法的 carNo + * @return 车辆生命周期聚合DTO,包含概要及计数 + * @throws ServiceException 车牌号为空、超长、或车辆不存在/无权限时抛出 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public CarLifecycleDTO selectLifecycle(CarLifecycleQuery query) + { + CarLifecycleSummaryDTO car = buildAuthorizedCar(query); + CarLifecycleDTO dto = new CarLifecycleDTO(); + dto.setCar(car); + dto.setMountedTyres(baseCarLifecycleMapper.selectMountedTyres(query)); + dto.setRecentEvents(baseCarLifecycleMapper.selectRecentEvents(query)); + dto.setInstallCount(baseCarLifecycleMapper.countInstallRecords(query)); + dto.setMaintenanceCount(baseCarLifecycleMapper.countMaintenanceOrders(query)); + dto.setCheckCount(baseCarLifecycleMapper.countCheckRecords(query)); + dto.setMileageCount(baseCarLifecycleMapper.countMileageRecords(query)); + return dto; + } + + /** + * 查询车辆轮胎装卸历史(分页/全量)。 + *

    + * 返回该车辆历史上所有轮胎安装与卸下记录,按操作时间倒序排列。 + * 展示字段包括:轮胎RFID、轮胎自编号、品牌型号、轮位、操作类型(安装/卸下)、操作里程、花纹深度、操作时间等。 + *

    + * + * @param query 查询参数,内部通过 buildAuthorizedCar 回填 carId + * @return 装卸记录列表;无记录时返回空列表而非 null + * @throws ServiceException 车辆不存在或无权限访问时抛出 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectInstallList(CarLifecycleQuery query) + { + buildAuthorizedCar(query); + return baseCarLifecycleMapper.selectInstallList(query); + } + + /** + * 查询车辆维保工单历史(分页/全量)。 + *

    + * 通过 {@code biz_maintenance_order.plate_number = carNo} 直接关联车辆,返回所有维保工单。 + * 展示字段包括:工单编号、维保类型、修理厂、保养日期、工单状态、录入里程、上次里程、故障描述等。 + * 数据按保养日期(maintain_date)倒序排列。 + *

    + * + * @param query 查询参数,内部通过 buildAuthorizedCar 回填 carId + * @return 维保工单列表;无记录时返回空列表 + * @throws ServiceException 车辆不存在或无权限访问时抛出 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectMaintenanceList(CarLifecycleQuery query) + { + buildAuthorizedCar(query); + return baseCarLifecycleMapper.selectMaintenanceList(query); + } + + /** + * 查询车辆关联轮胎质检历史(分页/全量)。 + *

    + * 车辆与质检记录无直接外键关联,需通过“该车辆曾装过的轮胎”间接查询: + * 以 record_tyre_install 中出现过且 car_no 匹配的记录为桥梁,找到对应轮胎在 record_check 中的质检记录。 + * 展示字段包括:轮胎RFID、轮胎编号、品牌型号、质检结果、维保类型、里程、花纹深度、质检时间等。 + *

    + * + * @param query 查询参数,内部通过 buildAuthorizedCar 回填 carId + * @return 质检记录列表;无记录时返回空列表 + * @throws ServiceException 车辆不存在或无权限访问时抛出 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectCheckList(CarLifecycleQuery query) + { + buildAuthorizedCar(query); + return baseCarLifecycleMapper.selectCheckList(query); + } + + /** + * 查询车辆关联轮胎里程历史(分页/全量)。 + *

    + * 轮胎里程通过 record_tyre_mileage 记录,间接关联到车辆。 + * 展示字段包括:轮胎RFID、轮胎编号、品牌、开始时间、结束时间、行驶里程、花纹深度等。 + * 用于展示车辆使用过的各轮胎在其装车周期内的里程消耗情况。 + *

    + * + * @param query 查询参数,内部通过 buildAuthorizedCar 回填 carId + * @return 轮胎里程记录列表;无记录时返回空列表 + * @throws ServiceException 车辆不存在或无权限访问时抛出 + */ + @Override + @DataScope(deptAlias = "d", userAlias = "u") + public List selectMileageList(CarLifecycleQuery query) + { + buildAuthorizedCar(query); + return baseCarLifecycleMapper.selectMileageList(query); + } + + /** + * 构建受权车辆主档并回填查询条件。 + *

    + * 核心权限闸口:所有公开查询方法均先调用本方法。 + * 1. 调用 {@link #validateQuery(CarLifecycleQuery)} 做基础参数校验; + * 2. 通过 Mapper 查询车辆主档,SQL 中已拼接 {@code DataScope} 部门/用户别名(d/u); + * 3. 若查询结果为 null,统一提示“车辆不存在或无权限访问”,防止攻击者通过接口枚举判断某车牌是否存在; + * 4. 将车辆主键 carId 回写到 query 对象,供后续子查询作为精确过滤条件,避免仅依赖字符串车牌号跨表查询带来的性能与歧义问题。 + *

    + * + * @param query 生命周期查询参数对象 + * @return 车辆主档概要DTO + * @throws ServiceException 参数非法、车辆不存在或无数据权限时抛出 + */ + private CarLifecycleSummaryDTO buildAuthorizedCar(CarLifecycleQuery query) + { + validateQuery(query); + CarLifecycleSummaryDTO car = baseCarLifecycleMapper.selectLifecycleCar(query); + if (car == null) + { + // 统一“无权限”和“不存在”的提示,避免通过接口探测车辆主档是否存在。 + throw new ServiceException("车辆不存在或无权限访问"); + } + query.setCarId(car.getCarId()); + return car; + } + + /** + * 校验生命周期查询参数。 + *

    + * 校验规则: + * 1. query 对象不能为 null,且 carNo 不能为空或空白字符; + * 2. 车牌号去除前后空格后,长度不得超过 50 字符(与数据库表 base_car.car_no 的 varchar(50) 定义保持一致); + * 3. 校验通过后将规范化后的车牌号(trim 后)重新设置回 query,避免后续 SQL 中因前后空格导致匹配失败。 + *

    + * + * @param query 待校验的查询参数 + * @throws ServiceException 校验不通过时抛出,携带明确错误提示 + */ + private void validateQuery(CarLifecycleQuery query) + { + if (query == null || StringUtils.isBlank(query.getCarNo())) + { + throw new ServiceException("车牌号不能为空"); + } + String carNo = query.getCarNo().trim(); + if (carNo.length() > 50) + { + // base_car.car_no 当前按 varchar(50) 设计,超长路径参数直接拒绝更利于定位异常调用。 + throw new ServiceException("车牌号长度超过限制"); + } + query.setCarNo(carNo); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseInventoryServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseInventoryServiceImpl.java index c9ae9188..7d14ba79 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseInventoryServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/BaseInventoryServiceImpl.java @@ -5,21 +5,27 @@ import com.ruoyi.common.core.domain.AjaxResult; import com.ruoyi.common.core.domain.entity.SysDeptVo; import com.ruoyi.common.core.domain.entity.SysUser; import com.ruoyi.common.core.text.Convert; +import com.ruoyi.common.exception.ServiceException; import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.BaseInventory; import com.ruoyi.system.domain.BaseTyre; import com.ruoyi.system.domain.RecordWarehousing; +import com.ruoyi.system.domain.vo.InboundBatchPreviewItemVo; +import com.ruoyi.system.domain.vo.InboundBatchPreviewVo; import com.ruoyi.system.mapper.BaseInventoryMapper; import com.ruoyi.system.mapper.BaseTyreMapper; import com.ruoyi.system.mapper.RecordWarehousingMapper; import com.ruoyi.system.mapper.SysUserMapper; import com.ruoyi.system.service.IBaseInventoryService; +import com.ruoyi.system.service.IInboundBatchService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -42,6 +48,10 @@ public class BaseInventoryServiceImpl implements IBaseInventoryService @Autowired private SysUserMapper sysUserMapper; + + @Autowired + private IInboundBatchService inboundBatchService; + private static final Logger log = LoggerFactory.getLogger(BaseInventoryServiceImpl.class); /** @@ -153,6 +163,7 @@ public class BaseInventoryServiceImpl implements IBaseInventoryService baseTyre.setTeam(team); baseTyre.setCreateBy(baseInventory.getCreateBy()); baseTyre.setDeptId(sysUser.getDeptId()); + baseTyre.setInventoryStatus("0"); // 入库后库存状态置为在仓 baseTyreMapper.insertBaseTyre(baseTyre); }else { baseTyre.setTyreId(baseTyres.getTyreId()); @@ -160,6 +171,7 @@ public class BaseInventoryServiceImpl implements IBaseInventoryService baseTyre.setTeam(team); baseTyre.setUpdateBy(baseInventory.getCreateBy()); baseTyre.setDeptId(sysUser.getDeptId()); + baseTyre.setInventoryStatus("0"); // 入库后库存状态置为在仓 baseTyreMapper.updateBaseTyre(baseTyre); } } @@ -222,4 +234,167 @@ public class BaseInventoryServiceImpl implements IBaseInventoryService public int queryCarTotal() { return baseInventoryMapper.queryCarTotal(); } + + + /** + * 按入库编码预览批次入库情况 + * + * @param inboundCode 入库编码 + * @return 批量入库预览视图 + */ + @Override + public InboundBatchPreviewVo previewBatchByCode(String inboundCode) { + if (StringUtils.isEmpty(inboundCode)) + { + throw new ServiceException("入库编码不能为空"); // 前置参数校验 + } + String code = normalizeInboundCode(inboundCode); // 标准化入库编码,去除前后空白 + List tyres = baseTyreMapper.selectByInboundCode(code); // 按编码查询批次下的所有轮胎基础档案 + if (StringUtils.isEmpty(tyres)) + { + throw new ServiceException("未找到入库编码为 " + code + " 的批次"); // 无数据时给出明确提示 + } + // Service 层只返回业务数据,避免把 AjaxResult 这种 Web 响应模型下沉到业务层。 + return buildBatchPreview(code, tyres); // 组装预览视图,统计总条数、已入库条数与待入库条数 + } + + /** + * 按入库编码执行批量入库 + * + * @param inboundCode 入库编码 + * @param operName 操作人登录名 + * @return 实际成功入库的条数 + */ + @Override + public int batchInboundByCode(String inboundCode, String operName) { + if (StringUtils.isEmpty(inboundCode)) + { + throw new ServiceException("入库编码不能为空"); // 前置参数校验 + } + String code = normalizeInboundCode(inboundCode); // 标准化入库编码 + List tyres = baseTyreMapper.selectByInboundCode(code); // 查询批次下所有轮胎 + if (StringUtils.isEmpty(tyres)) + { + throw new ServiceException("未找到入库编码为 " + code + " 的批次"); // 无数据时阻断 + } + + int success = 0; // 统计实际成功写入库存的条数 + for (BaseTyre tyre : tyres) + { + try + { + boolean inserted = inboundBatchService.inboundOne(tyre, operName, code); // 逐条调用独立事务入库 + if (inserted) + { + success++; // 写入成功则计数累加 + } + else + { + // 已存在库存时按幂等跳过,不计入本次成功写入条数。 + log.info("批量入库跳过已在库轮胎,inboundCode={}, tyreEpc={}", code, tyre.getTyreEpc()); // 记录幂等跳过日志 + } + } + catch (Exception e) + { + log.error("批量入库失败,inboundCode={}, tyreEpc={}", code, tyre.getTyreEpc(), e); // 单条异常不影响整体批次,仅记录日志 + } + } + + return success; // 返回实际成功入库条数 + } + + /** + * 按入库编码撤回批量入库 + * + * @param inboundCode 入库编码 + * @param operName 操作人登录名 + * @return 实际成功撤回的条数 + */ + @Override + public int rollbackBatchInboundByCode(String inboundCode, String operName) { + if (StringUtils.isEmpty(inboundCode)) + { + throw new ServiceException("入库编码不能为空"); // 前置参数校验 + } + String code = normalizeInboundCode(inboundCode); // 标准化入库编码 + List tyres = baseTyreMapper.selectByInboundCode(code); // 查询批次下所有轮胎 + if (StringUtils.isEmpty(tyres)) + { + throw new ServiceException("未找到入库编码为 " + code + " 的批次"); // 无数据时阻断 + } + + int success = 0; // 统计实际成功撤回的条数 + for (BaseTyre tyre : tyres) + { + try + { + boolean rollback = inboundBatchService.rollbackOne(tyre, operName, code); // 逐条调用独立事务撤回 + if (rollback) + { + success++; // 撤回成功则计数累加 + } + else + { + // 不在库或已出库的记录不能撤回,按幂等跳过,不计入成功撤回条数。 + log.info("批量入库撤回跳过非在库轮胎,inboundCode={}, tyreEpc={}", code, tyre.getTyreEpc()); // 记录幂等跳过日志 + } + } + catch (Exception e) + { + log.error("批量入库撤回失败,inboundCode={}, tyreEpc={}", code, tyre.getTyreEpc(), e); // 单条异常不影响整体批次,仅记录日志 + } + } + + return success; // 返回实际成功撤回条数 + } + + /** + * 标准化入库编码,去除前后空白 + * + * @param inboundCode 原始入库编码 + * @return 标准化后的入库编码 + */ + private String normalizeInboundCode(String inboundCode) + { + return inboundCode.trim(); // 去除前后空白,避免首尾空格导致批次查询不一致 + } + + /** + * 组装批量入库预览视图 + * + * @param inboundCode 入库编码 + * @param tyres 批次下的轮胎列表 + * @return 预览视图对象 + */ + private InboundBatchPreviewVo buildBatchPreview(String inboundCode, List tyres) + { + int exists = 0; // 统计已入库的轮胎条数 + List items = new ArrayList<>(); // 明细列表 + for (BaseTyre tyre : tyres) + { + BaseInventory probe = new BaseInventory(); // 构造库存查询探针 + probe.setTyreRfid(tyre.getTyreEpc()); // 按 RFID 查询库存 + BaseInventory inventory = baseInventoryMapper.selectBaseInventoryByEpc(probe); // 查询当前是否已入库 + if (inventory != null) + { + exists++; // 已存在库存记录则累加 + } + InboundBatchPreviewItemVo item = new InboundBatchPreviewItemVo(); // 构造预览明细项 + item.setTyreEpc(tyre.getTyreEpc()); // 轮胎 RFID + item.setTyreNo(tyre.getTyreNo()); // 轮胎外部编号 + item.setTyreBrand(tyre.getTyreBrand()); // 轮胎品牌 + item.setTyreModel(tyre.getTyreModel()); // 轮胎型号 + // 预览时直接给出状态,现场可在入库前确认哪些会被跳过。 + item.setStatus(inventory == null ? "待入库" : "已存在库存记录"); // 状态区分:未入库 / 已存在 + items.add(item); // 加入明细列表 + } + InboundBatchPreviewVo data = new InboundBatchPreviewVo(); // 构造预览结果对象 + data.setInboundCode(inboundCode); // 批次入库编码 + data.setTotal(tyres.size()); // 批次轮胎总数 + data.setExists(exists); // 已入库数量 + data.setPending(tyres.size() - exists); // 待入库数量 = 总数 - 已存在 + data.setItems(items); // 明细数据 + return data; // 返回预览结果 + } + } 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 09e2706b..b333b5ad 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 @@ -10,12 +10,8 @@ import com.ruoyi.common.utils.DateUtils; import com.ruoyi.common.utils.StringUtils; import com.ruoyi.system.domain.BaseCar; import com.ruoyi.system.domain.BaseTyre; -import com.ruoyi.system.domain.RecordTyreInstall; -import com.ruoyi.system.domain.RecordWarehousing; import com.ruoyi.system.domain.vo.BaseTyreVo; 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 org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -24,8 +20,10 @@ 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 static com.ruoyi.common.utils.ShiroUtils.getLoginName; @@ -176,6 +174,31 @@ public class BaseTyreServiceImpl implements IBaseTyreService int failureNum = 0; StringBuilder successMsg = new StringBuilder(); StringBuilder failureMsg = new StringBuilder(); + String currentInboundCode = null; // 当前行生效的入库编码,空行时继承上一行 + Set inboundCodes = new HashSet<>(); // 收集本次导入涉及的所有入库编码,用于全局唯一校验 + for (BaseTyreVo baseTyreVo : baseTyreVoList) + { + String rowInboundCode = baseTyreVo.getInboundCode(); // 读取 Excel 当前行的入库编码 + if (StringUtils.isNotEmpty(rowInboundCode)) + { + currentInboundCode = rowInboundCode.trim(); // 遇到非空编码时更新当前生效编码并去空白 + inboundCodes.add(currentInboundCode); // 加入编码集合,后续做全局唯一校验 + } + if (StringUtils.isEmpty(currentInboundCode)) + { + throw new ServiceException("入库编码不能为空,请在导入模板第一行填写默认入库编码!"); // 首行及继承后仍为空则阻断导入 + } + // 入库编码按 Excel 行顺序分段继承:空行沿用最近一次出现的编码,遇到新编码则切换到新批次。 + baseTyreVo.setInboundCode(currentInboundCode); // 回写最终生效的入库编码到当前行 + } + for (String inboundCode : inboundCodes) + { + // 入库编码只按编码本身做全局唯一校验,不绑定供应商,号段由用户自行规划。 + if (baseTyreMapper.countBaseTyreByInboundCode(inboundCode) > 0) + { + throw new ServiceException("入库编码 " + inboundCode + " 已存在,请更换本批次唯一入库编码!"); // 任一编码重复即整体阻断,防止批次混用 + } + } for (BaseTyreVo baseTyreVo : baseTyreVoList) { @@ -225,6 +248,11 @@ public class BaseTyreServiceImpl implements IBaseTyreService return mapList; } + @Override + public List selectBaseTyresByInboundCode(String inboundCode) { + return baseTyreMapper.selectByInboundCode(inboundCode); + } + @Override public Map pdaQueryTyreTimeLine(BaseTyre baseTyre) { Map map = new HashMap(); diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InboundBatchServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InboundBatchServiceImpl.java new file mode 100644 index 00000000..5ebe06e7 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/InboundBatchServiceImpl.java @@ -0,0 +1,160 @@ +package com.ruoyi.system.service.impl; + +import com.ruoyi.common.core.domain.entity.SysUser; +import com.ruoyi.common.exception.ServiceException; +import com.ruoyi.common.utils.DateUtils; +import com.ruoyi.system.domain.BaseInventory; +import com.ruoyi.system.domain.BaseTyre; +import com.ruoyi.system.domain.RecordWarehousing; +import com.ruoyi.system.mapper.BaseInventoryMapper; +import com.ruoyi.system.mapper.BaseTyreMapper; +import com.ruoyi.system.mapper.RecordWarehousingMapper; +import com.ruoyi.system.mapper.SysUserMapper; +import com.ruoyi.system.service.IInboundBatchService; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Propagation; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Date; + +/** + * 批量入库单条事务服务 + * + * @author zch + */ +@Service +public class InboundBatchServiceImpl implements IInboundBatchService +{ + @Autowired + private BaseInventoryMapper baseInventoryMapper; // 库存数据访问 + + @Autowired + private BaseTyreMapper baseTyreMapper; // 轮胎基础档案数据访问 + + @Autowired + private RecordWarehousingMapper recordWarehousingMapper; // 入库流水数据访问 + + @Autowired + private SysUserMapper sysUserMapper; // 用户数据访问,用于读取操作人部门 + + /** + * 单条入库使用独立事务,避免批次中某一条失败时把其他轮胎的成功入库一起回滚。 + * + * @param tyre 轮胎基础档案 + * @param operName 操作人登录名 + * @param inboundCode 入库编码 + * @return 入库成功返回 true,已存在库存时幂等跳过返回 false + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) + public boolean inboundOne(BaseTyre tyre, String operName, String inboundCode) + { + BaseInventory probe = new BaseInventory(); // 构造查询探针 + probe.setTyreRfid(tyre.getTyreEpc()); // 按轮胎 RFID 查找库存 + BaseInventory existed = baseInventoryMapper.selectBaseInventoryByEpc(probe); // 查询是否已入库 + if (existed != null) + { + return false; // 已存在库存记录,幂等跳过 + } + + Date now = DateUtils.getNowDate(); // 获取当前系统时间 + BaseInventory inventory = new BaseInventory(); // 新建库存记录 + inventory.setTyreRfid(tyre.getTyreEpc()); // 绑定轮胎 RFID + inventory.setTyreOutsideId(tyre.getTyreNo()); // 绑定轮胎外部编号 + inventory.setNumber(1L); // 数量默认为 1 + inventory.setStatus("0"); //参考insertInventoryByPda + inventory.setCreateBy(operName); // 记录创建人 + inventory.setCreateTime(now); // 记录创建时间 + inventory.setUpdateTime(now); // 记录更新时间 + inventory.setRemark("批量入库[" + inboundCode + "]"); // 备注携带批次号 + int inventoryRows = baseInventoryMapper.insertBaseInventory(inventory); // 写入库存表 + if (inventoryRows <= 0) + { + throw new ServiceException("库存写入失败"); // 写入失败则抛异常触发回滚 + } + + RecordWarehousing record = new RecordWarehousing(); // 新建入库流水 + record.setTyreRfid(tyre.getTyreEpc()); // 绑定轮胎 RFID + record.setType("0"); // 参考insertInventoryByPda + record.setCreateBy(operName); // 记录操作人 + record.setCreateTime(now); // 记录操作时间 + record.setRemark("批量入库[" + inboundCode + "]"); // 备注携带批次号 + int recordRows = recordWarehousingMapper.insertRecordWarehousing(record); // 写入流水表 + if (recordRows <= 0) + { + throw new ServiceException("入库流水写入失败"); // 写入失败则抛异常触发回滚 + } + syncBaseTyreOwner(tyre, operName, now); // 同步轮胎归属信息到当前操作人部门 + return true; // 单条入库成功 + } + + /** + * 批量入库后同步基础档案归属,保持与 PDA 单条入库一致,避免库存已入库但轮胎仍挂在旧部门。 + */ + private void syncBaseTyreOwner(BaseTyre tyre, String operName, Date now) + { + if (tyre.getTyreId() == null) + { + throw new ServiceException("轮胎基础档案ID不能为空"); // 档案 ID 必传校验 + } + SysUser sysUser = sysUserMapper.selectUserByLoginName(operName); // 按登录名查询用户信息 + if (sysUser == null || sysUser.getDeptId() == null) + { + throw new ServiceException("未找到操作人部门信息"); // 校验操作人及所属部门 + } + + BaseTyre updateTyre = new BaseTyre(); // 构造更新对象 + updateTyre.setTyreId(tyre.getTyreId()); // 指定待更新的轮胎档案 + updateTyre.setTeam(baseTyreMapper.getTeamByUser(operName)); // 同步车队归属 + updateTyre.setDeptId(sysUser.getDeptId()); // 同步部门归属 + updateTyre.setInventoryStatus("0"); // 入库后库存状态更新为在仓(0=在仓,1=出仓,NULL=已发货待入库) + updateTyre.setUpdateBy(operName); // 记录更新人 + updateTyre.setUpdateTime(now); // 记录更新时间 + int tyreRows = baseTyreMapper.updateBaseTyre(updateTyre); // 执行更新 + if (tyreRows <= 0) + { + throw new ServiceException("轮胎归属信息同步失败"); // 更新失败抛异常 + } + } + + /** + * 撤回只处理仍处于在库状态的库存记录,避免把已出库或已被后续业务使用的轮胎误删。 + * + * @param tyre 轮胎基础档案 + * @param operName 操作人登录名 + * @param inboundCode 入库编码 + * @return 撤回成功返回 true,库存不存在或非在库状态时幂等跳过返回 false + */ + @Override + @Transactional(propagation = Propagation.REQUIRES_NEW, rollbackFor = Exception.class) + public boolean rollbackOne(BaseTyre tyre, String operName, String inboundCode) + { + BaseInventory probe = new BaseInventory(); // 构造查询探针 + probe.setTyreRfid(tyre.getTyreEpc()); // 按轮胎 RFID 查找库存 + BaseInventory existed = baseInventoryMapper.selectBaseInventoryByEpc(probe); // 查询当前库存状态 + if (existed == null || !"0".equals(existed.getStatus())) + { + return false; // 库存不存在或非在库状态时不允许撤回,幂等跳过 + } + + int deleteRows = baseInventoryMapper.deleteInStockBaseInventoryByEpc(tyre.getTyreEpc()); // 删除在库记录 + if (deleteRows <= 0) + { + throw new ServiceException("库存撤回失败"); // 删除失败抛异常 + } + + RecordWarehousing record = new RecordWarehousing(); // 新建撤回流水 + record.setTyreRfid(tyre.getTyreEpc()); // 绑定轮胎 RFID + record.setType("1"); // 1 表示撤回类型 + record.setCreateBy(operName); // 记录操作人 + record.setCreateTime(DateUtils.getNowDate()); // 记录操作时间 + record.setRemark("批量入库撤回[" + inboundCode + "]"); // 备注携带批次号 + int recordRows = recordWarehousingMapper.insertRecordWarehousing(record); // 写入流水表 + if (recordRows <= 0) + { + throw new ServiceException("撤回流水写入失败"); // 写入失败抛异常 + } + return true; // 单条撤回成功 + } +} diff --git a/ruoyi-system/src/main/resources/mapper/tyre/BaseCarLifecycleMapper.xml b/ruoyi-system/src/main/resources/mapper/tyre/BaseCarLifecycleMapper.xml new file mode 100644 index 00000000..8a82c7bc --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/tyre/BaseCarLifecycleMapper.xml @@ -0,0 +1,269 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-system/src/main/resources/mapper/tyre/BaseInventoryMapper.xml b/ruoyi-system/src/main/resources/mapper/tyre/BaseInventoryMapper.xml index 7bdbc9d9..106762e3 100644 --- a/ruoyi-system/src/main/resources/mapper/tyre/BaseInventoryMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/tyre/BaseInventoryMapper.xml @@ -143,4 +143,10 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" delete from base_inventory where tyre_rfid = #{tyreRfid} - \ No newline at end of file + + delete from base_inventory + where tyre_rfid = #{tyreRfid} + and status = '0' + + + diff --git a/ruoyi-system/src/main/resources/mapper/tyre/BaseTyreMapper.xml b/ruoyi-system/src/main/resources/mapper/tyre/BaseTyreMapper.xml index d6e1f914..55396582 100644 --- a/ruoyi-system/src/main/resources/mapper/tyre/BaseTyreMapper.xml +++ b/ruoyi-system/src/main/resources/mapper/tyre/BaseTyreMapper.xml @@ -9,6 +9,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + @@ -28,15 +29,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" + select d.tyre_id, d.tyre_no, d.self_no, d.tyre_epc, d.tyre_brand, d.tyre_model, d.tyre_level, d.tyre_pattern, - d.grooves, d.pattern_depth, d.tyre_type, d.team, d.create_by, d.create_time, d.update_by, d.update_time, - d.remark, d.car_no, d.wheel_postion, d.dept_id, sd.dept_name + d.grooves, d.pattern_depth, d.tyre_type, d.team, d.inbound_code, d.inventory_status, d.create_by, d.create_time, d.update_by, d.update_time, + d.remark, d.car_no, d.wheel_postion, d.dept_id, tyre_dept.dept_name, + company_dept.dept_name as company, car_dept.dept_name as carTeam from base_tyre d - left join sys_dept sd on sd.dept_id = d.dept_id + + left join base_car bc on bc.car_no = d.car_no + left join sys_dept car_dept on car_dept.dept_id = bc.dept_id + left join sys_dept repair_dept on repair_dept.dept_id = car_dept.parent_id + left join sys_dept company_dept on company_dept.dept_id = repair_dept.parent_id + left join sys_dept tyre_dept on tyre_dept.dept_id = d.dept_id @@ -102,6 +116,7 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" and d.tyre_epc like concat('%', #{tyreEpc}, '%') + + + where d.inbound_code = #{inboundCode} + and d.tyre_epc is not null + and d.tyre_epc <> '' + order by d.tyre_id + + + +