liu
2026-09-02 7ef882f052ab0796b68be7d97150f8c3f321827c
feat(mes): 领料出库单新增物料仅展示当前工单 BOM 物料

- 新增接口 GET /mes/wm/product-issue-line/bom-item-list 返回当前领料单对应生产工单 BOM 物料
- 物料分页 MesMdItemPageReqVO/Mapper 支持 ids 白名单过滤,使物料选择器可限定可选范围

Co-Authored-By: Claude <noreply@anthropic.com>
已添加1个文件
已修改3个文件
90 ■■■■■ 文件已修改
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemPageReqVO.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productissue/MesWmProductIssueLineController.java 53 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productissue/vo/line/MesWmProductIssueBomItemRespVO.java 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/md/item/vo/MesMdItemPageReqVO.java
@@ -29,6 +29,9 @@
    @Schema(description = "状态", example = "0")
    private Integer status;
    @Schema(description = "物料编号集合(逗号分隔),用于限定可选物料范围", example = "1,2,3")
    private String ids;
    @Schema(description = "创建时间")
    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
    private LocalDateTime[] createTime;
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productissue/MesWmProductIssueLineController.java
@@ -5,17 +5,22 @@
import cn.iocoder.yudao.framework.common.pojo.PageResult;
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.wm.productissue.vo.line.MesWmProductIssueBomItemRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.productissue.vo.line.MesWmProductIssueLinePageReqVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.productissue.vo.line.MesWmProductIssueLineRespVO;
import cn.iocoder.yudao.module.mes.controller.admin.wm.productissue.vo.line.MesWmProductIssueLineSaveReqVO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.item.MesMdItemDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.md.unitmeasure.MesMdUnitMeasureDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.task.MesProTaskDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.pro.workorder.MesProWorkOrderBomDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueDO;
import cn.iocoder.yudao.module.mes.dal.dataobject.wm.productissue.MesWmProductIssueLineDO;
import cn.iocoder.yudao.module.mes.service.md.item.MesMdItemService;
import cn.iocoder.yudao.module.mes.service.md.unitmeasure.MesMdUnitMeasureService;
import cn.iocoder.yudao.module.mes.service.pro.task.MesProTaskService;
import cn.iocoder.yudao.module.mes.service.pro.workorder.MesProWorkOrderBomService;
import cn.iocoder.yudao.module.mes.service.wm.productissue.MesWmProductIssueLineService;
import cn.iocoder.yudao.module.mes.service.wm.productissue.MesWmProductIssueService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
@@ -25,7 +30,10 @@
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
@@ -40,6 +48,10 @@
    @Resource
    private MesWmProductIssueLineService issueLineService;
    @Resource
    private MesWmProductIssueService issueService;
    @Resource
    private MesProWorkOrderBomService workOrderBomService;
    @Resource
    private MesMdItemService mdmItemService;
    @Resource
@@ -102,6 +114,47 @@
        return success(buildRespVOList(list));
    }
    @GetMapping("/bom-item-list")
    @Operation(summary = "获得领料出库单可领物料列表",
            description = "仅返回当前领料单对应生产工单 BOM ä¸­çš„物料,用于新增行物料选择器过滤,避免选择 BOM ä¹‹å¤–的物料")
    @Parameter(name = "issueId", description = "领料单编号", required = true, example = "1024")
    @PreAuthorize("@ss.hasPermission('mes:wm-product-issue:query')")
    public CommonResult<List<MesWmProductIssueBomItemRespVO>> getBomItemList(@RequestParam("issueId") Long issueId) {
        // 1. æ ¡éªŒé¢†æ–™å•存在,获取关联工单
        MesWmProductIssueDO issue = issueService.validateProductIssueExists(issueId);
        if (issue.getWorkOrderId() == null) {
            return success(Collections.emptyList());
        }
        // 2. èŽ·å–å·¥å• BOM ç‰©æ–™ï¼ˆåŒä¸€ç‰©æ–™è·¨å·¥åºå¤šæ¬¡æŠ•料时,需求量按物料汇总)
        List<MesProWorkOrderBomDO> bomList = workOrderBomService.getWorkOrderBomListByWorkOrderId(issue.getWorkOrderId());
        if (CollUtil.isEmpty(bomList)) {
            return success(Collections.emptyList());
        }
        Map<Long, BigDecimal> requiredQtyMap = new LinkedHashMap<>();
        for (MesProWorkOrderBomDO bom : bomList) {
            BigDecimal quantity = bom.getQuantity() != null ? bom.getQuantity() : BigDecimal.ZERO;
            requiredQtyMap.merge(bom.getItemId(), quantity, BigDecimal::add);
        }
        // 3. æ‰¹é‡èŽ·å–ç‰©æ–™ä¸Žå•ä½ä¿¡æ¯ï¼Œæ‹¼æŽ¥ VO
        Map<Long, MesMdItemDO> itemMap = mdmItemService.getItemMap(requiredQtyMap.keySet());
        Map<Long, MesMdUnitMeasureDO> unitMeasureMap = unitMeasureService.getUnitMeasureMap(
                convertSet(itemMap.values(), MesMdItemDO::getUnitMeasureId));
        List<MesWmProductIssueBomItemRespVO> result = new ArrayList<>(requiredQtyMap.size());
        requiredQtyMap.forEach((itemId, requiredQuantity) -> {
            MesMdItemDO item = itemMap.get(itemId);
            if (item == null) {
                return;
            }
            MesWmProductIssueBomItemRespVO vo = new MesWmProductIssueBomItemRespVO()
                    .setItemId(itemId).setItemCode(item.getCode()).setItemName(item.getName())
                    .setItemSpecification(item.getSpecification()).setRequiredQuantity(requiredQuantity);
            MapUtils.findAndThen(unitMeasureMap, item.getUnitMeasureId(),
                    unit -> vo.setUnitMeasureName(unit.getName()));
            result.add(vo);
        });
        return success(result);
    }
    // ==================== æ‹¼æŽ¥ VO ====================
    private List<MesWmProductIssueLineRespVO> buildRespVOList(List<MesWmProductIssueLineDO> list) {
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/controller/admin/wm/productissue/vo/line/MesWmProductIssueBomItemRespVO.java
¶Ô±ÈÐÂÎļþ
@@ -0,0 +1,30 @@
package cn.iocoder.yudao.module.mes.controller.admin.wm.productissue.vo.line;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.math.BigDecimal;
@Schema(description = "管理后台 - MES é¢†æ–™å‡ºåº“单行 BOM ç‰©æ–™é€‰æ‹© Response VO")
@Data
public class MesWmProductIssueBomItemRespVO {
    @Schema(description = "物料编号", example = "100")
    private Long itemId;
    @Schema(description = "物料编码", example = "M-001")
    private String itemCode;
    @Schema(description = "物料名称", example = "电阻 10K")
    private String itemName;
    @Schema(description = "规格型号", example = "0603")
    private String itemSpecification;
    @Schema(description = "单位名称", example = "个")
    private String unitMeasureName;
    @Schema(description = "工单 BOM éœ€æ±‚量(同物料跨工序用量汇总)", example = "1000.00")
    private BigDecimal requiredQuantity;
}
yudao-module-mes/src/main/java/cn/iocoder/yudao/module/mes/dal/mysql/md/item/MesMdItemMapper.java
@@ -1,7 +1,9 @@
package cn.iocoder.yudao.module.mes.dal.mysql.md.item;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.string.StrUtils;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.mes.controller.admin.md.item.vo.MesMdItemPageReqVO;
@@ -31,6 +33,8 @@
                .likeIfPresent(MesMdItemDO::getCode, reqVO.getCode())
                .likeIfPresent(MesMdItemDO::getName, reqVO.getName())
                .inIfPresent(MesMdItemDO::getItemTypeId, itemTypeIds)
                .inIfPresent(MesMdItemDO::getId,
                        StrUtil.isBlank(reqVO.getIds()) ? null : StrUtils.splitToLong(reqVO.getIds(), ","))
                .eqIfPresent(MesMdItemDO::getStatus, reqVO.getStatus())
                .betweenIfPresent(MesMdItemDO::getCreateTime, reqVO.getCreateTime())
                .orderByDesc(MesMdItemDO::getId));