package cn.iocoder.yudao.module.mes.controller.admin.pro.route;
|
|
import cn.hutool.core.collection.CollUtil;
|
import cn.hutool.core.collection.ListUtil;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.util.collection.MapUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.process.MesProProcessBomItemVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.process.MesProProcessOutputItemVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.process.MesProRouteProcessRespVO;
|
import cn.iocoder.yudao.module.mes.controller.admin.pro.route.vo.process.MesProRouteProcessSaveReqVO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.process.MesProProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProcessDO;
|
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.route.MesProRouteProductBomDO;
|
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
|
import cn.iocoder.yudao.module.mes.service.pro.process.MesProProcessService;
|
import cn.iocoder.yudao.module.mes.service.pro.route.MesProRouteProcessService;
|
import io.swagger.v3.oas.annotations.Operation;
|
import io.swagger.v3.oas.annotations.Parameter;
|
import io.swagger.v3.oas.annotations.tags.Tag;
|
import jakarta.annotation.Resource;
|
import jakarta.validation.Valid;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.validation.annotation.Validated;
|
import org.springframework.web.bind.annotation.*;
|
|
import java.util.*;
|
import java.util.stream.Collectors;
|
|
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertMap;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
|
|
@Tag(name = "管理后台 - MES 工艺路线工序")
|
@RestController
|
@RequestMapping("/mes/pro/route-process")
|
@Validated
|
public class MesProRouteProcessController {
|
|
@Resource
|
private MesProRouteProcessService routeProcessService;
|
@Resource
|
private MesProProcessService processService;
|
@Resource
|
private MesMdItemService mdItemService;
|
|
@PostMapping("/create")
|
@Operation(summary = "创建工艺路线工序")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:update')")
|
public CommonResult<Long> createRouteProcess(@Valid @RequestBody MesProRouteProcessSaveReqVO createReqVO) {
|
return success(routeProcessService.createRouteProcess(createReqVO));
|
}
|
|
@PutMapping("/update")
|
@Operation(summary = "更新工艺路线工序")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:update')")
|
public CommonResult<Boolean> updateRouteProcess(@Valid @RequestBody MesProRouteProcessSaveReqVO updateReqVO) {
|
routeProcessService.updateRouteProcess(updateReqVO);
|
return success(true);
|
}
|
|
@DeleteMapping("/delete")
|
@Operation(summary = "删除工艺路线工序")
|
@Parameter(name = "id", description = "编号", required = true)
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:update')")
|
public CommonResult<Boolean> deleteRouteProcess(@RequestParam("id") Long id) {
|
routeProcessService.deleteRouteProcess(id);
|
return success(true);
|
}
|
|
@GetMapping("/get")
|
@Operation(summary = "获得工艺路线工序")
|
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:query')")
|
public CommonResult<MesProRouteProcessRespVO> getRouteProcess(@RequestParam("id") Long id) {
|
MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcess(id);
|
return success(buildRouteProcessRespVO(routeProcess));
|
}
|
|
@GetMapping("/list-by-product")
|
@Operation(summary = "按产品获得工序列表", description = "根据产品查找关联的工艺路线,返回该路线的工序列表(含各工序的投料BOM)")
|
@Parameter(name = "productId", description = "产品编号", required = true, example = "1")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:query')")
|
public CommonResult<List<MesProRouteProcessRespVO>> getRouteProcessListByProduct(@RequestParam("productId") Long productId) {
|
List<MesProRouteProcessDO> list = routeProcessService.getRouteProcessListByProductId(productId);
|
List<MesProRouteProcessRespVO> result = buildRouteProcessRespVOList(list);
|
|
// 查询配置投料并按工序填充
|
Map<Long, List<MesProRouteProductBomDO>> bomByProcess = routeProcessService.getRouteProcessBomMapByProductId(productId);
|
if (!bomByProcess.isEmpty()) {
|
Set<Long> itemIds = bomByProcess.values().stream()
|
.flatMap(List::stream)
|
.map(MesProRouteProductBomDO::getItemId)
|
.collect(Collectors.toSet());
|
Map<Long, MesMdItemDO> itemMap = mdItemService.getItemMap(itemIds);
|
for (MesProRouteProcessRespVO vo : result) {
|
List<MesProRouteProductBomDO> processBoms = bomByProcess.get(vo.getProcessId());
|
if (CollUtil.isNotEmpty(processBoms)) {
|
vo.setBomItems(processBoms.stream().map(bom -> {
|
MesProProcessBomItemVO itemVO = new MesProProcessBomItemVO();
|
itemVO.setItemId(bom.getItemId());
|
itemVO.setQuantity(bom.getQuantity());
|
itemVO.setRemark(bom.getRemark());
|
MesMdItemDO item = itemMap.get(bom.getItemId());
|
if (item != null) {
|
itemVO.setItemCode(item.getCode());
|
itemVO.setItemName(item.getName());
|
}
|
return itemVO;
|
}).collect(Collectors.toList()));
|
}
|
}
|
}
|
return success(result);
|
}
|
|
@GetMapping("/list-by-route")
|
@Operation(summary = "按工艺路线获得工序列表")
|
@Parameter(name = "routeId", description = "工艺路线编号", required = true, example = "1")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:query')")
|
public CommonResult<List<MesProRouteProcessRespVO>> getRouteProcessListByRoute(@RequestParam("routeId") Long routeId) {
|
List<MesProRouteProcessDO> list = routeProcessService.getRouteProcessListByRouteId(routeId);
|
return success(buildRouteProcessRespVOList(list));
|
}
|
|
@GetMapping("/get-by-route-and-process")
|
@Operation(summary = "按工艺路线+工序获得工序配置")
|
@Parameter(name = "routeId", description = "工艺路线编号", required = true, example = "1")
|
@Parameter(name = "processId", description = "工序编号", required = true, example = "1")
|
@PreAuthorize("@ss.hasPermission('mes:pro-route:query')")
|
public CommonResult<MesProRouteProcessRespVO> getRouteProcessByRouteAndProcess(
|
@RequestParam("routeId") Long routeId,
|
@RequestParam("processId") Long processId) {
|
MesProRouteProcessDO routeProcess = routeProcessService.getRouteProcessByRouteIdAndProcessId(routeId, processId);
|
return success(buildRouteProcessRespVO(routeProcess));
|
}
|
|
// ==================== 拼接 VO ====================
|
|
private List<MesProRouteProcessRespVO> buildRouteProcessRespVOList(List<MesProRouteProcessDO> list) {
|
if (CollUtil.isEmpty(list)) {
|
return Collections.emptyList();
|
}
|
// 1. 批量获取关联数据
|
Set<Long> processIds = convertSet(list, MesProRouteProcessDO::getProcessId);
|
list.forEach(item -> { if (item.getNextProcessId() != null) processIds.add(item.getNextProcessId()); });
|
Map<Long, MesProProcessDO> processMap = convertMap(
|
processService.getProcessList(new ArrayList<>(processIds)), MesProProcessDO::getId);
|
// 2. 解析产出配置(JSON 数组 或 旧的逗号分隔),收集全部物料/产品编号
|
List<List<MesProProcessOutputItemVO>> outputsPerRow = new ArrayList<>();
|
Set<Long> allItemIds = new HashSet<>();
|
for (MesProRouteProcessDO row : list) {
|
List<MesProProcessOutputItemVO> outs = parseOutputsRaw(row.getOutputItemId());
|
outputsPerRow.add(outs);
|
for (MesProProcessOutputItemVO out : outs) {
|
if (out.getItemId() != null) {
|
allItemIds.add(out.getItemId());
|
}
|
if (out.getProductId() != null) {
|
allItemIds.add(out.getProductId());
|
}
|
}
|
}
|
Map<Long, MesMdItemDO> outputItemMap = allItemIds.isEmpty()
|
? Collections.emptyMap() : mdItemService.getItemMap(allItemIds);
|
// 3. 拼接 VO(先把 output_item_id 置空,避免 String 转 Long 抛 NumberFormatException;产出单独填充)
|
List<MesProRouteProcessDO> safeList = BeanUtils.toBean(list, MesProRouteProcessDO.class);
|
safeList.forEach(row -> row.setOutputItemId(null));
|
List<MesProRouteProcessRespVO> result = BeanUtils.toBean(safeList, MesProRouteProcessRespVO.class);
|
for (int i = 0; i < result.size(); i++) {
|
MesProRouteProcessRespVO vo = result.get(i);
|
MapUtils.findAndThen(processMap, vo.getProcessId(),
|
process -> vo.setProcessCode(process.getCode()).setProcessName(process.getName()));
|
MapUtils.findAndThen(processMap, vo.getNextProcessId(),
|
nextProcess -> vo.setNextProcessName(nextProcess.getName()));
|
// 产出物料(支持多选,含归属产品)
|
List<MesProProcessOutputItemVO> outs = outputsPerRow.get(i);
|
for (MesProProcessOutputItemVO out : outs) {
|
fillOutputItemInfo(out, outputItemMap);
|
}
|
if (!outs.isEmpty()) {
|
List<Long> ids = outs.stream().map(MesProProcessOutputItemVO::getItemId)
|
.filter(Objects::nonNull).collect(Collectors.toList());
|
vo.setOutputItemIds(ids);
|
vo.setOutputItemNames(outs.stream().map(MesProProcessOutputItemVO::getItemName)
|
.filter(Objects::nonNull).collect(Collectors.joining(", ")));
|
// 向后兼容:第一个产出物料
|
MesProProcessOutputItemVO first = outs.get(0);
|
vo.setOutputItemId(first.getItemId());
|
vo.setOutputItemCode(first.getItemCode());
|
vo.setOutputItemName(first.getItemName());
|
}
|
// 前端主用:outputs(含归属产品)
|
vo.setOutputs(outs);
|
}
|
return result;
|
}
|
|
private MesProRouteProcessRespVO buildRouteProcessRespVO(MesProRouteProcessDO routeProcess) {
|
if (routeProcess == null) {
|
return null;
|
}
|
return buildRouteProcessRespVOList(ListUtil.of(routeProcess)).get(0);
|
}
|
|
/**
|
* 解析 output_item_id 为产出配置列表(不含名称)
|
* 兼容 JSON 数组 [{"itemId":231,"productId":231}] 与逗号分隔 "231,232" 两种格式
|
*/
|
private List<MesProProcessOutputItemVO> parseOutputsRaw(String raw) {
|
List<MesProProcessOutputItemVO> result = new ArrayList<>();
|
if (raw == null || raw.isBlank()) {
|
return result;
|
}
|
String text = raw.trim();
|
if (text.startsWith("[")) {
|
try {
|
cn.hutool.json.JSONArray array = cn.hutool.json.JSONUtil.parseArray(text);
|
for (Object element : array) {
|
if (!(element instanceof cn.hutool.json.JSONObject)) {
|
continue;
|
}
|
cn.hutool.json.JSONObject m = (cn.hutool.json.JSONObject) element;
|
Long itemId = m.getLong("itemId");
|
if (itemId == null) {
|
continue;
|
}
|
MesProProcessOutputItemVO vo = new MesProProcessOutputItemVO();
|
vo.setItemId(itemId);
|
vo.setProductId(m.getLong("productId"));
|
result.add(vo);
|
}
|
return result;
|
} catch (Exception ignored) {
|
// 解析失败按逗号兜底
|
result.clear();
|
}
|
}
|
for (String s : text.split(",")) {
|
String t = s.trim();
|
if (t.isEmpty()) {
|
continue;
|
}
|
try {
|
MesProProcessOutputItemVO vo = new MesProProcessOutputItemVO();
|
vo.setItemId(Long.valueOf(t));
|
result.add(vo);
|
} catch (NumberFormatException ignored) {
|
// 跳过非法值
|
}
|
}
|
return result;
|
}
|
|
/**
|
* 填充产出物料的编码、名称与归属产品名称
|
*/
|
private void fillOutputItemInfo(MesProProcessOutputItemVO vo, Map<Long, MesMdItemDO> itemMap) {
|
if (vo.getItemId() == null) {
|
return;
|
}
|
MesMdItemDO item = itemMap.get(vo.getItemId());
|
if (item != null) {
|
vo.setItemCode(item.getCode());
|
vo.setItemName(item.getName());
|
}
|
if (vo.getProductId() != null) {
|
MesMdItemDO product = itemMap.get(vo.getProductId());
|
if (product != null) {
|
vo.setProductName(product.getName());
|
}
|
}
|
}
|
|
}
|