自动化立体仓库 - WMS系统
pang.jiabao
5 天以前 8407e277e156a55fee38e7bb7b8930ec16a15f0e
库存上下限预警,物料高低频摆放
12个文件已修改
298 ■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/LocDetlController.java 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/MatController.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/Mat.java 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/WcsController.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/LocDetlMapper.xml 74 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/MatMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/common.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/locDetlGroup/locDetlGroup.js 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/locDetlGroup/locDetlGroup.html 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/mat/mat.html 41 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/LocDetlController.java
@@ -68,47 +68,59 @@
//        excludeTrash(param);
        param.put("curr", curr);
        param.put("limit", limit);
        Page<LocDetl> groupLocDetl = locDetlService.getStockStatis2(toPage(1, 10000, param, LocDetl.class));
//        List<LocDetl> groupLocDetl = locDetlService.selectGroupPage(param, curr, limit);
        for (LocDetl locDetl : groupLocDetl.getRecords()) {
            AbnormalLocDetlParam abnormalLocDetlParam = new AbnormalLocDetlParam();
            Mat mat = matService.selectOne(new EntityWrapper<Mat>()
                    .eq("matnr", locDetl.getMatnr()));
            if (Cools.isEmpty(mat)) {
                continue;
            }
        Page<LocDetl> locDetlPage1 = toPage(curr, limit, param, LocDetl.class);
        Map<String, Object> condition1 = locDetlPage1.getCondition();
            if (!Cools.isEmpty(mat.getStoreMax()) || !Cools.isEmpty(mat.getStoreMin())) {
                abnormalLocDetlParam.setStoreMax(mat.getStoreMax());
                abnormalLocDetlParam.setStoreMaxDate(mat.getStoreMaxDate());
                abnormalLocDetlParam.setStoreMin(mat.getStoreMin());
                abnormalLocDetlParam.setAnfme(locDetl.getAnfme());
                abnormalLocDetlParam.setMaktx(mat.getMaktx());
                abnormalLocDetlParam.setMatnr(mat.getMatnr());
                abnormalLocDetlParam.setSpecs(mat.getSpecs());
                abnormalLocDetlParam.setBatch(locDetl.getBatch());
//                SimpleDateFormat simple = new SimpleDateFormat("yyyyMMdd");
//                Date maxDate = simple.parse(locDetl.getBatch());
//                long time = maxDate.getTime();
//                Date now = new Date();
//                long time1 = now.getTime();
//                abnormalLocDetlParam.setNowTime((int) ((time1 - time) / (1000 * 60 * 60 * 24)));
                if (!Cools.isEmpty(mat.getStoreMax()) && locDetl.getAnfme() > mat.getStoreMax()) {
                    result.add(abnormalLocDetlParam);
                } else if (!Cools.isEmpty(mat.getStoreMin()) && locDetl.getAnfme() < mat.getStoreMin()) {
                    result.add(abnormalLocDetlParam);
                }
            }
        }
        Page<AbnormalLocDetlParam> locDetlPage = new Page<>();
        locDetlPage.setRecords(paging(result, curr, limit));
        locDetlPage.setTotal(result.size());
        List<LocDetl> locDetlList = locDetlMapper.getStockList(condition1);
        long locDetlListCount = locDetlMapper.getStockListCount(condition1);
        Page<LocDetl> locDetlPage = new Page<>();
        locDetlPage.setRecords(locDetlList);
        locDetlPage.setTotal(locDetlListCount);
        locDetlPage.setCurrent(curr);
        locDetlPage.setSize(limit);
//        Page<LocDetl> groupLocDetl = locDetlService.getStockStatis2(toPage(1, 16, param, LocDetl.class));
////        List<LocDetl> groupLocDetl = locDetlService.selectGroupPage(param, curr, limit);
//        for (LocDetl locDetl : groupLocDetl.getRecords()) {
//            AbnormalLocDetlParam abnormalLocDetlParam = new AbnormalLocDetlParam();
//            Mat mat = matService.selectOne(new EntityWrapper<Mat>()
//                    .eq("matnr", locDetl.getMatnr()));
//            if (Cools.isEmpty(mat)) {
//                continue;
//            }
//
//
//            if (!Cools.isEmpty(mat.getStoreMax()) || !Cools.isEmpty(mat.getStoreMin())) {
//                abnormalLocDetlParam.setStoreMax(mat.getStoreMax());
//                abnormalLocDetlParam.setStoreMaxDate(mat.getStoreMaxDate());
//                abnormalLocDetlParam.setStoreMin(mat.getStoreMin());
//                abnormalLocDetlParam.setAnfme(locDetl.getAnfme());
//                abnormalLocDetlParam.setMaktx(mat.getMaktx());
//                abnormalLocDetlParam.setMatnr(mat.getMatnr());
//                abnormalLocDetlParam.setSpecs(mat.getSpecs());
//                abnormalLocDetlParam.setBatch(locDetl.getBatch());
//
////                SimpleDateFormat simple = new SimpleDateFormat("yyyyMMdd");
////                Date maxDate = simple.parse(locDetl.getBatch());
////                long time = maxDate.getTime();
////                Date now = new Date();
////                long time1 = now.getTime();
////                abnormalLocDetlParam.setNowTime((int) ((time1 - time) / (1000 * 60 * 60 * 24)));
//
//                if (!Cools.isEmpty(mat.getStoreMax()) && locDetl.getAnfme() > mat.getStoreMax()) {
//                    result.add(abnormalLocDetlParam);
//                } else if (!Cools.isEmpty(mat.getStoreMin()) && locDetl.getAnfme() < mat.getStoreMin()) {
//                    result.add(abnormalLocDetlParam);
//                }
//            }
//        }
//        Page<AbnormalLocDetlParam> locDetlPage = new Page<>();
//        locDetlPage.setRecords(paging(result, curr, limit));
//        locDetlPage.setTotal(result.size());
//        locDetlPage.setCurrent(curr);
//        locDetlPage.setSize(limit);
        return R.ok(locDetlPage);
    }
src/main/java/com/zy/asrs/controller/MatController.java
@@ -50,9 +50,9 @@
    @RequestMapping(value = "/mat/list/pda/auth")
    @ManagerAuth
    public R pdaList(@RequestParam(required = true) Long tagId) {
    public R pdaList(@RequestParam(required = false) Long tagId) {
        EntityWrapper<Mat> wrapper = new EntityWrapper<>();
        wrapper.eq("tag_id", tagId);
//        wrapper.eq("tag_id", tagId);
        wrapper.orderBy("create_time", false);
        List<Mat> mats = matService.selectList(wrapper);
        return R.ok().add(mats);
src/main/java/com/zy/asrs/entity/Mat.java
@@ -232,7 +232,7 @@
    /**
     * 是否批次 1: 是  0: 否
     */
    @ApiModelProperty(value = "是否批次 1: 是  0: 否  ")
    @ApiModelProperty(value = "高低频 0: 高 1: 低  ")
    @TableField("be_batch")
    private Integer beBatch;
@@ -322,12 +322,14 @@
     * 库存预警数量上限
     */
    @TableField("store_max")
    @ExcelProperty(value = "库存预警数量上限")
    private Double storeMax;
    /**
     * 库存预警数量下限
     */
    @TableField("store_min")
    @ExcelProperty(value = "库存预警数量下限")
    private Double storeMin;
    /**
@@ -448,9 +450,9 @@
        }
        switch (this.beBatch) {
            case 1:
                return "是";
                return "低频";
            case 0:
                return "否";
                return "高频";
            default:
                return String.valueOf(this.beBatch);
        }
src/main/java/com/zy/asrs/mapper/LocDetlMapper.java
@@ -114,4 +114,7 @@
     */
    void frozenInventory(@Param("locNo") String locNo, @Param("matnr") String matnr, @Param("batch") String batch, @Param("frozen") int frozen);
    List<LocDetl> getStockList(Map<String, Object> condition1);
    long getStockListCount(Map<String, Object> condition1);
}
src/main/java/com/zy/common/service/CommonService.java
@@ -1030,7 +1030,7 @@
    @Resource
    private LocMastMapper locMastMapper;
    public StartupDto getLocNoNew(int ioType, Integer sourceStaNo, Integer locType, List<Integer> rows) {
    public StartupDto getLocNoNew(int ioType, Integer sourceStaNo, Integer locType, List<Integer> rows, int sortRole) {
        // 寻找到的库位
        LocMast locMast = null;
@@ -1057,14 +1057,18 @@
                        m -> ((Number) m.get("cnt")).intValue()
                ));
        Wrapper<LocMast> wrapper = new EntityWrapper<LocMast>()
                .eq("loc_type1", locType)
                .eq("loc_sts", 'O')
                .in("crn_no", basCrnps.stream().map(BasCrnp::getCrnNo).collect(Collectors.toList()));
        if(sortRole == 0) {
            wrapper.last("ORDER BY CASE WHEN row1 IN (1,4,5,8,9,12) THEN 0 ELSE 1 END, lev1, bay1, row1");
        } else {
            wrapper.last("ORDER BY CASE WHEN row1 IN (1,4,5,8,9,12) THEN 0 ELSE 1 END, lev1, bay1 desc, row1");
        }
        // 所有满足条件的库位
        List<LocMast> allLocs = locMastMapper.selectList(
                new EntityWrapper<LocMast>()
                        .eq("loc_type1", locType)
                        .eq("loc_sts" ,'O')
                        .in("crn_no", basCrnps.stream().map(BasCrnp::getCrnNo).collect(Collectors.toList()))
                        .last("ORDER BY CASE WHEN row1 IN (1,4,5,8,9,12) THEN 0 ELSE 1 END, lev1, bay1, row1")
        );
        List<LocMast> allLocs = locMastMapper.selectList(wrapper);
        // 按堆垛机分组
        Map<Integer, List<LocMast>> locMap = allLocs.stream()
@@ -1078,7 +1082,7 @@
        if (availableCrn.isEmpty()) {
            // 递归兼容
            if (locType >= 3) return null;
            return getLocNoNew(ioType, sourceStaNo, locType + 1, rows);
            return getLocNoNew(ioType, sourceStaNo, locType + 1, rows, sortRole);
        }
        availableCrn.sort(Comparator.comparing(c -> countMap.getOrDefault(c.getCrnNo(), 0)));
@@ -1098,8 +1102,8 @@
                    // 获取浅库位
                    String shallowLoc = Utils.getShallowLoc(slaveProperties, locNo);
                    LocMast shallow = locNoMap.get(shallowLoc);
                    // 浅库位无货
                    if (shallow == null) {
                    // 浅库位是空库位,放深库位
                    if (shallow != null) {
                        locMast = locMast1;
                        break;
                    }
@@ -1124,7 +1128,7 @@
        if (locMast == null) {
            if (locType >= 3) return null;
            return getLocNoNew(ioType, sourceStaNo, locType + 1, rows);
            return getLocNoNew(ioType, sourceStaNo, locType + 1, rows, sortRole);
        }
        // 根据入库类型和源站点获取工作路径
src/main/java/com/zy/common/web/WcsController.java
@@ -9,6 +9,7 @@
import com.zy.asrs.entity.param.EmptyPlateOutParam;
import com.zy.asrs.entity.result.FindLocNoAttributeVo;
import com.zy.asrs.mapper.LocMastMapper;
import com.zy.asrs.mapper.MatMapper;
import com.zy.asrs.service.*;
import com.zy.asrs.utils.Utils;
import com.zy.common.CodeRes;
@@ -29,6 +30,7 @@
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
/**
 * Created by vincent on 2020/10/30
@@ -231,7 +233,7 @@
            rows.add(row[i * 4 + 1]);
            rows.add(row[i * 4 + 2]);
            rows.add(row[i * 4 + 3]);
            dto = commonService.getLocNoNew(1, 0, Integer.valueOf(locTypeDto.getLocType1()),rows);
            dto = commonService.getLocNoNew(1, 0, Integer.valueOf(locTypeDto.getLocType1()),rows,0);
            if (dto != null) {
                break;
            }
@@ -373,6 +375,9 @@
        return R.ok(!Cools.isEmpty(wrkMast) ? R.ok("自动空托出库成功,工作号:" + wrkMast.getWrkNo()) : R.error("生成自动空托出库失败"));
    }
    @Resource
    private MatMapper matMapper;
    /**
     * 全板入库
     */
@@ -380,6 +385,12 @@
    public StartupDto startupFullPutStore(Integer devpNo, String barcode, LocTypeDto locTypeDto, List<WaitPakin> waitPakins, int[] row) {
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        /// 判断是否有低频物料
        int sortRole = 0;
        if(!waitPakins.isEmpty()) {
            sortRole = matMapper.selectCount(new EntityWrapper<Mat>().eq("be_batch",1).in("matnr", waitPakins.stream().map(WaitPakin::getMatnr).distinct().collect(Collectors.toList())));
        }
        // 检索库位
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(waitPakins.get(0));
//        StartupDto dto = commonService.getLocNo(1, devpNo, findLocNoAttributeVo, locTypeDto);
@@ -396,7 +407,7 @@
//                break;
//            }
//        }
        StartupDto dto = commonService.getLocNoNew(1, devpNo, Integer.valueOf(locTypeDto.getLocType1()),null);;
        StartupDto dto = commonService.getLocNoNew(1, devpNo, Integer.valueOf(locTypeDto.getLocType1()),null,sortRole);;
        if (dto == null) {
            throw new CoolException("没有匹配到库位,检查可用库位/堆垛机报警");
        }
@@ -491,7 +502,7 @@
//                break;
//            }
//        }
        StartupDto dto = commonService.getLocNoNew(10, devpNo, Integer.valueOf(locTypeDto.getLocType1()),null);;
        StartupDto dto = commonService.getLocNoNew(10, devpNo, Integer.valueOf(locTypeDto.getLocType1()),null,0);;
        if (dto == null) {
            throw new CoolException("没有匹配到库位,检查可用库位/堆垛机报警");
        }
src/main/resources/mapper/LocDetlMapper.xml
@@ -763,5 +763,79 @@
        group by a.matnr,a.batch
        ) t where t.row between ((#{pageNumber}-1)*#{pageSize}+1) and (#{pageNumber}*#{pageSize})
    </select>
    <select id="getStockList" resultType="com.zy.asrs.entity.LocDetl">
        select
        *
        from
        (
        SELECT
        ROW_NUMBER() over (
        order by m.matnr desc) as row,
        m.matnr,
        m.maktx ,
        m.store_min boxType1,
        m.store_max boxType2,
        ISNULL(SUM(d.anfme),
        0) AS anfme
        FROM
        man_mat m
        LEFT JOIN asr_loc_detl d
        ON
        m.matnr = d.matnr
        WHERE
        m.store_min IS NOT NULL
        OR m.store_max IS NOT NULL
        <if test="matnr!=null and matnr!='' ">
            and m.matnr like '%' + #{matnr} + '%'
        </if>
        <if test="maktx!=null and maktx!='' ">
            and m.maktx like '%' + #{maktx} + '%'
        </if>
        GROUP BY
        m.matnr,
        m.maktx ,
        m.store_min,
        m.store_max
        HAVING
        ISNULL(SUM(d.anfme),0) &lt; m.store_min OR ISNULL(SUM(d.anfme),0) > m.store_max
        ) t where t.row between ((#{pageNumber}-1)*#{pageSize}+1) and (#{pageNumber}*#{pageSize})
    </select>
    <select id="getStockListCount" resultType="java.lang.Long">
        select
        count(*)
        from
        (
        SELECT
        ROW_NUMBER() over (
        order by m.matnr desc) as row,
        m.matnr,
        m.maktx ,
        m.store_min boxType1,
        m.store_max boxType2,
        ISNULL(SUM(d.anfme),
        0) AS anfme
        FROM
        man_mat m
        LEFT JOIN asr_loc_detl d
        ON
        m.matnr = d.matnr
        WHERE
        m.store_min IS NOT NULL
        OR m.store_max IS NOT NULL
        <if test="matnr!=null and matnr!='' ">
            and m.matnr like '%' + #{matnr} + '%'
        </if>
        <if test="maktx!=null and maktx!='' ">
            and m.maktx like '%' + #{maktx} + '%'
        </if>
        GROUP BY
        m.matnr,
        m.maktx ,
        m.store_min,
        m.store_max
        HAVING
        ISNULL(SUM(d.anfme),0) &lt; m.store_min OR ISNULL(SUM(d.anfme),0) > m.store_max
        ) t
    </select>
</mapper>
src/main/resources/mapper/MatMapper.xml
@@ -42,7 +42,8 @@
        <result column="update_by" property="updateBy" />
        <result column="update_time" property="updateTime" />
        <result column="memo" property="memo" />
        <result column="store_max" property="storeMax" />
        <result column="store_min" property="storeMin" />
        <result column="stock" property="stock" />
    </resultMap>
src/main/webapp/static/js/common.js
@@ -208,7 +208,7 @@
    ,{field: 'threeCode', align: 'center',title: '箱子尺寸', hide: true}
    ,{field: 'supp', align: 'center',title: '供应商', hide: true}
    ,{field: 'suppCode', align: 'center',title: '供应商编码', hide: true}
    ,{field: 'beBatch$', align: 'center',title: '是否批次', hide: true}
    ,{field: 'beBatch$', align: 'center',title: '高低频', hide: true}
    ,{field: 'deadTime', align: 'center',title: '保质期', hide: true}
    ,{field: 'deadWarn', align: 'center',title: '预警天数', hide: true}
    ,{field: 'source$', align: 'center',title: '制购', hide: true}
src/main/webapp/static/js/locDetlGroup/locDetlGroup.js
@@ -4,10 +4,10 @@
    var cols = [
        {field: 'matnr', align: 'center', title: '物料号', sort: true}
        , {field: 'maktx', align: 'center', title: '物料名称', sort: true}
        , {field: 'specs', align: 'center', title: '规格'}
        , {field: 'batch', align: 'center', title: '批号', width: 300, sort: true}
        , {field: 'storeMax', align: 'center', title: '数量上限', sort: true}
        , {field: 'storeMin', align: 'center', title: '数量下限', sort: true}
        // , {field: 'specs', align: 'center', title: '规格'}
        // , {field: 'batch', align: 'center', title: '批号', width: 300, sort: true}
        , {field: 'boxType1', align: 'center', title: '数量下限', sort: true}
        , {field: 'boxType2', align: 'center', title: '数量上限', sort: true}
        // , {field: 'storeMaxDate', align: 'center', title: '库龄上限', sort: true}
        , {field: 'anfme', align: 'center', title: '实际数量'}
        // , {field: 'nowTime', align: 'center', title: '实际库龄'}
@@ -31,8 +31,8 @@
        headers: {token: localStorage.getItem('token')},
        url: baseUrl + '/locDetl/groupLocList/auth',
        page: true,
        limit: 20,
        limits: [20, 30, 50, 100, 200, 500],
        limit: 16,
        limits: [16, 32, 50, 100, 200, 500],
        even: true,
        toolbar: '#toolbar',
        cellMinWidth: 50,
src/main/webapp/views/locDetlGroup/locDetlGroup.html
@@ -24,16 +24,16 @@
            <input class="layui-input" type="text" name="maktx" placeholder="物料名称" autocomplete="off">
        </div>
    </div>
    <div class="layui-inline">
        <div class="layui-input-inline">
            <input class="layui-input" type="text" name="specs" placeholder="规格" autocomplete="off">
        </div>
    </div>
    <div class="layui-inline">
        <div class="layui-input-inline">
            <input class="layui-input" type="text" name="batch" placeholder="批号" autocomplete="off">
        </div>
    </div>
<!--    <div class="layui-inline">-->
<!--        <div class="layui-input-inline">-->
<!--            <input class="layui-input" type="text" name="specs" placeholder="规格" autocomplete="off">-->
<!--        </div>-->
<!--    </div>-->
<!--    <div class="layui-inline">-->
<!--        <div class="layui-input-inline">-->
<!--            <input class="layui-input" type="text" name="batch" placeholder="批号" autocomplete="off">-->
<!--        </div>-->
<!--    </div>-->
    <!-- 待添加 -->
    <div id="data-search-btn" class="layui-btn-container layui-form-item" style="display: inline-block">
src/main/webapp/views/mat/mat.html
@@ -195,16 +195,16 @@
                        <input name="maktx" placeholder="请输入商品名称" class="layui-input" lay-vertype="tips" lay-verify="required" required="">
                    </div>
                </div>
<!--                <div class="layui-form-item">-->
<!--                    <label class="layui-form-label layui-form-required">组托上限</label>-->
<!--                    <div class="layui-input-block">-->
<!--                        <input name="upQty" placeholder="请输入最大组托数量" class="layui-input" lay-vertype="tips" lay-verify="required" required="">-->
<!--                    </div>-->
<!--                </div>-->
                <div class="layui-form-item">
                    <label class="layui-form-label layui-form-required">组托上限</label>
                    <label class="layui-form-label">库存预警下限</label>
                    <div class="layui-input-block">
                        <input name="upQty" placeholder="请输入最大组托数量" class="layui-input" lay-vertype="tips" lay-verify="required" required="">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">配置</label>
                    <div class="layui-input-block">
                        <input name="specs" placeholder="请输入配置" class="layui-input">
                        <input name="storeMin" placeholder="请输入库存预警下限" class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
@@ -217,6 +217,12 @@
                    <label class="layui-form-label">单箱体积</label>
                    <div class="layui-input-block">
                        <input name="volume" placeholder="请输入单箱体积" class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">备注</label>
                    <div class="layui-input-block">
                        <input name="memo" placeholder="请输入备注" class="layui-input">
                    </div>
                </div>
            </div>
@@ -234,16 +240,27 @@
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">备注</label>
                    <label class="layui-form-label">库存预警上限</label>
                    <div class="layui-input-block">
                        <input name="memo" placeholder="请输入备注" class="layui-input">
                        <input name="storeMax" placeholder="请输入库存预警上限" class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">单箱毛重</label>
                    <label class="layui-form-label">高低频</label>
<!--                    <select name="loc_type1" id="loc_type1" class="layui-input" type="text" placeholder="库位类型" autocomplete="off">-->
<!--                        &lt;!&ndash;                    <option style="display: none"></option>&ndash;&gt;-->
<!--                        <option value=""></option>-->
<!--                        <option value="1">小库位</option>-->
<!--                        <option value="2">大库位</option>-->
<!--                    </select>-->
                    <div class="layui-input-block">
                        <input name="manLength" placeholder="请输入单箱毛重" class="layui-input">
                        <select name="beBatch">
                            <option value="0" selected>高频</option>
                            <option value="1">低频</option>
                        </select>
<!--                        <input name="maktx" placeholder="请输入商品名称" class="layui-input" lay-vertype="tips" lay-verify="required" required="">-->
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">单箱体积</label>