From eeae37b7b781db40127086dd5223db4b1d68e4ef Mon Sep 17 00:00:00 2001 From: tzy Date: Mon, 1 Dec 2025 17:30:26 +0800 Subject: [PATCH] =?UTF-8?q?35R=20=E9=9B=B6=E4=BB=B6=E7=9A=84=E5=8F=98?= =?UTF-8?q?=E9=87=8F=E5=87=BA=E5=9B=BE=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/DeviceSpec35rController.java | 106 +++++++ .../controller/ProcessOrderProController.java | 268 ++++++++++-------- .../ruoyi/system/domain/DeviceSpec35r.java | 129 +++++++++ .../system/domain/bo/DeviceSpec35rBo.java | 180 ++++++++++++ .../system/domain/vo/DeviceSpec35rVo.java | 180 ++++++++++++ .../system/mapper/DeviceSpec35rMapper.java | 15 + .../system/service/IDeviceSpec35rService.java | 49 ++++ .../impl/DeviceSpec35rServiceImpl.java | 133 +++++++++ .../impl/ProcessOrderProServiceImpl.java | 4 +- .../resources/jpg/生产及工艺计划模版.xlsx | Bin 18504 -> 18266 bytes .../mapper/system/DeviceSpec35rMapper.xml | 41 +++ 11 files changed, 977 insertions(+), 128 deletions(-) create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/controller/DeviceSpec35rController.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/DeviceSpec35r.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/DeviceSpec35rBo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeviceSpec35rVo.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/mapper/DeviceSpec35rMapper.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/IDeviceSpec35rService.java create mode 100644 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceSpec35rServiceImpl.java create mode 100644 ruoyi-system/src/main/resources/mapper/system/DeviceSpec35rMapper.xml diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/DeviceSpec35rController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DeviceSpec35rController.java new file mode 100644 index 0000000..55d36a1 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/DeviceSpec35rController.java @@ -0,0 +1,106 @@ +package com.ruoyi.system.controller; + +import java.util.List; +import java.util.Arrays; + +import lombok.RequiredArgsConstructor; +import javax.servlet.http.HttpServletResponse; +import javax.validation.constraints.*; +import cn.dev33.satoken.annotation.SaCheckPermission; +import org.springframework.web.bind.annotation.*; +import org.springframework.validation.annotation.Validated; +import com.ruoyi.common.annotation.RepeatSubmit; +import com.ruoyi.common.annotation.Log; +import com.ruoyi.common.core.controller.BaseController; +import com.ruoyi.common.core.domain.PageQuery; +import com.ruoyi.common.core.domain.R; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import com.ruoyi.common.enums.BusinessType; +import com.ruoyi.common.utils.poi.ExcelUtil; +import com.ruoyi.system.domain.vo.DeviceSpec35rVo; +import com.ruoyi.system.domain.bo.DeviceSpec35rBo; +import com.ruoyi.system.service.IDeviceSpec35rService; +import com.ruoyi.common.core.page.TableDataInfo; + +/** + * 35R设备规格参数 + * + * @author ruoyi + * @date 2025-12-01 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/system/spec35r") +public class DeviceSpec35rController extends BaseController { + + private final IDeviceSpec35rService iDeviceSpec35rService; + + /** + * 查询35R设备规格参数列表 + */ + @SaCheckPermission("system:spec35r:list") + @GetMapping("/list") + public TableDataInfo list(DeviceSpec35rBo bo, PageQuery pageQuery) { + return iDeviceSpec35rService.queryPageList(bo, pageQuery); + } + + /** + * 导出35R设备规格参数列表 + */ + @SaCheckPermission("system:spec35r:export") + @Log(title = "35R设备规格参数", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(DeviceSpec35rBo bo, HttpServletResponse response) { + List list = iDeviceSpec35rService.queryList(bo); + ExcelUtil.exportExcel(list, "35R设备规格参数", DeviceSpec35rVo.class, response); + } + + /** + * 获取35R设备规格参数详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("system:spec35r:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(iDeviceSpec35rService.queryById(id)); + } + + /** + * 新增35R设备规格参数 + */ + @SaCheckPermission("system:spec35r:add") + @Log(title = "35R设备规格参数", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody DeviceSpec35rBo bo) { + return toAjax(iDeviceSpec35rService.insertByBo(bo)); + } + + /** + * 修改35R设备规格参数 + */ + @SaCheckPermission("system:spec35r:edit") + @Log(title = "35R设备规格参数", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody DeviceSpec35rBo bo) { + return toAjax(iDeviceSpec35rService.updateByBo(bo)); + } + + /** + * 删除35R设备规格参数 + * + * @param ids 主键串 + */ + @SaCheckPermission("system:spec35r:remove") + @Log(title = "35R设备规格参数", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(iDeviceSpec35rService.deleteWithValidByIds(Arrays.asList(ids), true)); + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java index 822e101..e8ad875 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/controller/ProcessOrderProController.java @@ -8,6 +8,7 @@ import java.util.*; import cn.hutool.json.JSONUtil; import com.alibaba.excel.EasyExcel; +import com.alibaba.fastjson.JSON; import com.fasterxml.jackson.core.JsonProcessingException; import com.ruoyi.common.excel.DefaultExcelListener; import com.ruoyi.common.exception.ServiceException; @@ -75,6 +76,7 @@ public class ProcessOrderProController extends BaseController { private final IImMaterialService imMaterialService; private final ISafetyStockService iSafetyStockService; private static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy年MM月dd日"); + /** * 查询项目令号列表 */ @@ -370,7 +372,6 @@ public class ProcessOrderProController extends BaseController { } - @SaCheckPermission("system:route:exportRoute") @Log(title = "下载工艺生产表", businessType = BusinessType.EXPORT) @PostMapping("/exportRoute") @@ -391,8 +392,8 @@ public class ProcessOrderProController extends BaseController { } // 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格 - List allDataList = readExcelWithPOI(excelName); - List routeList = readExcelPOIRoute(excelName); + List allDataList = readExcelWithPOI(excelName,orderPro.getProductionOrderNo()); + List routeList = readExcelPOIRoute(excelName,orderPro.getProductionOrderNo()); // 2. 读取原始表数据 List rawDataList = readRawDataTable(rawDataFile); @@ -554,7 +555,7 @@ public class ProcessOrderProController extends BaseController { staticDataMap.put("productionName", orderPro.getProductionName()); //获取工艺数据信息 - List excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList,processDataList,orderPro); + List excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList, processDataList, orderPro); excelDTOList.sort(Comparator.comparing(ProcessRouteExcelDTO::getMaterial, Comparator.nullsLast((m1, m2) -> { // 总装部件优先 boolean isTotal1 = "总装部件".equals(m1); @@ -653,7 +654,7 @@ public class ProcessOrderProController extends BaseController { } } - private List readExcelPOIRoute(String excelName) { + private List readExcelPOIRoute(String excelName,String name) { List resultList = new ArrayList<>(); try (FileInputStream fis = new FileInputStream(excelName); @@ -662,7 +663,7 @@ public class ProcessOrderProController extends BaseController { XSSFSheet sheet = workbook.getSheetAt(6); // 读取第一个sheet // 从第3行开始读取(headRowNumber=2,所以从第3行开始) - for (int rowIndex = 2; rowIndex <= sheet.getLastRowNum(); rowIndex++) { + for (int rowIndex = 3; rowIndex <= sheet.getLastRowNum(); rowIndex++) { XSSFRow row = sheet.getRow(rowIndex); if (row == null) { continue; @@ -671,6 +672,7 @@ public class ProcessOrderProController extends BaseController { // 根据列索引读取数据,保留原始空格 vo.setMaterialCode(getCellValueAsString(row.getCell(0))); // 图号 + vo.setRouteDescription(name); // 图号 vo.setMaterialName(getCellValueAsString(row.getCell(1))); // 名称 vo.setMaterial(getCellValueAsString(row.getCell(2))); // 数量 vo.setDiscWeight(getCellValueAsDouble(row.getCell(3))); @@ -755,7 +757,7 @@ public class ProcessOrderProController extends BaseController { /** * 使用POI直接读取Excel文件,保留前后空格 */ - private List readExcelWithPOI(String excelPath) { + private List readExcelWithPOI(String excelPath,String orderName) { List resultList = new ArrayList<>(); try (FileInputStream fis = new FileInputStream(excelPath); @@ -772,6 +774,7 @@ public class ProcessOrderProController extends BaseController { ProductionOrderVo vo = new ProductionOrderVo(); // 根据列索引读取数据,保留原始空格 vo.setId(getCellValueAsLong(row.getCell(0))); + vo.setProductionOrderNo(orderName); vo.setDrawingNo(getCellValueAsString(row.getCell(1))); // 图号 vo.setDrawingName(getCellValueAsString(row.getCell(2))); // 名称 vo.setQuantity(getCellValueAsDouble(row.getCell(3))); // 数量 @@ -1096,9 +1099,11 @@ public class ProcessOrderProController extends BaseController { } return mapList; } + private String formatDate(Date date) { return date == null ? "" : DATE_FORMAT.format(date); } + /** * 转换工艺VO为Map列表(用于模板) */ @@ -1134,9 +1139,8 @@ public class ProcessOrderProController extends BaseController { } - @SaCheckPermission("system:route:exportRoute") - @Log(title = "下载工艺生产表", businessType = BusinessType.EXPORT) + @Log(title = "下载工艺生产表2", businessType = BusinessType.EXPORT) @PostMapping("/exportRoute2") public void exportRoute2(@RequestParam("id") Long id, HttpServletResponse response) { try { @@ -1155,8 +1159,8 @@ public class ProcessOrderProController extends BaseController { } // 1. 读取第一个sheet的数据list - 使用POI直接读取以保留空格 - List allDataList = readExcelWithPOI(excelName); - List routeList = readExcelPOIRoute(excelName); + List allDataList = readExcelWithPOI(excelName,orderPro.getProductionOrderNo()); + List routeList = readExcelPOIRoute(excelName,orderPro.getProductionOrderNo()); List routes = new ArrayList<>(); List> kingdeeBomRows = new ArrayList<>(); for (ProcessRoute base : routeList) { @@ -1176,44 +1180,27 @@ public class ProcessOrderProController extends BaseController { String bomversion = JdUtil.readGetTheLatestVersion(materialCode); List bomItems = StringUtils.isNotBlank(bomversion) ? JdUtil.getMaterialUseXByVer(bomversion) : Collections.emptyList(); List routeGuDing = JdUtil.getRouteGuDing(materialCode); - if (bomItems != null && !bomItems.isEmpty()) { - for (MaterialUseDTO b : bomItems) { - Map bomMap = new HashMap<>(); - bomMap.put("routeDescription", base.getRouteDescription()); - bomMap.put("materialCode", base.getMaterialCode()); - bomMap.put("materialName", base.getMaterialName()); - bomMap.put("material", base.getMaterial()); - bomMap.put("discWeight", base.getDiscWeight()); - bomMap.put("rawMaterialCode", b.getMaterialCode()); - bomMap.put("rawMaterialName", b.getMaterialName()); - bomMap.put("bomMaterial", b.getCaizhi()); - bomMap.put("bomDanZhong", b.getDanzhong()); - bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? (b.getFenzi() + "/" + b.getFenmu()) : null); - bomMap.put("bomUnit", b.getChildUnit()); - kingdeeBomRows.add(bomMap); - } - } + if (routeGuDing != null && !routeGuDing.isEmpty()) { - routeGuDing.stream() - .forEach(r -> { - ProcessRoute item = new ProcessRoute(); - item.setRouteDescription(base.getRouteDescription()); - item.setMaterialCode(base.getMaterialCode()); - item.setMaterialName(base.getMaterialName()); - item.setMaterial(base.getMaterial()); - item.setDiscWeight(base.getDiscWeight()); - item.setUnitQuantity(base.getUnitQuantity()); - item.setBatchQuantity(base.getBatchQuantity()); - // 不写入BOM字段,保持纯工艺数据行 - item.setProcessNo(r.getProcessNo()); - item.setWorkCenter(r.getWorkCenter()); - item.setProcessName(r.getProcessName()); - item.setProcessDescription(r.getProcessDescription()); - item.setProcessControl(r.getProcessControl()); - item.setActivityDuration(r.getActivityDuration()); - item.setActivityUnit(r.getActivityUnit()); - routes.add(item); - }); + routeGuDing.stream().forEach(r -> { + ProcessRoute item = new ProcessRoute(); + item.setRouteDescription(base.getRouteDescription()); + item.setMaterialCode(base.getMaterialCode()); + item.setMaterialName(base.getMaterialName()); + item.setMaterial(base.getMaterial()); + item.setDiscWeight(base.getDiscWeight()); + item.setUnitQuantity(base.getUnitQuantity()); + item.setBatchQuantity(base.getBatchQuantity()); + // 不写入BOM字段,保持纯工艺数据行 + item.setProcessNo(r.getProcessNo()); + item.setWorkCenter(r.getWorkCenter()); + item.setProcessName(r.getProcessName()); + item.setProcessDescription(r.getProcessDescription()); + item.setProcessControl(r.getProcessControl()); + item.setActivityDuration(r.getActivityDuration()); + item.setActivityUnit(r.getActivityUnit()); + routes.add(item); + }); } else { ProcessRoute item = new ProcessRoute(); item.setRouteDescription(base.getRouteDescription()); @@ -1226,6 +1213,32 @@ public class ProcessOrderProController extends BaseController { // 不写入BOM字段,保持纯工艺数据行 routes.add(item); } + if (bomItems != null && !bomItems.isEmpty()) { + if ("总装部件".equals(Objects.toString(base.getMaterial(), "").trim())) { + + } else { + for (MaterialUseDTO b : bomItems) { + Map bomMap = new HashMap<>(); + bomMap.put("routeDescription", base.getRouteDescription()); + bomMap.put("materialCode", base.getMaterialCode()); + bomMap.put("materialName", base.getMaterialName()); + bomMap.put("material", base.getMaterial()); + bomMap.put("discWeight", base.getDiscWeight()); + bomMap.put("rawMaterialCode", b.getMaterialCode()); + bomMap.put("rawMaterialName", b.getMaterialName()); + bomMap.put("bomMaterial", b.getCaizhi()); + bomMap.put("bomDanZhong", b.getDanzhong()); + if (b.getChildUnit().equals("根")) { + bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? (b.getFenzi() + "/" + b.getFenmu()) : null); + } else { + bomMap.put("discUsage", (b.getFenzi() != null && b.getFenmu() != null) ? b.getFenzi() : null); + } + + bomMap.put("bomUnit", b.getChildUnit()); + kingdeeBomRows.add(bomMap); + } + } + } } // 用生成的 routes 替换原始 routeList,保持原序展开后的结构用于后续导出 routeList = routes; @@ -1282,10 +1295,8 @@ public class ProcessOrderProController extends BaseController { // 电气外包分类条件:物料编码开头空格/特定前缀 或 备注包含"外购" if (materialCode.startsWith(" ") - || materialCode.startsWith("009301") || materialCode.startsWith("009999") - || materialCode.startsWith("017003") || materialCode.startsWith("017002") - || materialCode.startsWith("009001") || materialCode.startsWith("009081") - || (remark != null && remark.contains("外购"))) { + || materialCode.startsWith("009301") || materialCode.startsWith("009999") || materialCode.startsWith("017003") || materialCode.startsWith("017002") + || materialCode.startsWith("009001") || materialCode.startsWith("009081") || (remark != null && remark.contains("外购"))) { // 过滤安全库存:如果属于安全库存,则进入工艺数据列表 Boolean isSafeStock = iSafetyStockService.isSafeCode(materialCode.trim()); if (isSafeStock) { @@ -1387,25 +1398,6 @@ public class ProcessOrderProController extends BaseController { staticDataMap.put("productionOrderNo", orderPro.getProductionOrderNo()); staticDataMap.put("productionName", orderPro.getProductionName()); - //获取工艺数据信息 - /* List excelDTOList = iProcessOrderProService.getRouteAndBomDetail(routeList,processDataList,orderPro); - excelDTOList.sort(Comparator.comparing(ProcessRouteExcelDTO::getMaterial, Comparator.nullsLast((m1, m2) -> { - // 总装部件优先 - boolean isTotal1 = "总装部件".equals(m1); - boolean isTotal2 = "总装部件".equals(m2); - if (isTotal1 && !isTotal2) return -1; - if (!isTotal1 && isTotal2) return 1; - if (isTotal1 && isTotal2) return 0; - // 其他材质按字母顺序排序 - if (m1 == null && m2 == null) return 0; - if (m1 == null) return 1; - if (m2 == null) return -1; - return m1.compareTo(m2); - }) - ).thenComparing( - ProcessRouteExcelDTO::getMaterialCode, - Comparator.nullsLast(new VersionComparator()) - ));*/ // 准备动态数据映射 List dynamicDataMappingList = new ArrayList<>(); @@ -1502,61 +1494,28 @@ public class ProcessOrderProController extends BaseController { * 合并工艺路线与金蝶BOM行,按物料编码分组生成统一的 RouteBomData 列表 * 每条记录包含两类:rowType=route(工艺行)或 rowType=bom(BOM行),以便模板在同一块中连续展示 */ - private List> convertRouteBomToMapList(List routeDataList, - List> kingdeeBomRows) { + private List> convertRouteBomToMapList(List routeDataList, List> kingdeeBomRows) { Map>> grouped = new LinkedHashMap<>(); - - // 先按工艺数据建立分组与顺序 - for (ProcessRoute item : routeDataList) { - String mcode = item.getMaterialCode(); - if (mcode == null) mcode = ""; - grouped.computeIfAbsent(mcode, k -> new ArrayList<>()); - - Map map = new HashMap<>(); - map.put("rowType", "route"); - map.put("routeDescription", item.getRouteDescription()); - map.put("materialCode", item.getMaterialCode()); - map.put("materialName", item.getMaterialName()); - map.put("material", item.getMaterial()); - map.put("discWeight", item.getDiscWeight()); - map.put("processNo", item.getProcessNo()); - map.put("workCenter", item.getWorkCenter()); - map.put("processName", item.getProcessName()); - map.put("processDescription", item.getProcessDescription()); - map.put("processControl", item.getProcessControl()); - map.put("activityDuration", item.getActivityDuration()); - map.put("activityUnit", item.getActivityUnit()); - map.put("unitQuantity", item.getUnitQuantity()); - map.put("batchQuantity", item.getBatchQuantity()); - map.put("firstBatchQuantity", item.getFirstBatchQuantity()); - map.put("planStartTime", formatDate(item.getPlanStartTime())); - map.put("planEndTime", formatDate(item.getPlanEndTime())); - map.put("xuStartTime", formatDate(item.getXuStartTime())); - map.put("xuEndTime", formatDate(item.getXuEndTime())); - - // BOM占位(当前行类型为工艺,BOM字段置空) - map.put("rawMaterialCode", ""); - map.put("rawMaterialName", ""); - map.put("bomMaterial", ""); - map.put("bomDanZhong", ""); - map.put("discUsage", ""); - map.put("bomUnit", ""); - - grouped.get(mcode).add(map); - } - // 追加BOM数据到对应物料分组;若该物料此前未出现,则在最后新增一个分组 for (Map row : kingdeeBomRows) { - String mcode = Objects.toString(row.get("materialCode"), ""); + String mcode = Objects.toString(row.get("materialCode"), "").trim(); + String childCode = Objects.toString(row.get("rawMaterialCode"), "").trim(); + String parentMaterial = Objects.toString(row.get("material"), "").trim(); + if (mcode.isEmpty() || childCode.isEmpty()) { + continue; + } + if ("总装部件".equals(parentMaterial)) { + continue; + } grouped.computeIfAbsent(mcode, k -> new ArrayList<>()); Map map = new HashMap<>(); map.put("rowType", "bom"); - map.put("routeDescription", row.get("routeDescription")); - map.put("materialCode", row.get("materialCode")); - map.put("materialName", row.get("materialName")); - map.put("material", row.get("material")); - map.put("discWeight", row.get("discWeight")); + map.put("routeDescription", Objects.toString(row.get("routeDescription"), "")); + map.put("materialCode", mcode); + map.put("materialName", Objects.toString(row.get("materialName"), "")); + map.put("material", Objects.toString(row.get("material"), "")); + map.put("discWeight", Objects.toString(row.get("discWeight"), "")); // 工艺占位(当前行类型为BOM,工艺字段置空) map.put("processNo", ""); @@ -1575,12 +1534,71 @@ public class ProcessOrderProController extends BaseController { map.put("xuEndTime", ""); // BOM具体字段 - map.put("rawMaterialCode", row.get("rawMaterialCode")); - map.put("rawMaterialName", row.get("rawMaterialName")); - map.put("bomMaterial", row.get("bomMaterial")); - map.put("bomDanZhong", row.get("bomDanZhong")); - map.put("discUsage", row.get("discUsage")); - map.put("bomUnit", row.get("bomUnit")); + map.put("rawMaterialCode", childCode); + map.put("rawMaterialName", Objects.toString(row.get("rawMaterialName"), "")); + map.put("bomMaterial", Objects.toString(row.get("bomMaterial"), "")); + map.put("bomDanZhong", Objects.toString(row.get("bomDanZhong"), "")); + map.put("discUsage", Objects.toString(row.get("discUsage"), "")); + map.put("bomUnit", Objects.toString(row.get("bomUnit"), "")); + + grouped.get(mcode).add(map); + } + // 先按工艺数据建立分组与顺序 + for (ProcessRoute item : routeDataList) { + String mcode = Objects.toString(item.getMaterialCode(), "").trim(); + boolean noRoute = + Objects.toString(item.getMaterialCode(), "").trim().isEmpty() && + Objects.toString(item.getMaterialName(), "").trim().isEmpty() && + Objects.toString(item.getMaterial(), "").trim().isEmpty() && + item.getDiscWeight() == null && + item.getProcessNo() == null && + Objects.toString(item.getWorkCenter(), "").trim().isEmpty() && + Objects.toString(item.getProcessName(), "").trim().isEmpty() && + Objects.toString(item.getProcessDescription(), "").trim().isEmpty() && + Objects.toString(item.getProcessControl(), "").trim().isEmpty() && + item.getActivityDuration() == null && + Objects.toString(item.getActivityUnit(), "").trim().isEmpty() && + item.getUnitQuantity() == null && + item.getBatchQuantity() == null && + Objects.toString(item.getFirstBatchQuantity(), "").trim().isEmpty() && + item.getPlanStartTime() == null && + item.getPlanEndTime() == null && + item.getXuStartTime() == null && + item.getXuEndTime() == null; + if (noRoute) { + continue; + } + grouped.computeIfAbsent(mcode, k -> new ArrayList<>()); + + Map map = new HashMap<>(); + map.put("rowType", "route"); + map.put("routeDescription", Objects.toString(item.getRouteDescription(), "")); + map.put("materialCode", mcode); + map.put("materialName", Objects.toString(item.getMaterialName(), "")); + map.put("material", Objects.toString(item.getMaterial(), "")); + map.put("discWeight", Objects.toString(item.getDiscWeight(), "")); + map.put("processNo", item.getProcessNo()); + map.put("workCenter", Objects.toString(item.getWorkCenter(), "")); + map.put("processName", Objects.toString(item.getProcessName(), "")); + map.put("processDescription", Objects.toString(item.getProcessDescription(), "")); + map.put("processControl", Objects.toString(item.getProcessControl(), "")); + map.put("activityDuration", Objects.toString(item.getActivityDuration(), "")); + map.put("activityUnit", Objects.toString(item.getActivityUnit(), "")); + map.put("unitQuantity", item.getUnitQuantity()); + map.put("batchQuantity", item.getBatchQuantity()); + map.put("firstBatchQuantity", Objects.toString(item.getFirstBatchQuantity(), "")); + map.put("planStartTime", formatDate(item.getPlanStartTime())); + map.put("planEndTime", formatDate(item.getPlanEndTime())); + map.put("xuStartTime", formatDate(item.getXuStartTime())); + map.put("xuEndTime", formatDate(item.getXuEndTime())); + + // BOM占位(当前行类型为工艺,BOM字段置空) + map.put("rawMaterialCode", ""); + map.put("rawMaterialName", ""); + map.put("bomMaterial", ""); + map.put("bomDanZhong", ""); + map.put("discUsage", ""); + map.put("bomUnit", ""); grouped.get(mcode).add(map); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/DeviceSpec35r.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DeviceSpec35r.java new file mode 100644 index 0000000..2866ee0 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/DeviceSpec35r.java @@ -0,0 +1,129 @@ +package com.ruoyi.system.domain; + +import com.baomidou.mybatisplus.annotation.*; +import com.ruoyi.common.core.domain.BaseEntity; +import lombok.Data; +import lombok.EqualsAndHashCode; + +import java.math.BigDecimal; + +/** + * 35R设备规格参数对象 device_spec_35r + * + * @author ruoyi + * @date 2025-12-01 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("device_spec_35r") +public class DeviceSpec35r extends BaseEntity { + + private static final long serialVersionUID=1L; + + /** + * 主键ID + */ + @TableId(value = "id") + private Long id; + /** + * 行程变量 + */ + private String travelLength; + /** + * 类型 + */ + private String itemType; + /** + * 轴向 + */ + private String axialType; + /** + * 箱体 + */ + private String boxType; + /** + * 行程 + */ + private Long V1; + /** + * 设备总长 + */ + private Long V2; + /** + * 地脚位置1 + */ + private Long V3; + /** + * 箱体装配长度 + */ + private Long V5; + /** + * 箱体地脚位置1 + */ + private Long V6; + /** + * 铝箱长度1 + */ + private Long V8; + /** + * 铝箱1重量 + */ + private BigDecimal G1; + /** + * 铝箱长度2 + */ + private BigDecimal V9; + /** + * 铝箱2重量 + */ + private BigDecimal G2; + /** + * 导向条长度1 + */ + private Long V10; + /** + * 导向条1单重 + */ + private BigDecimal G5; + /** + * 导向条长度2 + */ + private Long V12; + /** + * 导向条2单重 + */ + private BigDecimal G6; + /** + * 导向条长度3 + */ + private Long V14; + /** + * 导向条3单重 + */ + private BigDecimal G7; + /** + * 轴挡 + */ + private Long V41; + /** + * 35E链条滚轮 + */ + private Long V42; + /** + * 35E垫圈 + */ + private Long V43; + /** + * 35R链节轴2 + */ + private Long V44; + /** + * 35E链节轴2 + */ + private Long V45; + /** + * 35E链板 + */ + private Long V46; + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/DeviceSpec35rBo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/DeviceSpec35rBo.java new file mode 100644 index 0000000..4d1bd82 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/bo/DeviceSpec35rBo.java @@ -0,0 +1,180 @@ +package com.ruoyi.system.domain.bo; + +import com.ruoyi.common.core.domain.BaseEntity; +import com.ruoyi.common.core.validate.AddGroup; +import com.ruoyi.common.core.validate.EditGroup; +import lombok.Data; +import lombok.EqualsAndHashCode; +import javax.validation.constraints.*; + +import java.math.BigDecimal; + +/** + * 35R设备规格参数业务对象 device_spec_35r + * + * @author ruoyi + * @date 2025-12-01 + */ + +@Data +@EqualsAndHashCode(callSuper = true) +public class DeviceSpec35rBo extends BaseEntity { + + /** + * 主键ID + */ + @NotNull(message = "主键ID不能为空", groups = { EditGroup.class }) + private Long id; + + /** + * 行程变量 + */ + @NotBlank(message = "行程变量不能为空", groups = { AddGroup.class, EditGroup.class }) + private String travelLength; + + /** + * 类型 + */ + @NotBlank(message = "类型不能为空", groups = { AddGroup.class, EditGroup.class }) + private String itemType; + + /** + * 轴向 + */ + @NotBlank(message = "轴向不能为空", groups = { AddGroup.class, EditGroup.class }) + private String axialType; + + /** + * 箱体 + */ + @NotBlank(message = "箱体不能为空", groups = { AddGroup.class, EditGroup.class }) + private String boxType; + + /** + * 行程 + */ + @NotNull(message = "行程不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V1; + + /** + * 设备总长 + */ + @NotNull(message = "设备总长不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V2; + + /** + * 地脚位置1 + */ + @NotNull(message = "地脚位置1不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V3; + + /** + * 箱体装配长度 + */ + @NotNull(message = "箱体装配长度不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V5; + + /** + * 箱体地脚位置1 + */ + @NotNull(message = "箱体地脚位置1不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V6; + + /** + * 铝箱长度1 + */ + @NotNull(message = "铝箱长度1不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V8; + + /** + * 铝箱1重量 + */ + @NotNull(message = "铝箱1重量不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal G1; + + /** + * 铝箱长度2 + */ + @NotNull(message = "铝箱长度2不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal V9; + + /** + * 铝箱2重量 + */ + @NotNull(message = "铝箱2重量不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal G2; + + /** + * 导向条长度1 + */ + @NotNull(message = "导向条长度1不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V10; + + /** + * 导向条1单重 + */ + @NotNull(message = "导向条1单重不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal G5; + + /** + * 导向条长度2 + */ + @NotNull(message = "导向条长度2不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V12; + + /** + * 导向条2单重 + */ + @NotNull(message = "导向条2单重不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal G6; + + /** + * 导向条长度3 + */ + @NotNull(message = "导向条长度3不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V14; + + /** + * 导向条3单重 + */ + @NotNull(message = "导向条3单重不能为空", groups = { AddGroup.class, EditGroup.class }) + private BigDecimal G7; + + /** + * 轴挡 + */ + @NotNull(message = "轴挡不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V41; + + /** + * 35E链条滚轮 + */ + @NotNull(message = "35E链条滚轮不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V42; + + /** + * 35E垫圈 + */ + @NotNull(message = "35E垫圈不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V43; + + /** + * 35R链节轴2 + */ + @NotNull(message = "35R链节轴2不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V44; + + /** + * 35E链节轴2 + */ + @NotNull(message = "35E链节轴2不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V45; + + /** + * 35E链板 + */ + @NotNull(message = "35E链板不能为空", groups = { AddGroup.class, EditGroup.class }) + private Long V46; + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeviceSpec35rVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeviceSpec35rVo.java new file mode 100644 index 0000000..86766b6 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/DeviceSpec35rVo.java @@ -0,0 +1,180 @@ +package com.ruoyi.system.domain.vo; + +import java.math.BigDecimal; +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import com.ruoyi.common.annotation.ExcelDictFormat; +import com.ruoyi.common.convert.ExcelDictConvert; +import lombok.Data; + + +/** + * 35R设备规格参数视图对象 device_spec_35r + * + * @author ruoyi + * @date 2025-12-01 + */ +@Data +@ExcelIgnoreUnannotated +public class DeviceSpec35rVo { + + private static final long serialVersionUID = 1L; + + /** + * 主键ID + */ + @ExcelProperty(value = "主键ID") + private Long id; + + /** + * 行程变量 + */ + @ExcelProperty(value = "行程变量") + private String travelLength; + + /** + * 类型 + */ + @ExcelProperty(value = "类型") + private String itemType; + + /** + * 轴向 + */ + @ExcelProperty(value = "轴向") + private String axialType; + + /** + * 箱体 + */ + @ExcelProperty(value = "箱体") + private String boxType; + + /** + * 行程 + */ + @ExcelProperty(value = "行程") + private Long V1; + + /** + * 设备总长 + */ + @ExcelProperty(value = "设备总长") + private Long V2; + + /** + * 地脚位置1 + */ + @ExcelProperty(value = "地脚位置1") + private Long V3; + + /** + * 箱体装配长度 + */ + @ExcelProperty(value = "箱体装配长度") + private Long V5; + + /** + * 箱体地脚位置1 + */ + @ExcelProperty(value = "箱体地脚位置1") + private Long V6; + + /** + * 铝箱长度1 + */ + @ExcelProperty(value = "铝箱长度1") + private Long V8; + + /** + * 铝箱1重量 + */ + @ExcelProperty(value = "铝箱1重量") + private BigDecimal G1; + + /** + * 铝箱长度2 + */ + @ExcelProperty(value = "铝箱长度2") + private BigDecimal V9; + + /** + * 铝箱2重量 + */ + @ExcelProperty(value = "铝箱2重量") + private BigDecimal G2; + + /** + * 导向条长度1 + */ + @ExcelProperty(value = "导向条长度1") + private Long V10; + + /** + * 导向条1单重 + */ + @ExcelProperty(value = "导向条1单重") + private BigDecimal G5; + + /** + * 导向条长度2 + */ + @ExcelProperty(value = "导向条长度2") + private Long V12; + + /** + * 导向条2单重 + */ + @ExcelProperty(value = "导向条2单重") + private BigDecimal G6; + + /** + * 导向条长度3 + */ + @ExcelProperty(value = "导向条长度3") + private Long V14; + + /** + * 导向条3单重 + */ + @ExcelProperty(value = "导向条3单重") + private BigDecimal G7; + + /** + * 轴挡 + */ + @ExcelProperty(value = "轴挡") + private Long V41; + + /** + * 35E链条滚轮 + */ + @ExcelProperty(value = "35E链条滚轮") + private Long V42; + + /** + * 35E垫圈 + */ + @ExcelProperty(value = "35E垫圈") + private Long V43; + + /** + * 35R链节轴2 + */ + @ExcelProperty(value = "35R链节轴2") + private Long V44; + + /** + * 35E链节轴2 + */ + @ExcelProperty(value = "35E链节轴2") + private Long V45; + + /** + * 35E链板 + */ + @ExcelProperty(value = "35E链板") + private Long V46; + + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DeviceSpec35rMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DeviceSpec35rMapper.java new file mode 100644 index 0000000..f29f872 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/DeviceSpec35rMapper.java @@ -0,0 +1,15 @@ +package com.ruoyi.system.mapper; + +import com.ruoyi.system.domain.DeviceSpec35r; +import com.ruoyi.system.domain.vo.DeviceSpec35rVo; +import com.ruoyi.common.core.mapper.BaseMapperPlus; + +/** + * 35R设备规格参数Mapper接口 + * + * @author ruoyi + * @date 2025-12-01 + */ +public interface DeviceSpec35rMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/IDeviceSpec35rService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDeviceSpec35rService.java new file mode 100644 index 0000000..760e4d2 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/IDeviceSpec35rService.java @@ -0,0 +1,49 @@ +package com.ruoyi.system.service; + +import com.ruoyi.system.domain.DeviceSpec35r; +import com.ruoyi.system.domain.vo.DeviceSpec35rVo; +import com.ruoyi.system.domain.bo.DeviceSpec35rBo; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; + +import java.util.Collection; +import java.util.List; + +/** + * 35R设备规格参数Service接口 + * + * @author ruoyi + * @date 2025-12-01 + */ +public interface IDeviceSpec35rService { + + /** + * 查询35R设备规格参数 + */ + DeviceSpec35rVo queryById(Long id); + + /** + * 查询35R设备规格参数列表 + */ + TableDataInfo queryPageList(DeviceSpec35rBo bo, PageQuery pageQuery); + + /** + * 查询35R设备规格参数列表 + */ + List queryList(DeviceSpec35rBo bo); + + /** + * 新增35R设备规格参数 + */ + Boolean insertByBo(DeviceSpec35rBo bo); + + /** + * 修改35R设备规格参数 + */ + Boolean updateByBo(DeviceSpec35rBo bo); + + /** + * 校验并批量删除35R设备规格参数信息 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceSpec35rServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceSpec35rServiceImpl.java new file mode 100644 index 0000000..4572799 --- /dev/null +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/DeviceSpec35rServiceImpl.java @@ -0,0 +1,133 @@ +package com.ruoyi.system.service.impl; + +import cn.hutool.core.bean.BeanUtil; +import com.ruoyi.common.core.page.TableDataInfo; +import com.ruoyi.common.core.domain.PageQuery; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.ruoyi.common.utils.StringUtils; +import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Service; +import com.ruoyi.system.domain.bo.DeviceSpec35rBo; +import com.ruoyi.system.domain.vo.DeviceSpec35rVo; +import com.ruoyi.system.domain.DeviceSpec35r; +import com.ruoyi.system.mapper.DeviceSpec35rMapper; +import com.ruoyi.system.service.IDeviceSpec35rService; + +import java.util.List; +import java.util.Map; +import java.util.Collection; + +/** + * 35R设备规格参数Service业务层处理 + * + * @author ruoyi + * @date 2025-12-01 + */ +@RequiredArgsConstructor +@Service +public class DeviceSpec35rServiceImpl implements IDeviceSpec35rService { + + private final DeviceSpec35rMapper baseMapper; + + /** + * 查询35R设备规格参数 + */ + @Override + public DeviceSpec35rVo queryById(Long id){ + return baseMapper.selectVoById(id); + } + + /** + * 查询35R设备规格参数列表 + */ + @Override + public TableDataInfo queryPageList(DeviceSpec35rBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询35R设备规格参数列表 + */ + @Override + public List queryList(DeviceSpec35rBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(DeviceSpec35rBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getTravelLength()), DeviceSpec35r::getTravelLength, bo.getTravelLength()); + lqw.eq(StringUtils.isNotBlank(bo.getItemType()), DeviceSpec35r::getItemType, bo.getItemType()); + lqw.eq(StringUtils.isNotBlank(bo.getAxialType()), DeviceSpec35r::getAxialType, bo.getAxialType()); + lqw.eq(StringUtils.isNotBlank(bo.getBoxType()), DeviceSpec35r::getBoxType, bo.getBoxType()); + lqw.eq(bo.getV1() != null, DeviceSpec35r::getV1, bo.getV1()); + lqw.eq(bo.getV2() != null, DeviceSpec35r::getV2, bo.getV2()); + lqw.eq(bo.getV3() != null, DeviceSpec35r::getV3, bo.getV3()); + lqw.eq(bo.getV5() != null, DeviceSpec35r::getV5, bo.getV5()); + lqw.eq(bo.getV6() != null, DeviceSpec35r::getV6, bo.getV6()); + lqw.eq(bo.getV8() != null, DeviceSpec35r::getV8, bo.getV8()); + lqw.eq(bo.getG1() != null, DeviceSpec35r::getG1, bo.getG1()); + lqw.eq(bo.getV9() != null, DeviceSpec35r::getV9, bo.getV9()); + lqw.eq(bo.getG2() != null, DeviceSpec35r::getG2, bo.getG2()); + lqw.eq(bo.getV10() != null, DeviceSpec35r::getV10, bo.getV10()); + lqw.eq(bo.getG5() != null, DeviceSpec35r::getG5, bo.getG5()); + lqw.eq(bo.getV12() != null, DeviceSpec35r::getV12, bo.getV12()); + lqw.eq(bo.getG6() != null, DeviceSpec35r::getG6, bo.getG6()); + lqw.eq(bo.getV14() != null, DeviceSpec35r::getV14, bo.getV14()); + lqw.eq(bo.getG7() != null, DeviceSpec35r::getG7, bo.getG7()); + lqw.eq(bo.getV41() != null, DeviceSpec35r::getV41, bo.getV41()); + lqw.eq(bo.getV42() != null, DeviceSpec35r::getV42, bo.getV42()); + lqw.eq(bo.getV43() != null, DeviceSpec35r::getV43, bo.getV43()); + lqw.eq(bo.getV44() != null, DeviceSpec35r::getV44, bo.getV44()); + lqw.eq(bo.getV45() != null, DeviceSpec35r::getV45, bo.getV45()); + lqw.eq(bo.getV46() != null, DeviceSpec35r::getV46, bo.getV46()); + return lqw; + } + + /** + * 新增35R设备规格参数 + */ + @Override + public Boolean insertByBo(DeviceSpec35rBo bo) { + DeviceSpec35r add = BeanUtil.toBean(bo, DeviceSpec35r.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改35R设备规格参数 + */ + @Override + public Boolean updateByBo(DeviceSpec35rBo bo) { + DeviceSpec35r update = BeanUtil.toBean(bo, DeviceSpec35r.class); + validEntityBeforeSave(update); + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(DeviceSpec35r entity){ + //TODO 做一些数据校验,如唯一约束 + } + + /** + * 批量删除35R设备规格参数 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + if(isValid){ + //TODO 做一些业务上的校验,判断是否需要校验 + } + return baseMapper.deleteBatchIds(ids) > 0; + } +} diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java index b039210..aef41c0 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/ProcessOrderProServiceImpl.java @@ -424,6 +424,7 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { // 批量查询PcRigidChain,避免N+1问题 Set figureNumbers = productionOrders.stream().map(FigureSave::getFigureNumber).collect(Collectors.toSet()); + Map rigidChainMap = pcRigidChainService.selectByTypeNames(figureNumbers).stream().collect(Collectors.toMap(PcRigidChain::getTypeName, Function.identity())); return productionOrders.stream().map(figureSave -> buildProductInfo(figureSave, rigidChainMap.get(figureSave.getFigureNumber()))).collect(Collectors.toList()); @@ -434,12 +435,9 @@ public class ProcessOrderProServiceImpl implements IProcessOrderProService { productInfo.setAssembledrawing(figureSave.getFigureNumber()); productInfo.setNumber(String.valueOf(figureSave.getFigureNum())); productInfo.setSourcefile(figureSave.getDrawPath().replace("/", "\\")); - log.info("项目生产令号为:{}查询产品型号信息: {}+ 产品名称: {}", figureSave.getProductionCode(), figureSave.getFigureNumber(), figureSave.getFigureName()); - DataInfo datainfo = buildDataInfo(rigidChain); productInfo.setVars(datainfo); - return productInfo; } diff --git a/ruoyi-system/src/main/resources/jpg/生产及工艺计划模版.xlsx b/ruoyi-system/src/main/resources/jpg/生产及工艺计划模版.xlsx index 7f72a343d2580c96e6024997348a2380b7951787..1fcdf7fd5d8c678112c0151b26590fc064d7b95a 100644 GIT binary patch delta 12774 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 delta 12956 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 C8!D>+ diff --git a/ruoyi-system/src/main/resources/mapper/system/DeviceSpec35rMapper.xml b/ruoyi-system/src/main/resources/mapper/system/DeviceSpec35rMapper.xml new file mode 100644 index 0000000..fec99dc --- /dev/null +++ b/ruoyi-system/src/main/resources/mapper/system/DeviceSpec35rMapper.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +