自动化立体仓库 - WMS系统
pang.jiabao
2025-11-10 11a590bda370ddad398b2c3ae68a218ee8d5a5d2
项目wms功能初始化
1个文件已添加
27个文件已修改
6个文件已删除
975 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/DocTypeController.java 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/OpenController.java 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/WrkMastLogController.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/CraneLoadInfo.java 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMast.java 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMastLog.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/WrkMastLogMapper.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 64 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/WrkMastLogServiceImpl.java 17 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/AutoLocMoveScheduler.java 106 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/BareBoardScheduler.java 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/CheckDeepScheduler.java 51 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/LocMoveAllScheduler.java 112 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/OrderMoveHistoryScheduler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/OrderSyncScheduler.java 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/WorkMastScheduler.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/AutoLocMoveHandler.java 89 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/OrderPakinSyncHandler.java 62 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/OrderPakoutSyncHandler.java 64 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/config/ThreadPoolConfig.java 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/constant/MesConstant.java 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/properties/SlaveWmsParameterProperties.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/WcsController.java 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-prod.yml 14 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ViewStockUseMapper.xml 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastLogMapper.xml 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/WrkMastMapper.xml 4 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/order/order.html 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/orderPakin/order.html 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/orderPakout/order.html 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
version/v1.0.0/truncate.sql 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/DocTypeController.java
@@ -119,6 +119,44 @@
        return R.ok(result);
    }
    // 只查入库单据
    @RequestMapping(value = "/docTypeQueryIn/auth")
    @ManagerAuth
    public R queryIn(String condition) {
        EntityWrapper<DocType> wrapper = new EntityWrapper<>();
        wrapper.like("doc_name", condition);
        wrapper.eq("status", 1);
        wrapper.eq("pakin", 1);
        Page<DocType> page = docTypeService.selectPage(new Page<>(0, 30), wrapper);
        List<Map<String, Object>> result = new ArrayList<>();
        for (DocType docType : page.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", docType.getDocId());
            map.put("value", docType.getDocName());
            result.add(map);
        }
        return R.ok(result);
    }
    // 只查出库单据
    @RequestMapping(value = "/docTypeQueryOut/auth")
    @ManagerAuth
    public R queryOut(String condition) {
        EntityWrapper<DocType> wrapper = new EntityWrapper<>();
        wrapper.like("doc_name", condition);
        wrapper.eq("status", 1);
        wrapper.eq("pakout", 1);
        Page<DocType> page = docTypeService.selectPage(new Page<>(0, 30), wrapper);
        List<Map<String, Object>> result = new ArrayList<>();
        for (DocType docType : page.getRecords()) {
            Map<String, Object> map = new HashMap<>();
            map.put("id", docType.getDocId());
            map.put("value", docType.getDocName());
            result.add(map);
        }
        return R.ok(result);
    }
    @RequestMapping(value = "/docType/check/column/auth")
    @ManagerAuth
    public R query(@RequestBody JSONObject param) {
src/main/java/com/zy/asrs/controller/OpenController.java
@@ -10,6 +10,8 @@
import com.zy.asrs.entity.param.OpenOrderPakoutParam;
import com.zy.asrs.service.OpenService;
import com.zy.common.model.DetlDto;
import com.zy.common.model.MesPakinParam;
import com.zy.common.model.MesPakoutParam;
import com.zy.common.web.BaseController;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
@@ -35,6 +37,22 @@
    @Autowired
    private OpenService openService;
    // 入库完成上报测试接口
    @PostMapping("/inOrderFinishReport")
    public synchronized R inOrderFinishReport(@RequestHeader(required = false) String appkey,
                                        @RequestBody(required = false) MesPakinParam param,
                                        HttpServletRequest request) {
        return R.ok();
    }
    // 出库完成上报测试接口
    @PostMapping("/outOrderFinishReport")
    public synchronized R outOrderFinishReport(@RequestHeader(required = false) String appkey,
                                        @RequestBody(required = false) MesPakoutParam param,
                                        HttpServletRequest request) {
        return R.ok();
    }
    @PostMapping("/order/matSync/default/v2")
//    @AppAuth(memo = "商品信息同步接口")
@@ -167,7 +185,7 @@
    }
    private void auth(String appkey, Object obj, HttpServletRequest request) {
        log.info("{}接口被访问;appkey:{};请求数据:{}", "open/sensorType/list/auth/v1", appkey, JSON.toJSONString(obj));
        log.info("{}接口被访问;appkey:{};请求数据:{}", request.getRequestURI(), appkey, JSON.toJSONString(obj));
        request.setAttribute("cache", obj);
        if (!auth) {
            return;
src/main/java/com/zy/asrs/controller/WrkMastLogController.java
@@ -57,7 +57,7 @@
    }
    @RequestMapping(value = "/inventoryFlow/list/auth")
    @ManagerAuth(memo = "库存移动流水记录")
    @ManagerAuth(memo = "库存移动流水记录",value = ManagerAuth.Auth.NONE)
    public R inventoryFlowList(@RequestParam(defaultValue = "1") Integer curr,
                               @RequestParam(defaultValue = "10") Integer limit,
                               @RequestParam(required = false) String orderByField,
src/main/java/com/zy/asrs/entity/CraneLoadInfo.java
New file
@@ -0,0 +1,18 @@
package com.zy.asrs.entity;
import lombok.Data;
/**
 * @author pang.jiabao
 * @description 计算相对负载均衡实体类
 * @createDate 2025/11/8 8:43
 */
@Data
public class CraneLoadInfo {
    private int crnNo;          // 堆垛机编号
    private int taskCount;      // 挂载任务数
    private double occupancy;   // 库位已占用比例(0~1)
    private double alpha;       // 综合负载值
}
src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -33,6 +33,7 @@
    private Integer wrkNo;
    @ApiModelProperty("任务类型: agv, crn")
    @TableField("task_type")
    private String taskType;
    @ApiModelProperty(value = "")
src/main/java/com/zy/asrs/entity/WrkMastLog.java
@@ -29,8 +29,9 @@
    @TableId(value = "id", type = IdType.AUTO)
    private Long id;
    @ApiModelProperty("日志ID")
    private Long logId;
    @ApiModelProperty("任务类型: agv, crn")
    @TableField("task_type")
    private String taskType;
    /**
     * 工作号
@@ -273,8 +274,8 @@
    private String manuType;
    @ApiModelProperty(value = "")
    @TableField("memo_m")
    private String memoM;
    @TableField("memo")
    private String memo;
    @ApiModelProperty(value = "")
    @TableField("sc_weight")
src/main/java/com/zy/asrs/mapper/WrkMastLogMapper.java
@@ -15,7 +15,7 @@
@Repository
public interface WrkMastLogMapper extends BaseMapper<WrkMastLog> {
    @Insert("insert into asr_wrk_mast_log select *, id as log_id from asr_wrk_mast where wrk_no=#{workNo}")
    @Insert("insert into asr_wrk_mast_log select * from asr_wrk_mast where wrk_no=#{workNo}")
    int save(Integer workNo);
    /**
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -626,7 +626,7 @@
            param.getCombMats().forEach(elem -> {
                OrderPakin order = orderPakinService.selectByNo(elem.getOrderNo());
                if (Cools.isEmpty(order) || order.getSettle() > 2) {
                    throw new CoolException("单据编号已过期");
                    throw new CoolException("单据正在作业中");
                }
                // 订单明细数量校验
                OrderDetlPakin detls = orderDetlPakinService.selectOne(new EntityWrapper<OrderDetlPakin>()
@@ -655,38 +655,38 @@
                }
            });
            BasContainer container = basContainerService.selectOne(new EntityWrapper<BasContainer>().eq("barcode", param.getBarcode()));
            if (Objects.isNull(container)) {
                throw new CoolException("数据错误:容器码不存在!!");
            }
            if (container.getMixMax() < detlDtos.size()) {
                throw new CoolException("超出容器最大混装数量,当前容器最大数量为:" + container.getMixMax() + "!!");
            }
            Set<String> matnrs = detlDtos.stream().map(DetlDto::getMatnr).collect(Collectors.toSet());
            List<Mat> mats = matService.selectList(new EntityWrapper<Mat>().in("matnr", matnrs));
            Set<Long> tagIds = mats.stream().map(Mat::getTagId).collect(Collectors.toSet());
            if (tagIds.size() > 1) {
                throw new CoolException("组托物料类型不一致,只有相同的物料分类才可以组托!!");
            }
            //还可以放入多少种物料
            Integer suplus = container.getMixMax();
//            BasContainer container = basContainerService.selectOne(new EntityWrapper<BasContainer>().eq("barcode", param.getBarcode()));
//            if (Objects.isNull(container)) {
//                throw new CoolException("数据错误:容器码不存在!!");
//            }
//            if (container.getMixMax() < detlDtos.size()) {
//                throw new CoolException("超出容器最大混装数量,当前容器最大数量为:" + container.getMixMax() + "!!");
//            }
//            Set<String> matnrs = detlDtos.stream().map(DetlDto::getMatnr).collect(Collectors.toSet());
//            List<Mat> mats = matService.selectList(new EntityWrapper<Mat>().in("matnr", matnrs));
//            Set<Long> tagIds = mats.stream().map(Mat::getTagId).collect(Collectors.toSet());
//            if (tagIds.size() > 1) {
//                throw new CoolException("组托物料类型不一致,只有相同的物料分类才可以组托!!");
//            }
//            //还可以放入多少种物料
//            Integer suplus = container.getMixMax();
            for (DetlDto detlDto : detlDtos) {
                Mat mat = matService.selectByMatnr(detlDto.getMatnr());
                if (Cools.isEmpty(mat)) {
                    throw new CoolException(detlDto.getMatnr() + "商品档案不存在");
                }
                //最多可放数量
                Double singleMax = mat.getUpQty() * suplus;
                if (singleMax.compareTo(detlDto.getAnfme()) < 0) {
                    throw new CoolException("物料:" + detlDto.getMatnr() + "单次组托上限为:" + mat.getUpQty() + ",当前总量超出托盘装载上限!!");
                }
                BigDecimal decimal = new BigDecimal(detlDto.getAnfme() / mat.getUpQty());
                //当前物料需要占用料箱格数
                Integer curr = decimal.setScale(0, RoundingMode.CEILING).intValue();
                suplus = suplus - curr;
                if (suplus < 0) {
                    throw new CoolException("物料:" + detlDto.getMatnr() + ", 超出当前托盘装载上限!!");
                }
//                //最多可放数量
//                Double singleMax = mat.getUpQty() * suplus;
//                if (singleMax.compareTo(detlDto.getAnfme()) < 0) {
//                    throw new CoolException("物料:" + detlDto.getMatnr() + "单次组托上限为:" + mat.getUpQty() + ",当前总量超出托盘装载上限!!");
//                }
//                BigDecimal decimal = new BigDecimal(detlDto.getAnfme() / mat.getUpQty());
//                //当前物料需要占用料箱格数
//                Integer curr = decimal.setScale(0, RoundingMode.CEILING).intValue();
//                suplus = suplus - curr;
//                if (suplus < 0) {
//                    throw new CoolException("物料:" + detlDto.getMatnr() + ", 超出当前托盘装载上限!!");
//                }
                WaitPakin waitPakin = new WaitPakin();
                BeanUtils.copyProperties(mat, waitPakin);
@@ -914,7 +914,7 @@
                boolean success = false;
                try {
                    response = new HttpHandler.Builder()
                            .setUri(MesConstant.URL)
                            .setUri(MesConstant.URI)
                            .setPath(MesConstant.PACK_DOWN_URL)
                            .setJson(JSON.toJSONString(mesCombParam))
                            .build()
@@ -923,10 +923,10 @@
                    if (jsonObject.getInteger("code").equals(200)) {
                        success = true;
                    } else if (jsonObject.getInteger("code").equals(500)) {
                        log.error("请求接口失败!!!url:{};request:{};response:{}", MesConstant.URL + MesConstant.PACK_DOWN_URL, JSON.toJSONString(mesCombParam), response);
                        log.error("请求接口失败!!!url:{};request:{};response:{}", MesConstant.URI + MesConstant.PACK_DOWN_URL, JSON.toJSONString(mesCombParam), response);
                        throw new CoolException(jsonObject.getString("msg"));
                    } else {
                        log.error("请求接口失败!!!url:{};request:{};response:{}", MesConstant.URL + MesConstant.PACK_DOWN_URL, JSON.toJSONString(mesCombParam), response);
                        log.error("请求接口失败!!!url:{};request:{};response:{}", MesConstant.URI + MesConstant.PACK_DOWN_URL, JSON.toJSONString(mesCombParam), response);
                        throw new CoolException("上报mes系统失败");
                    }
                } catch (Exception e) {
@@ -937,7 +937,7 @@
                        // 保存接口日志
                        apiLogService.save(
                                "打包下线帮托上报",
                                MesConstant.URL + MesConstant.PACK_DOWN_URL,
                                MesConstant.URI + MesConstant.PACK_DOWN_URL,
                                null,
                                "127.0.0.1",
                                JSON.toJSONString(mesCombParam),
src/main/java/com/zy/asrs/service/impl/WorkServiceImpl.java
@@ -490,17 +490,17 @@
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        // 检索库位
        LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo();
//        LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo();
        StartupDto dto = commonService.getLocNo(10, devpNo, findLocNoAttributeVo, locTypeDto);
        StartupDto dto = commonService.getLocNoBySdyhfz(devpNo,10);
        int workNo = dto.getWorkNo();
        Date now = new Date();
        // 生成工作档
        WrkMast wrkMast = new WrkMast();
        wrkMast.setWrkNo(workNo);
        wrkMast.setIoTime(now);
        wrkMast.setWrkSts(1L); // 工作状态:生成入库ID
        wrkMast.setWrkSts(2L); // 工作状态:生成入库ID
        wrkMast.setIoType(10); // 入出库状态:10.空板入库
        wrkMast.setIoPri(10D); // 优先级:10
        wrkMast.setCrnNo(dto.getCrnNo());
src/main/java/com/zy/asrs/service/impl/WrkMastLogServiceImpl.java
@@ -11,6 +11,7 @@
import com.zy.asrs.mapper.WrkMastLogMapper;
import com.zy.asrs.service.WrkMastLogService;
import com.zy.asrs.service.WrkMastService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -20,6 +21,7 @@
import java.util.Objects;
@Service("wrkMastLogService")
@Slf4j
public class WrkMastLogServiceImpl extends ServiceImpl<WrkMastLogMapper, WrkMastLog> implements WrkMastLogService {
    @Autowired
@@ -28,21 +30,8 @@
    private WrkMastLogService wrkMastLogService;
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(Integer workNo) {
        WrkMast mast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", workNo));
        if (Objects.isNull(mast)) {
            throw new CoolException("数据错误:任务不存在!!");
        }
        WrkMastLog mastLog = new WrkMastLog();
        BeanUtils.copyProperties(mast, mastLog);
        mastLog.setLogId(mast.getId());
        if (!wrkMastLogService.insert(mastLog)) {
            throw new CoolException("任务日志保存失败!!");
        }
        return true;
        return this.baseMapper.save(workNo) > 0;
    }
    @Override
src/main/java/com/zy/asrs/task/AutoLocMoveScheduler.java
File was deleted
src/main/java/com/zy/asrs/task/BareBoardScheduler.java
File was deleted
src/main/java/com/zy/asrs/task/CheckDeepScheduler.java
File was deleted
src/main/java/com/zy/asrs/task/LocMoveAllScheduler.java
File was deleted
src/main/java/com/zy/asrs/task/OrderMoveHistoryScheduler.java
@@ -7,7 +7,7 @@
import org.springframework.stereotype.Component;
@Component
//@Component
public class OrderMoveHistoryScheduler {
    @Autowired
    private OrderPakinMoveHistoryHandler orderPakinMoveHistoryHandler;
src/main/java/com/zy/asrs/task/OrderSyncScheduler.java
@@ -37,17 +37,6 @@
    @Autowired
    private LoadingConfigTimer loadingConfigTimer;
    @Scheduled(cron = "0 0 1 * * ? ")
    public void clearApiLog() {
        try {
            apiLogService.clearWeekBefore();
        } catch (Exception e) {
            log.error("第三方接口日志自动清除失败(范围:一周之前", e);
        }
    }
    @Scheduled(cron = "0/30 * * * * ? ")
    @Async("orderThreadPool")
    public void completeOrderPakin() {
@@ -67,7 +56,6 @@
        }
    }
    @Scheduled(cron = "0/30 * * * * ? ")
    @Async("orderThreadPool")
    public void completeOrderPakout() {
@@ -86,4 +74,14 @@
            }
        }
    }
    @Scheduled(cron = "0 0 1 * * ? ")
    public void clearApiLog() {
        try {
            apiLogService.clearWeekBefore();
        } catch (Exception e) {
            log.error("第三方接口日志自动清除失败(范围:一周之前", e);
        }
    }
}
src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -49,7 +49,7 @@
        }
    }
    @Scheduled(cron = "0/3 * * * * ? ")
//    @Scheduled(cron = "0/3 * * * * ? ")
    private void executeTask() {
        List<Task> wrkMasts = taskService.selectToBeCompleteData();
        if (wrkMasts.isEmpty()) {
src/main/java/com/zy/asrs/task/handler/AutoLocMoveHandler.java
File was deleted
src/main/java/com/zy/asrs/task/handler/OrderPakinSyncHandler.java
@@ -1,6 +1,12 @@
package com.zy.asrs.task.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.DocType;
import com.zy.asrs.entity.OrderDetl;
import com.zy.asrs.entity.OrderDetlPakin;
import com.zy.asrs.entity.OrderPakin;
import com.zy.asrs.service.ApiLogService;
@@ -9,6 +15,9 @@
import com.zy.asrs.service.OrderPakinService;
import com.zy.asrs.task.AbstractHandler;
import com.zy.asrs.task.core.ReturnT;
import com.zy.common.constant.MesConstant;
import com.zy.common.model.MesPakinParam;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -35,14 +44,59 @@
    @Transactional
    public ReturnT<String> startOrderReport(OrderPakin order) {
        DocType docType = docTypeService.selectById(order.getDocType());
        if (null == docType) {
            return SUCCESS;
            log.error("未找到对应的DocType,订单号:{},单据类型:{}", order.getOrderNo(), order.getDocType());
            return FAIL.setMsg("未找到对应的单据类型:" + order.getOrderNo());
        }
        long settle = 6L;
        List<OrderDetlPakin> orderDetls = orderDetlPakinService.selectByOrderId(order.getId());
        return SUCCESS;
        MesPakinParam pakinParam = new MesPakinParam();
        List<OrderDetlPakin> orderDetls = orderDetlPakinService.selectByOrderId(order.getId());
        for (OrderDetlPakin orderDetl : orderDetls) {
            String serial = Cools.isEmpty(orderDetl.getBatch()) ? "" : orderDetl.getBatch();
            pakinParam.getList().add(new MesPakinParam.Detl(orderDetl.getMatnr() + (Cools.isEmpty(serial) ? "" : "-" + serial), orderDetl.getAnfme()));
        }
        String response = "";
        boolean success = false;
        ReturnT<String> result = SUCCESS;
        try {
            response = new HttpHandler.Builder()
                    .setUri(MesConstant.URI)
                    .setPath(MesConstant.PAKIN_PATH)
                    .setJson(JSON.toJSONString(pakinParam))
                    .build()
                    .doPost();
            JSONObject jsonObject = JSON.parseObject(response);
            if (jsonObject.getInteger("code").equals(200)) {
                // 修改订单状态 4.完成 ===>> 6.已上报
                orderPakinService.updateSettle(order.getId(), 6L, null);
                success = true;
            } else {
                log.error("入库完成上报erp失败!url:{};request:{};response:{}", MesConstant.URI + MesConstant.PAKIN_PATH, JSON.toJSONString(pakinParam), response);
                throw new CoolException("入库完成上报erp失败");
            }
        } catch (Exception e) {
            log.error("入库完成上报erp异常", e);
            result = FAIL.setMsg("入库完成上报异常:" + e.getMessage());
        } finally {
            try {
                // 保存接口日志
                apiLogService.save(
                        "入库完成上报",
                        MesConstant.URI + MesConstant.PAKIN_PATH,
                        null,
                        "127.0.0.1",
                        JSON.toJSONString(pakinParam),
                        response,
                        success
                );
            } catch (Exception e) {
                log.error("入库保存接口日志异常", e);
            }
        }
        return result;
    }
}
src/main/java/com/zy/asrs/task/handler/OrderPakoutSyncHandler.java
@@ -1,6 +1,12 @@
package com.zy.asrs.task.handler;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.core.common.Cools;
import com.core.common.DateUtils;
import com.core.exception.CoolException;
import com.zy.asrs.entity.DocType;
import com.zy.asrs.entity.OrderDetl;
import com.zy.asrs.entity.OrderDetlPakout;
import com.zy.asrs.entity.OrderPakout;
import com.zy.asrs.service.ApiLogService;
@@ -9,6 +15,9 @@
import com.zy.asrs.service.OrderPakoutService;
import com.zy.asrs.task.AbstractHandler;
import com.zy.asrs.task.core.ReturnT;
import com.zy.common.constant.MesConstant;
import com.zy.common.model.MesPakoutParam;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@@ -35,14 +44,61 @@
    @Transactional
    public ReturnT<String> startOrderReport(OrderPakout order) {
        DocType docType = docTypeService.selectById(order.getDocType());
        if (null == docType) {
            return SUCCESS;
            log.error("未找到对应的DocType,订单号:{},单据类型:{}", order.getOrderNo(), order.getDocType());
            return FAIL.setMsg("未找到对应的单据类型:" + order.getOrderNo());
        }
        long settle = 6L;
        List<OrderDetlPakout> orderDetls = orderDetlPakoutService.selectByOrderId(order.getId());
        return SUCCESS;
        MesPakoutParam pakoutParam = new MesPakoutParam();
        pakoutParam.setTag(!order.getDocType$().equalsIgnoreCase("手动出库单"));
        pakoutParam.setOrderNo(order.getOrderNo());
        List<OrderDetlPakout> orderDetls = orderDetlPakoutService.selectByOrderId(order.getId());
        for (OrderDetlPakout orderDetl : orderDetls) {
            String serial = Cools.isEmpty(orderDetl.getBatch()) ? "" : orderDetl.getBatch();
            pakoutParam.getList().add(new MesPakoutParam.Detl(orderDetl.getMatnr() + (Cools.isEmpty(serial) ? "" : "-" + serial), orderDetl.getAnfme()));
        }
        String response = "";
        boolean success = false;
        ReturnT<String> result = SUCCESS;
        try {
            response = new HttpHandler.Builder()
                    .setUri(MesConstant.URI)
                    .setPath(MesConstant.PAKOUT_PATH)
                    .setJson(JSON.toJSONString(pakoutParam))
                    .build()
                    .doPost();
            JSONObject jsonObject = JSON.parseObject(response);
            if (jsonObject.getInteger("code").equals(200)) {
                // 修改订单状态 4.完成 ===>> 6.已上报
                orderPakoutService.updateSettle(order.getId(), 6L, null);
                success = true;
            } else {
                log.error("出库完成上报erp失败!url:{};request:{};response:{}", MesConstant.URI + MesConstant.PAKOUT_PATH, JSON.toJSONString(pakoutParam), response);
                throw new CoolException("出库完成上报erp失败");
            }
        } catch (Exception e) {
            log.error("出库完成上报erp异常", e);
            result = FAIL.setMsg("出库完成上报异常:" + e.getMessage());
        } finally {
            try {
                // 保存接口日志
                apiLogService.save(
                        "出库完成上报",
                        MesConstant.URI + MesConstant.PAKOUT_PATH,
                        null,
                        "127.0.0.1",
                        JSON.toJSONString(pakoutParam),
                        response,
                        success
                );
            } catch (Exception e) {
                log.error("出库保存接口日志异常", e);
            }
        }
        return result;
    }
}
src/main/java/com/zy/common/config/ThreadPoolConfig.java
@@ -2,6 +2,7 @@
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
@@ -15,6 +16,7 @@
public class ThreadPoolConfig {
    @Bean(name = "orderThreadPool")
    @Primary
    public ThreadPoolTaskExecutor orderThreadPool() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        int core = Runtime.getRuntime().availableProcessors();
src/main/java/com/zy/common/constant/MesConstant.java
@@ -5,13 +5,17 @@
 */
public class MesConstant {
    public static final String URL = "http://192.168.99.130:80";
    // ERP对接基础地址
//    public static final String URI = "http://192.168.99.130:80";
    public static final String URI = "http://127.0.0.1:8080/yhfzwms/open/asrs";
    public static final String PACK_DOWN_URL = "mes/api/zy/v1/packDown/sendList";
    public static final String PAKIN_URL = "mes/api/zy/v1/warehouse/sendList";
    // 入库完成上报路径
    public static final String PAKIN_PATH = "/inOrderFinishReport";
    public static final String PAKOUT_URL = "wmsFinprd/api/zy/v1/packOut/sendList";
    // 出库完成上报路径
    public static final String PAKOUT_PATH = "/outOrderFinishReport";
    /**
src/main/java/com/zy/common/properties/SlaveWmsParameterProperties.java
File was deleted
src/main/java/com/zy/common/service/CommonService.java
@@ -18,7 +18,8 @@
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
import java.util.*;
import java.util.stream.Collectors;
/**
 * 货架核心功能
@@ -50,6 +51,9 @@
    private SlaveProperties slaveProperties;
    @Autowired
    private WrkDetlService wrkDetlService;
    // 深库位排
    private static final List<Integer> deepLocRowList = Arrays.asList(1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32);
    /**
     * 生成工作号
@@ -91,6 +95,102 @@
        return workNo;
    }
    /**
     * 获取库位---山东宜和纺织
     *
     * @param sourceSiteNo 入库源站点
     */
    public StartupDto getLocNoBySdyhfz(Integer sourceSiteNo,int ioType) {
        // 获取可用,可入,无报警堆垛机
        List<BasCrnp> basCrnps = basCrnpService.selectList(new EntityWrapper<BasCrnp>().eq("crn_sts", 3).eq("crn_err", 0).eq("in_enable", "Y"));
        if (basCrnps.size() == 0) {
            log.error(sourceSiteNo + "入库请求库位失败:堆垛机报警/无可用/无可入");
            throw new CoolException(sourceSiteNo + "入库请求库位失败:堆垛机报警/无可用/无可入");
        }
        // 计算负载均衡
        List<CraneLoadInfo> craneInfos = new ArrayList<>();
        // 负载均衡权重(可调整)任务少,库位占用少的先分配
        double w1 = 0.6; // 任务数权重
        double w2 = 0.4; // 仓位权重
        for (BasCrnp basCrnp : basCrnps) {
            // 挂载任务数
            int taskCount = locMastService.selectCount(new EntityWrapper<LocMast>().eq("crn_no", basCrnp.getCrnNo()).in("loc_sts", "S", "R"));
            // 空库位数量
            int emptyCount = locMastService.selectCount(new EntityWrapper<LocMast>().eq("crn_no", basCrnp.getCrnNo()).eq("loc_sts", "O"));
            // 库位占用率
            double emptyLocOccupancy = (double) (800 - emptyCount) / 800;
            CraneLoadInfo craneLoadInfo = new CraneLoadInfo();
            craneLoadInfo.setCrnNo(basCrnp.getCrnNo());
            craneLoadInfo.setTaskCount(taskCount);
            craneLoadInfo.setOccupancy(emptyLocOccupancy);
            craneInfos.add(craneLoadInfo);
        }
        // 获取最值
        int taskMax = craneInfos.stream().mapToInt(CraneLoadInfo::getTaskCount).max().orElse(0);
        int taskMin = craneInfos.stream().mapToInt(CraneLoadInfo::getTaskCount).min().orElse(0);
        double occMax = craneInfos.stream().mapToDouble(CraneLoadInfo::getOccupancy).max().orElse(0);
        double occMin = craneInfos.stream().mapToDouble(CraneLoadInfo::getOccupancy).min().orElse(0);
        // 避免分母为0的情况
        double taskRange = (taskMax - taskMin) == 0 ? 1 : (taskMax - taskMin);
        double occRange = (occMax - occMin) == 0 ? 1 : (occMax - occMin);
        // 计算 α
        for (CraneLoadInfo info : craneInfos) {
            double taskNorm = (info.getTaskCount() - taskMin) / taskRange;
            double occNorm = (info.getOccupancy() - occMin) / occRange;
            double alpha = w1 * taskNorm + w2 * occNorm;
            info.setAlpha(alpha);
        }
        // 排序:α 越小越空闲
        craneInfos.sort(Comparator.comparingDouble(CraneLoadInfo::getAlpha));
        // 寻找库位
        LocMast locMast = null;
        // 根据入库类型和源站点获取工作路径
        StaDesc staDesc = null;
        for (CraneLoadInfo craneLoadInfo : craneInfos) {
            List<LocMast> locMastList = locMastService.selectList(new EntityWrapper<LocMast>().eq("crn_no", craneLoadInfo.getCrnNo()).eq("loc_sts", "O").orderBy("lev1").orderBy("bay1").orderBy("row1"));
            if (locMastList.size() <= 4) {
                continue;
            }
            // 先取深库位
            Optional<LocMast> first = locMastList.stream().filter(o -> deepLocRowList.contains(o.getRow1())).findFirst();
            // 深库位里面没有从浅库位里面取
            locMast = first.orElseGet(() -> locMastList.get(0));
            if (locMast != null) {
                staDesc = staDescService.selectOne(new EntityWrapper<StaDesc>().eq("type_no", ioType).eq("crn_no", locMast.getCrnNo()).eq("stn_no", sourceSiteNo));
                if (staDesc == null) {
                    log.error("获取工作路径异常,类型:{},堆垛机:{},源站:{}", ioType, locMast.getCrnNo(), sourceSiteNo);
                    throw new CoolException("获取工作路径异常,类型:" + ioType + ",堆垛机:" + locMast.getCrnNo() + ",源站:" + sourceSiteNo);
                }
                break;
            }
        }
        if (locMast == null) {
            log.error("堆垛机剩余库位不足:{}", craneInfos);
            throw new CoolException("堆垛机不可用/库位不足,请检查");
        }
        // 生成工作号
        int workNo = getWorkNo(0);
        // 返回dto
        StartupDto startupDto = new StartupDto();
        startupDto.setWorkNo(workNo);
        startupDto.setCrnNo(locMast.getCrnNo());
        startupDto.setSourceStaNo(sourceSiteNo);
        startupDto.setStaNo(staDesc.getCrnStn());
        startupDto.setLocNo(locMast.getLocNo());
        return startupDto;
    }
    //拆盘机处空板扫码,驱动托盘向码垛位,不入库
    @Transactional
    public StartupDto getScanBarcodeEmptyBoard() {
src/main/java/com/zy/common/web/WcsController.java
@@ -164,11 +164,8 @@
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        // 检索库位
//        List<String> matnrs = waitPakins.stream().map(WaitPakin::getMatnr).distinct().collect(Collectors.toList());
//        List<String> batchs = waitPakins.stream().map(WaitPakin::getBatch).distinct().collect(Collectors.toList());
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(matnrs.get(0), batchs.get(0));
        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(waitPakins.get(0));
        StartupDto dto = commonService.getLocNo(1, devpNo, findLocNoAttributeVo, locTypeDto);
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo(waitPakins.get(0));
        StartupDto dto = commonService.getLocNoBySdyhfz(devpNo,1);
        int workNo = dto.getWorkNo();
        Date now = new Date();
        // 生成工作档
@@ -243,9 +240,10 @@
        // 源站点状态检测
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(devpNo, true);
        // 检索库位
        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo();
//        FindLocNoAttributeVo findLocNoAttributeVo = new FindLocNoAttributeVo();
        StartupDto dto = commonService.getLocNo(10, devpNo, findLocNoAttributeVo, locTypeDto);
//        StartupDto dto = commonService.getLocNo(10, devpNo, findLocNoAttributeVo, locTypeDto);
        StartupDto dto = commonService.getLocNoBySdyhfz(devpNo,10);
        int workNo = dto.getWorkNo();
        // 生成工作档
        WrkMast wrkMast = new WrkMast();
src/main/resources/application-dev.yml
@@ -29,11 +29,11 @@
  mapper-locations: classpath:mapper/*.xml
  #  global-config:
  #    field-strategy: 0
  configuration:
#  configuration:
    #    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
    cache-enabled: true
    call-setters-on-nulls: true
#    map-underscore-to-camel-case: true
#    cache-enabled: true
#    call-setters-on-nulls: true
logging:
  file:
@@ -58,13 +58,13 @@
  # 双深
  doubleDeep: true
  # 双深库位排号
  doubleLocs: 1,4,5,8,9,12,13,16
  doubleLocs: 1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32
  # 一个堆垛机负责的货架排数
  groupCount: 4
  # 左深库位排号
  doubleLocsLeft: 1,5,9,13
  doubleLocsLeft: 1,5,9,13,17,21,25,29
  # 右深库位排号
  doubleLocsRight: 4,8,12,16
  doubleLocsRight: 4,8,12,16,20,24,28,32
src/main/resources/application-prod.yml
@@ -29,11 +29,11 @@
  mapper-locations: classpath:mapper/*.xml
  #  global-config:
  #    field-strategy: 0
  configuration:
#  configuration:
#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
    map-underscore-to-camel-case: true
    cache-enabled: true
    call-setters-on-nulls: true
#    map-underscore-to-camel-case: true
#    cache-enabled: true
#    call-setters-on-nulls: true
logging:
  file:
@@ -58,11 +58,11 @@
  # 双深
  doubleDeep: true
  # 双深库位排号
  doubleLocs: 1,4,5,8,9,12,13,16
  doubleLocs: 1,4,5,8,9,12,13,16,17,20,21,24,25,28,29,32
  # 一个堆垛机负责的货架排数
  groupCount: 4
  # 左深库位排号
  doubleLocsLeft: 1,5,9,13
  doubleLocsLeft: 1,5,9,13,17,21,25,29
  # 右深库位排号
  doubleLocsRight: 4,8,12,16
  doubleLocsRight: 4,8,12,16,20,24,28,32
src/main/resources/mapper/ViewStockUseMapper.xml
@@ -2,6 +2,16 @@
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.zy.asrs.mapper.ReportQueryMapper">
    <resultMap id="ViewStockUseMap" type="com.zy.asrs.entity.ViewStockUseBean">
        <result property="row1" column="row1"/>
        <result property="total_qty" column="total_qty"/>
        <result property="full_qty" column="full_qty"/>
        <result property="null_qty" column="null_qty"/>
        <result property="forbid_qty" column="forbid_qty"/>
        <result property="empty_qty" column="empty_qty"/>
        <result property="full_rate" column="full_rate"/>
        <result property="occ_rate" column="occ_rate"/>
    </resultMap>
<!-- mapper不支持sql语句嵌套时,采用sql片段包含方式,解决xml标签问题 -->
<sql id="viewStockUseConditionSql">    
@@ -11,10 +21,10 @@
</sql>
<!-- 分页查询所有信息 -->
<select id="queryViewStockUseList" parameterType="com.zy.asrs.entity.ViewStockUseBean" resultType="com.zy.asrs.entity.ViewStockUseBean">
select top (#{pageSize}) * from asr_stk_use_view
<select id="queryViewStockUseList" parameterType="com.zy.asrs.entity.ViewStockUseBean" resultMap="ViewStockUseMap">
select top (#{pageSize}) * from asr_stk_use_view
<where>
    row1 not in (select top ((#{pageNumber}-1)*#{pageSize}) row1 from asr_stk_use_view
    row1 not in (select top ((#{pageNumber}-1)*#{pageSize}) row1 from asr_stk_use_view
    <where>
        1=1
        <include refid="viewStockUseConditionSql"></include>        
src/main/resources/mapper/WrkMastLogMapper.xml
@@ -5,6 +5,7 @@
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.zy.asrs.entity.WrkMastLog">
        <id column="id" property="id" />
        <result column="task_type" property="taskType" />
        <result column="wrk_no" property="wrkNo" />
        <result column="inv_wh" property="invWh" />
        <result column="ymd" property="ymd" />
@@ -51,7 +52,7 @@
        <result column="error_memo" property="errorMemo" />
        <result column="ctn_kind" property="ctnKind" />
        <result column="manu_type" property="manuType" />
        <result column="memo_m" property="memoM" />
        <result column="memo" property="memo" />
        <result column="sc_weight" property="scWeight" />
        <result column="log_mk" property="logMk" />
        <result column="log_err_time" property="logErrTime" />
src/main/resources/mapper/WrkMastMapper.xml
@@ -4,7 +4,9 @@
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.zy.asrs.entity.WrkMast">
        <id column="wrk_no" property="wrkNo" />
        <id column="id" property="id" />
        <result column="wrk_no" property="wrkNo" />
        <result column="task_type" property="taskType" />
        <result column="inv_wh" property="invWh" />
        <result column="ymd" property="ymd" />
        <result column="mk" property="mk" />
src/main/webapp/views/order/order.html
@@ -79,20 +79,20 @@
                        <button class="layui-btn icon-btn" lay-filter="tbSearch" lay-submit>
                            <i class="layui-icon">&#xe615;</i>搜索
                        </button>
                        <button id="orderAddBtn" class="layui-btn icon-btn btn-add"><i class="layui-icon">&#xe654;</i>添加
                        </button>
<!--                        <button id="orderAddBtn" class="layui-btn icon-btn btn-add"><i class="layui-icon">&#xe654;</i>添加-->
<!--                        </button>-->
                    </div>
                </div>
            </div>
            <table id="order" lay-filter="order"></table>
        </div>
    </div>
    <div class="layui-card">
        <div class="layui-card-body">
            入库通知单:由ERP提供单据编号、类型、单据时间及物料明细,生成入库作业单,为维护系统高可用,用户可自行添加入库通知单数据,完成独立的入库作业。
            <span class="text-danger">手动添加时,请检查单据编号是否在ERP系统中已存在,避免发生数据错误问题。</span>
        </div>
    </div>
<!--    <div class="layui-card">-->
<!--        <div class="layui-card-body">-->
<!--            入库通知单:由ERP提供单据编号、类型、单据时间及物料明细,生成入库作业单,为维护系统高可用,用户可自行添加入库通知单数据,完成独立的入库作业。-->
<!--            <span class="text-danger">手动添加时,请检查单据编号是否在ERP系统中已存在,避免发生数据错误问题。</span>-->
<!--        </div>-->
<!--    </div>-->
</div>
<!-- 表格操作列 -->
<script type="text/html" id="operate">
src/main/webapp/views/orderPakin/order.html
@@ -150,8 +150,8 @@
                <input class="layui-input" name="docType" placeholder="请输入单据类型" style="display: none">
                <input id="docType$" name="docType$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入单据类型" onfocus=this.blur() lay-verType="tips" lay-verify="required">
                <div class="cool-auto-complete-window">
                    <input class="cool-auto-complete-window-input" data-key="docTypeQueryBydocType" onkeyup="autoLoad(this.getAttribute('data-key'))">
                    <select class="cool-auto-complete-window-select" data-key="docTypeQueryBydocTypeSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                    <input class="cool-auto-complete-window-input" data-key="docTypeQueryInBydocType" onkeyup="autoLoad(this.getAttribute('data-key'))">
                    <select class="cool-auto-complete-window-select" data-key="docTypeQueryInBydocTypeSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                    </select>
                </div>
            </div>
src/main/webapp/views/orderPakout/order.html
@@ -150,8 +150,8 @@
                <input class="layui-input" name="docType" placeholder="请输入单据类型" style="display: none">
                <input id="docType$" name="docType$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入单据类型" onfocus=this.blur() lay-verType="tips" lay-verify="required">
                <div class="cool-auto-complete-window">
                    <input class="cool-auto-complete-window-input" data-key="docTypeQueryBydocType" onkeyup="autoLoad(this.getAttribute('data-key'))">
                    <select class="cool-auto-complete-window-select" data-key="docTypeQueryBydocTypeSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                    <input class="cool-auto-complete-window-input" data-key="docTypeQueryOutBydocType" onkeyup="autoLoad(this.getAttribute('data-key'))">
                    <select class="cool-auto-complete-window-select" data-key="docTypeQueryOutBydocTypeSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple">
                    </select>
                </div>
            </div>
version/v1.0.0/truncate.sql
@@ -10,4 +10,20 @@
truncate table sys_user_login;
truncate table man_api_log;
truncate table asr_bas_err_log
truncate table asr_bas_devp_err_log
truncate table asr_bas_devp_err_log
TRUNCATE table asr_loc_detl
TRUNCATE table man_order
TRUNCATE table man_order_detl
TRUNCATE table man_order_log
TRUNCATE table man_order_detl_log
TRUNCATE table man_order_pakin
TRUNCATE table man_order_detl_pakin
TRUNCATE table man_order_log_pakin
TRUNCATE table man_order_detl_log_pakin
TRUNCATE table man_order_pakout
TRUNCATE table man_order_detl_pakout
TRUNCATE table man_order_log_pakout
TRUNCATE table man_order_detl_log_pakout