自动化立体仓库 - WMS系统
skyouc
4 天以前 dcd2e9ad65580de56147956e718059f50f1691d2
no message
9个文件已修改
6个文件已添加
970 ■■■■■ 已修改文件
src/main/java/com/zy/api/controller/WcsApiController.java 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/ReceviceTaskParams.java 46 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/params/WorkTaskParams.java 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/entity/dto/LocMastDto.java 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/WcsApiService.java 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java 233 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/MobileController.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/WrkMast.java 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/CompleteParam.java 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/MobileService.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/BasContainerServiceImpl.java 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 102 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/WorkMastScheduler.java 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/constant/MesConstant.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/service/CommonService.java 283 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/api/controller/WcsApiController.java
New file
@@ -0,0 +1,83 @@
package com.zy.api.controller;
import com.core.annotations.ManagerAuth;
import com.core.common.R;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.service.WcsApiService;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.Map;
import java.util.Objects;
@Api("WCS交互接口")
@RequestMapping("/wcs")
@RestController
public class WcsApiController {
    @Autowired
    private WcsApiService wcsApiService;
    /**
     * 獲取庫位信息
     * @param params
     * @return
     */
    @ManagerAuth
    @ApiOperation("同步库位信息")
    @PostMapping("/sync/locs")
    public R getAllLocs(@RequestBody Map<String, String> params) {
        return wcsApiService.getLocs(params);
    }
    /**
     * 获取站点信息
     * @param params
     * @return
     */
    @ManagerAuth
    @ApiOperation("获取站点信息")
    @PostMapping("sync/stations")
    public R getAllStation(@RequestBody Map<String, String> params) {
        return wcsApiService.getStations(params);
    }
    /**
     * 下发任务至WCS
     * @author Ryan
     * @date 2026/1/10 13:57
     * @param params
     * @return com.core.common.R
     */
    @ManagerAuth
    @ApiOperation("下发任务至WCS")
    @PostMapping("/pub/wrks")
    public R pubWrkToWcs(@RequestBody WorkTaskParams params) {
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        return wcsApiService.pubWrkToWcs(params);
    }
    @ManagerAuth
    @ApiOperation("设备执行状态回写")
    @PostMapping("/openapi/report")
    public R receviceTaskFromWcs(@RequestBody ReceviceTaskParams params) {
        if (Objects.isNull(params)) {
            return R.error("参数不能为空!!");
        }
        return wcsApiService.receviceTaskFromWcs(params);
    }
}
src/main/java/com/zy/api/controller/params/ReceviceTaskParams.java
New file
@@ -0,0 +1,46 @@
package com.zy.api.controller.params;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "ReceviceTaskParams", description = "穿线墙参数")
public class ReceviceTaskParams implements Serializable {
    @ApiModelProperty("机台号")
    private String deviceNo;
    @ApiModelProperty("流水号")
    private Integer id;
    @ApiModelProperty("通知类型:task")
    private String notifyType;
    @ApiModelProperty("堆垛机号")
    private Integer device;
    @ApiModelProperty("WCS任务号")
    private String taskNo;
    @ApiModelProperty("WMS任务号")
    private String wrkNo;
    @ApiModelProperty("消息类型:task_complete、task_cancel")
    private String msgType;
    @ApiModelProperty("消息描述")
    private String msgDesc;
    @ApiModelProperty("消息数据")
    private String data;
    @ApiModelProperty("重量")
    private Double weight;
}
src/main/java/com/zy/api/controller/params/WorkTaskParams.java
New file
@@ -0,0 +1,42 @@
package com.zy.api.controller.params;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "WorkTaskParams", description = "执行任务参数")
public class WorkTaskParams implements Serializable {
    private static final long serialVersionUID = 1L;
    @ApiModelProperty("协议任务编号(对应出库任务号)")
    private String taskNo;
    @ApiModelProperty("工作档任务号")
    private String wrkNo;
    @ApiModelProperty("库位编码")
    private String locNo;
    @ApiModelProperty("条码")
    private String barcode;
    @ApiModelProperty("优先级")
    private Integer taskPri;
    @ApiModelProperty("出库站点")
    private String staNo;
    @ApiModelProperty("作业类型,in: 入库, out:出库")
    private String type;
    @ApiModelProperty("是否余料")
    private Integer isSuplus;
}
src/main/java/com/zy/api/entity/dto/LocMastDto.java
New file
@@ -0,0 +1,27 @@
package com.zy.api.entity.dto;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.experimental.Accessors;
import java.io.Serializable;
@Data
@Accessors(chain = true)
@ApiModel(value = "LocMastDto", description = "库位信息")
public class LocMastDto implements Serializable {
    @ApiModelProperty("库位信息")
    private String locNo;
    private String locSts;
    private String barcode;
    private Integer row;
    private Integer bay;
    private Integer lev;
}
src/main/java/com/zy/api/service/WcsApiService.java
New file
@@ -0,0 +1,71 @@
package com.zy.api.service;
import com.core.common.R;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import java.util.Map;
import java.util.Set;
public interface WcsApiService {
    /**
     * 锁定库位信息
     * @author Ryan
     * @date 2026/1/10 11:17
     * @param params
     * @return com.core.common.R
     */
    R lockLocs(ReceviceTaskParams params);
//    /**
//     * 回库搬运指令
//     * @author Ryan
//     * @date 2026/1/10 13:08
//     * @param params
//     * @return com.core.common.R
//     */
//    R backLocs(WorkTaskParams params);
    /**
     * 下发任务至WCS
     * @author Ryan
     * @date 2026/1/10 13:57
     * @param params
     * @return com.core.common.R
     */
    R pubWrkToWcs(WorkTaskParams params);
//
//    /**
//     * 锁定或释放库位
//     * @author Ryan
//     * @date 2026/1/10 14:35
//     * @param locs
//     * @param type
//     */
//    void reportLockLocs(Set<String> locs, String type);
    /**
     * 堆垛机任务完成状态上报
     * @author Ryan
     * @date 2026/1/10 16:29
     * @param params
     * @return com.core.common.R
     */
    R receviceTaskFromWcs(ReceviceTaskParams params);
    /**
     * 獲取庫位信息
     * @param params
     * @return
     */
    R getLocs(Map<String, String> params);
    /**
     * 获取站点信息
     * @param params
     * @return
     */
    R getStations(Map<String, String> params);
}
src/main/java/com/zy/api/service/impl/WcsApiServiceImpl.java
New file
@@ -0,0 +1,233 @@
package com.zy.api.service.impl;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.core.common.Cools;
import com.core.common.R;
import com.core.exception.CoolException;
import com.zy.api.controller.params.ReceviceTaskParams;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.entity.dto.LocMastDto;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.*;
import com.zy.asrs.service.*;
import com.zy.asrs.service.impl.LocDetlServiceImpl;
import com.zy.asrs.service.impl.MatServiceImpl;
import com.zy.asrs.service.impl.WrkDetlServiceImpl;
import com.zy.common.constant.MesConstant;
import com.zy.common.utils.HttpHandler;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@Service
public class WcsApiServiceImpl implements WcsApiService {
    @Autowired
    private LocMastService locMastService;
    @Autowired
    private WrkMastService wrkMastService;
    @Autowired
    private WorkService workService;
    @Autowired
    private WrkDetlService wrkDetlService;
    @Autowired
    private MatService matService;
    @Autowired
    private LocDetlService locDetlService;
    /**
     * 通知WCS锁定库位,及禁止当前库位的一切操作
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2026/1/10 11:18
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R lockLocs(ReceviceTaskParams params) {
//        BasDevice basDevice = basDeviceService.selectOne(new EntityWrapper<BasDevice>()
//                .eq("status", 1)
//                .eq("dev_no", params.getDeviceNo()));
//        if (Objects.isNull(basDevice)) {
//            throw new CoolException("机台信息不存在或已禁用!!");
//        }
//        List<LocAroundBind> binds = locAroundBindService.selectList(new EntityWrapper<LocAroundBind>().eq("dev_no", basDevice.getDevNo()));
//        if (Objects.isNull(binds) || binds.isEmpty()) {
//            throw new CoolException("机台未绑定工作站台!!");
//        }
//        Set<String> locs = binds.stream().map(LocAroundBind::getBlocNo).collect(Collectors.toSet());
//
//        reportLockLocs(locs, "lock");
        return R.ok("上报成功!!");
    }
//    /**
//     * 余料回库 (搬运余料回库)
//     *
//     * @param params
//     * @return com.core.common.R
//     * @author Ryan
//     * @date 2026/1/10 13:19
//     */
//    @Override
//    @Transactional(rollbackFor = Exception.class)
//    public R backLocs(WorkTaskParams params) {
//        if (Objects.isNull(params.getWrkNo())) {
//            throw new CoolException("工作号不能为空!!");
//        }
////        String wrkCode = params.getTaskNo();
////       if (wrkCode.contains("-1")) {
////           throw new CoolException("配对任务编码错误,请检查后重新上传!!");
////       }
//        WrkMast mast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", params.getWrkNo()));
//        if (Objects.isNull(mast)) {
//            throw new CoolException("任务不存在!!");
//        }
////       if (!mast.getWrkSts().equals(103L)) {
////           throw new CoolException("当前任务并非余料出库任务!!");
////       }
////       if (params.getIsSuplus() == 1) {
////           mast.setIsSuplus(1);
////       }
////
////       if (!wrkMastService.updateById(mast)) {
////           throw new CoolException("任务状态更新失败!!");
////       }
//        workService.backLocOperation(mast.getWrkNo() + "", mast.getAppeUser());
//
//        return R.ok("接收成功,执行回库中...");
//    }
    /**
     * 下发任务至WCS
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2026/1/10 13:58
     */
    @Override
    public R pubWrkToWcs(WorkTaskParams params) {
        if (Objects.isNull(params.getTaskNo())) {
            return R.error("任务号不能为空!!");
        }
        if (Objects.isNull(params.getBarcode())) {
            return R.error("托盘码不能为空!!");
        }
        if (Objects.isNull(params.getLocNo())) {
            return R.error("目标库位不能为空!!");
        }
        String url = MesConstant.PUB_TASK_IN;
        if (Objects.isNull(params.getType()) && params.getType().equals("out")) {
            url = MesConstant.PUB_TASK_OUT;
        }
        String response;
        try {
            response = new HttpHandler.Builder()
                    .setUri(MesConstant.URL)
                    .setPath(url)
                    .setJson(JSON.toJSONString(params))
                    .build()
                    .doPost();
            R result = JSON.parseObject(response, R.class);
            if (result.get("code").equals("200")) {
                //TODO 上报是否成功
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }
    /**
     * 堆垛机执行状态上报
     *
     * @param params
     * @return com.core.common.R
     * @author Ryan
     * @date 2026/1/10 16:30
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R receviceTaskFromWcs(ReceviceTaskParams params) {
        if (Objects.isNull(params.getWrkNo())) {
            throw new CoolException("WMS任务号不能为空!!");
        }
        if (Objects.isNull(params.getNotifyType())) {
            throw new CoolException("动作类型不能为空!!");
        }
        WrkMast mast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("wrk_no", params.getWrkNo()));
        if (Objects.isNull(mast)) {
            throw new CoolException("任务档不存在!!");
        }
        if (params.getNotifyType().equals("task")) {
            //任务
            if (params.getMsgType().equals("task_complete")) {
                if (mast.getIoType() == 1) {
                    mast.setWrkSts(4L);
                } else if (mast.getIoType() == 101) {
                    mast.setWrkSts(14L);
                }
                if (!wrkMastService.updateById(mast)) {
                    throw new CoolException("任务状态修改失败!!");
                }
            } else if (params.getMsgType().equals("task_cancel")) {
                //todo 取消任务
            }
        }
        return R.ok();
    }
    /**
     * 獲取庫位信息
     * @param params
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R getLocs(Map<String, String> params) {
        String url = MesConstant.SYN_LOCS;
        String response;
        try {
            response = new HttpHandler.Builder()
                    .setUri(MesConstant.WCS_URL)
                    .setPath(url)
                    .setJson(JSON.toJSONString(params))
                    .build()
                    .doPost();
            JSONObject jsonObject = JSONObject.parseObject(response);
            if (jsonObject.get("code").equals(200)) {
                List<LocMastDto> dtos = JSONArray.parseArray(jsonObject.get("data").toString(), LocMastDto.class);
                dtos.forEach(e -> {
                    LocMast locMast = new LocMast();
                    BeanUtils.copyProperties(e, locMast);
                    locMast.setRow1(e.getRow());
                    locMast.setLev1(e.getLev());
                    locMast.setBay1(e.getBay());
                    System.out.println(JSONObject.toJSON(locMast));
                    if (!locMastService.insert(locMast)) {
                        throw new CoolException("库位保存失败!!");
                    }
                });
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return R.ok();
    }
    @Override
    public R getStations(Map<String, String> params) {
        return null;
    }
}
src/main/java/com/zy/asrs/controller/MobileController.java
@@ -374,8 +374,7 @@
        if (Objects.isNull(combParam)) {
            return R.error("参数不能为空!!");
        }
        mobileService.combInPub(combParam, 10031L);
        return R.ok("上架成功");
       return mobileService.combInPub(combParam, 10031L);
    }
    @RequestMapping("/pack/get/auth")
src/main/java/com/zy/asrs/entity/WrkMast.java
@@ -15,6 +15,7 @@
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Objects;
@Data
@TableName("asr_wrk_mast")
@@ -391,8 +392,8 @@
        }
    }
    public String getStaNo$(){
        if (Objects.isNull(this.staNo) || this.staNo.equals("null")) {return  null; }
        BasDevpService service = SpringUtils.getBean(BasDevpService.class);
        BasDevp basDevp = service.selectById(this.staNo);
        if (!Cools.isEmpty(basDevp)){
src/main/java/com/zy/asrs/entity/param/CompleteParam.java
@@ -3,6 +3,7 @@
import lombok.Data;
import java.io.Serializable;
import java.util.List;
@Data
public class CompleteParam implements Serializable {
@@ -12,7 +13,11 @@
    // 库位规格( 0:未知, 1:低库位, 2:高库位)
    private Short locType1;
    private String station;
    //站點
    private String sourceStaNo;
    //可用排
    private List<Integer> rowList;
    private String carBarcode;
src/main/java/com/zy/asrs/service/MobileService.java
@@ -147,7 +147,7 @@
     * @author Ryan
     * @date 2025/12/9 15:04
     */
    void combInPub(CompleteParam combParam, Long userId);
    R combInPub(CompleteParam combParam, Long userId);
    /**
     * SO/EO 区组托
src/main/java/com/zy/asrs/service/impl/BasContainerServiceImpl.java
@@ -10,7 +10,9 @@
import com.zy.asrs.entity.BasContainer;
import com.zy.asrs.service.BasContainerService;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import org.apache.tika.utils.StringUtils;
import org.apache.commons.codec.binary.StringUtils;
import org.apache.poi.util.StringUtil;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
@@ -58,7 +60,10 @@
                prefix = "TC5";
                basContainer.setMixMax(1.0);
            }
            ruleCode = prefix + StringUtils.leftPad(i + "", length, "0");
            String padded = String.format("%07d", Integer.parseInt(i + ""));
            ruleCode = prefix + padded;//StringUtils.leftPad(i + "", length, "0");
            basContainer.setType(container.getType())
                    .setCreateTime(new Date())
                    .setUpdateTime(new Date())
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -1760,53 +1760,44 @@
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public void combInPub(CompleteParam param, Long userId) {
    public R combInPub(CompleteParam param, Long userId) {
        if (Objects.isNull(param.getBarcode())) {
            throw new CoolException("托盘码不能为空!!");
        }
        if (Objects.isNull(param.getStation())) {
        if (Objects.isNull(param.getSourceStaNo())) {
            throw new CoolException("站点不能为空!!");
        }
//        // TODO 修改缓存站点状态及数据
//        Task task = taskService.selectOne(new EntityWrapper<Task>()
//                .eq("wrk_sts", 14L)
//                .eq("barcode", param.getCarBarcode()));
//        if (Objects.isNull(task)) {
//            throw new CoolException("数据错误,任务不存在!!");
//        }
//        List<TaskDetl> taskDetls = taskDetlService
//                .selectList(new EntityWrapper<TaskDetl>().eq("wrk_no", task.getWrkNo()));
//        if (Objects.isNull(taskDetls) || taskDetls.isEmpty()) {
//            throw new CoolException("数据错误,任务明细不存在!!");
//        }
        if (Objects.isNull(param.getLocType1())) {
            param.setLocType1((short)1);
        }
        BasStation station = basStationService.selectOne(new EntityWrapper<BasStation>()
                .eq("dev_no", param.getStation()));
        log.info("WCS任务生成请求参数:", JSONObject.toJSONString(param));
        BasDevp station = basDevpService.selectOne(new EntityWrapper<BasDevp>()
                .eq("dev_no", param.getSourceStaNo()));
        if (Objects.isNull(station)) {
            throw new CoolException("站点不存在!!");
        }
        station.setLocSts(LocStsType.LOC_STS_TYPE_O.type);
        station.setBarcode("");
        if (!basStationService.updateById(station)) {
            throw new CoolException("站点状态修改失败!");
        }
        basStationDetlService.delete(new EntityWrapper<BasStationDetl>().eq("dev_no", station.getDevNo()));
//        // 任务完成
//        task.setWrkSts(15L);
//
//        if (!taskService.updateById(task)) {
//            throw new CoolException("AGV任务完成失败!!");
//        }
        List<WaitPakin> waitPakins = waitPakinService
                .selectList(new EntityWrapper<WaitPakin>().eq("zpallet", param.getBarcode()));
                .selectList(new EntityWrapper<WaitPakin>()
                        .eq("io_status" , "N")
                        .eq("zpallet", param.getBarcode()));
        if (Objects.isNull(waitPakins) || waitPakins.isEmpty()) {
            throw new CoolException("数据错误,组拖档已不存在!!");
        }
        generateCrnInTask(waitPakins, station, param.getLocType1(), userId);
        WrkMast wrkMast = generateCrnInTask(waitPakins, station, param.getLocType1(), userId);
        Map<String, Object> response = new HashMap<>();
        response.put("taskNo", wrkMast.getWrkNo());
        response.put("locNo", wrkMast.getLocNo());
        response.put("taskPri", wrkMast.getIoPri());
        return R.ok("任务生成成功").add(response);
    }
    /**
@@ -1946,18 +1937,18 @@
     * @date 2025/12/9 13:54
     */
    @Transactional(rollbackFor = Exception.class)
    public void generateCrnInTask(List<WaitPakin> waitPakins, BasStation station, Short locType, Long userId) {
    public WrkMast generateCrnInTask(List<WaitPakin> waitPakins, BasDevp station, Short locType, Long userId) {
        Date now = new Date();
        StationRela rela = stationRelaService.selectOne(new EntityWrapper<StationRela>()
                .eq("agv_sta", station.getDevNo())
                .orderAsc(Arrays.asList("crn_sta"))
                .last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"));
//        StationRela rela = stationRelaService.selectOne(new EntityWrapper<StationRela>()
//                .eq("agv_sta", station.getDevNo())
//                .orderAsc(Arrays.asList("crn_sta"))
//                .last("OFFSET 0 ROWS FETCH NEXT 1 ROWS ONLY"));
//
//        if (Objects.isNull(rela)) {
//            throw new CoolException("未绑定作业站点!!");
//        }
        if (Objects.isNull(rela)) {
            throw new CoolException("未绑定作业站点!!");
        }
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(Integer.parseInt(rela.getCrnSta()), true);
        BasDevp sourceStaNo = basDevpService.checkSiteStatus(station.getDevNo(), true);
        sourceStaNo.setLocType1(locType);
        LocTypeDto locTypeDto = new LocTypeDto(sourceStaNo);
        WaitPakin pakin = waitPakins.stream().findFirst().get();
@@ -1965,6 +1956,7 @@
        WrkMast mast = wrkMastService.selectOne(new EntityWrapper<WrkMast>().eq("barcode", pakin.getZpallet()));
        WrkMast wrkMast = new WrkMast();
        String locNo;
        if (!Objects.isNull(mast)) {
            if (mast.getIoType().equals(TaskIOType.MERGE_OUT.type) || mast.getIoType().equals(TaskIOType.PICK_OUT.type) || mast.getIoType().equals(TaskIOType.CHECK_OUT.type)) {
                int ioType = mast.getIoType() - 50;
@@ -1978,6 +1970,7 @@
                if (!res) {
                    throw new CoolException("保存工作档失败");
                }
                locNo = mast.getLocNo();
                // 更新源站点信息
                sourceStaNo.setWrkNo(mast.getWrkNo());
                sourceStaNo.setModiTime(now);
@@ -1998,8 +1991,10 @@
            } else {
                throw new CoolException("托盘已存在任务档!!");
            }
        } else {
            StartupDto dto = commonService.getLocNo(1, sourceStaNo.getDevNo(), findLocNoAttributeVo, locTypeDto);
            int workNo = dto.getWorkNo();
            // 生成工作档
            wrkMast.setWrkNo(workNo);
@@ -2027,6 +2022,7 @@
            if (!res) {
                throw new CoolException("保存工作档失败");
            }
            locNo = dto.getLocNo();
            // 更新源站点信息
            sourceStaNo.setWrkNo(workNo);
            sourceStaNo.setModiTime(now);
@@ -2060,16 +2056,18 @@
        });
//        // 更新入库通知档 ioStatus ===>> Y
//        Wrapper<WaitPakin> wrapper = new EntityWrapper<WaitPakin>()
//                .eq("zpallet", pakin.getZpallet());
//        WaitPakin setParam = new WaitPakin();
//        setParam.setLocNo(dto.getLocNo());
//        setParam.setIoStatus("Y");
//        setParam.setModiTime(now);
//        if (!waitPakinService.update(setParam, wrapper)) {
//            throw new CoolException("更新通知档失败");
//        }
        // 更新入库通知档 ioStatus ===>> Y
        Wrapper<WaitPakin> wrapper = new EntityWrapper<WaitPakin>()
                .eq("zpallet", pakin.getZpallet());
        WaitPakin setParam = new WaitPakin();
        setParam.setLocNo(locNo);
        setParam.setIoStatus("Y");
        setParam.setModiTime(now);
        if (!waitPakinService.update(setParam, wrapper)) {
            throw new CoolException("更新通知档失败");
        }
        return wrkMast;
    }
    /**
src/main/java/com/zy/asrs/task/WorkMastScheduler.java
@@ -1,5 +1,8 @@
package com.zy.asrs.task;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.zy.api.controller.params.WorkTaskParams;
import com.zy.api.service.WcsApiService;
import com.zy.asrs.entity.Task;
import com.zy.asrs.entity.WrkMast;
import com.zy.asrs.service.TaskService;
@@ -12,6 +15,8 @@
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.List;
@@ -28,10 +33,12 @@
    @Autowired
    private WorkMastHandler workMastHandler;
    @Autowired
    private WcsApiService wcsApiService;
    @Autowired
    private TaskService taskService;
    @Scheduled(cron = "0/3 * * * * ? ")
    private void execute(){
    private void execute() {
        List<WrkMast> wrkMasts = wrkMastService.selectToBeCompleteData();
        if (wrkMasts.isEmpty()) {
            return;
@@ -50,7 +57,7 @@
    }
    @Scheduled(cron = "0/3 * * * * ? ")
    private void executeTask(){
    private void executeTask() {
        List<Task> wrkMasts = taskService.selectToBeCompleteData();
        if (wrkMasts.isEmpty()) {
            return;
@@ -68,4 +75,38 @@
        }
    }
    /**
     * 任务自动下发
     *
     * @author Ryan
     * @date 2026/1/10 14:42
     */
    @Scheduled(cron = "0/15 * * * * ? ")
    private void autoPubTasks() {
        List<WrkMast> wrkMasts = wrkMastService.selectList(new EntityWrapper<WrkMast>().in("wrk_sts", Arrays.asList(1L, 11L)));
        if (wrkMasts.isEmpty()) {
            return;
        }
        Collections.shuffle(wrkMasts);
        wrkMasts.forEach(wrkMast -> {
            WorkTaskParams params = new WorkTaskParams();
            if (wrkMast.getIoType().equals(1)) {
                params.setType("in");
                params.setTaskNo(wrkMast.getWrkNo() + "")
                        .setLocNo(wrkMast.getLocNo())
                        .setBarcode(wrkMast.getBarcode())
                        .setTaskPri(wrkMast.getIoPri().intValue());
            } else {
                params.setType("out")
                        .setTaskNo(wrkMast.getWrkNo() + "")
                        .setLocNo(wrkMast.getLocNo())
                        .setStaNo(wrkMast.getStaNo())
                        .setTaskPri(wrkMast.getIoPri().intValue());
                wcsApiService.pubWrkToWcs(params);
            }
        });
    }
}
src/main/java/com/zy/common/constant/MesConstant.java
@@ -8,6 +8,10 @@
    //小系统接口地址
    public static final String URL = "http://webservice.kopen.com.cn:1482/kc-api/api/wms/ ";
    //WCS系统接口地址
    public static final String WCS_URL = "http://192.168.238.244:9090/wcs";
    //上架派工单反馈
    public static final String IN_DISPATCH_RESULT = "getInDispatchResult";
    //备货指示派工单反馈
@@ -16,6 +20,16 @@
    public static final String OUT_DETAILS_RESULT = "getOutDetailsResult";
    /***申请入库任务*/
    public static final String PUB_TASK_IN = "/openapi/createInTask";
    /***申请出库任务*/
    public static final String PUB_TASK_OUT = "/openapi/createOutTask";
    /***同步庫位信息*/
    public static final String SYN_LOCS = "/openapi/getAllLocInformation";
    /**
     * token通过header传递的名称
     */
src/main/java/com/zy/common/service/CommonService.java
@@ -25,6 +25,7 @@
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
@@ -170,292 +171,31 @@
     */
    @Transactional
    public StartupDto getLocNoRun(Integer whsType, Integer staDescId, Integer sourceStaNo, FindLocNoAttributeVo findLocNoAttributeVo, Integer moveCrnNo, LocTypeDto locTypeDto, int times) {
        staDescId = 1;
        // 初始化参数
        int crnNo = 0;      //堆垛机号
        int nearRow = 0;    //最浅库位排
        int curRow = 0;     //最深库位排
        int rowCount = 0;   //轮询轮次
        LocMast locMast = null;     // 目标库位
        StartupDto startupDto = new StartupDto();
        RowLastno rowLastno = rowLastnoService.selectById(whsType);
        if (Cools.isEmpty(rowLastno)) {
            throw new CoolException("数据异常,请联系管理员===>库位规则未知");
        }
        RowLastnoType rowLastnoType = rowLastnoTypeService.selectById(rowLastno.getTypeId());
        if (Cools.isEmpty(rowLastnoType)) {
            throw new CoolException("数据异常,请联系管理员===》库位规则类型未知");
        }
        int sRow = rowLastno.getsRow();
        int eRow = rowLastno.geteRow();
        int crnNumber = rowLastno.getCrnQty();
        // ===============>>>> 开始执行
        curRow = rowLastno.getCurrentRow();
        if (!Cools.isEmpty(moveCrnNo) && moveCrnNo != 0) {
            crnNumber = moveCrnNo;
            if (times == 0) {
                curRow = moveCrnNo * 4 - 1;
            } else {
                curRow = moveCrnNo * 4 - 2;
            }
        }
        //此程序用于优化堆垛机异常时的运行时间
        for (int i = times; i < crnNumber * 2; i++) {
            int[] locNecessaryParameters = Utils.LocNecessaryParameters(rowLastno, curRow, crnNumber);
            curRow = locNecessaryParameters[1];
            crnNo = locNecessaryParameters[2];
            if (basCrnpService.checkSiteError(crnNo, true)) {
                rowCount = locNecessaryParameters[0];
                nearRow = locNecessaryParameters[3];
                List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                        .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                int crnCountO = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).le("io_type", 100));
                if (locMasts.size() - crnCountO <= 2) {
                    log.error(crnNo + "号堆垛机没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
                    nearRow = 0;
                    times++;
                    continue;
                }
                break;
            } else {
                times++;
            }
        }
        if (nearRow == 0) {
            throw new CoolException("无可用堆垛机");
        }
        boolean signRule1 = false;
        boolean signRule2 = false;
        if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
            // 靠近摆放规则 --- 同天同规格物料 //分离版
            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) {
                signRule1 = true;
            }
            // 靠近摆放规则 --- 同天同规格物料 //互通版
            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && staDescId == 1) {
                signRule2 = true;
            }
            if (!Cools.isEmpty(findLocNoAttributeVo.getMatnr()) && (staDescId == 11 || staDescId == 111)) {
                signRule1 = true;
            }
        }
        if (signRule1) {
            if (nearRow != curRow) {
                List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                        .eq("row1", nearRow).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                for (LocMast locMast1 : locMasts) {
                    //获取巷道
//                    List<String> groupOutsideLocCrn = Utils.getGroupOutLocCrn(curRow,nearRow,locMast1.getLocNo(), curRow>nearRow);
//                    LocMast locMastGro = locMastService.selectById(wrkMast.getLocNo());
                    //获取目标库位所在巷道最浅非空库位
                    LocMast locMastF = locMastService.selectLocByLocStsPakInF(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
                    if (!Cools.isEmpty(locMastF) && locMastF.getLocSts().equals("F")) {
                        LocDetl locDetl = locDetlService.selectOne(new EntityWrapper<LocDetl>().eq("loc_no", locMastF.getLocNo()));
                        if (!Cools.isEmpty(locDetl) && findLocNoAttributeVo.beSimilar(locDetl)) {
                            //获取目标库位所在巷道最深空库位
                            locMast = locMastService.selectLocByLocStsPakInO(curRow, nearRow, locMast1, rowLastnoType.getType().longValue());
                            break;
                        }
                    }
                }
            }
        } else if (signRule2) {
            List<String> locNos = locDetlService.getSameDetlToday(findLocNoAttributeVo.getMatnr(), sRow, eRow);
            for (String locNo : locNos) {
                if (Utils.isShallowLoc(slaveProperties, locNo)) {
                    continue;
                }
                String shallowLocNo = Utils.getShallowLoc(slaveProperties, locNo);
                // 检测目标库位是否为空库位
                LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
                    if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
                        if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                            locMast = shallowLoc;
                            crnNo = locMast.getCrnNo();
                            break;
                        }
                    }
                }
            }
        }
//        // 靠近摆放规则 --- 空托  //分离版
//        if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(whsType)) {
//            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>().eq("row1", nearRow).eq("loc_sts", "O"));
//            for (LocMast locMast1:locMasts){
//                if (VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
//                    continue;
//                }
//                String shallowLoc = Utils.getDeepLoc(slaveProperties,locMast1.getLocNo());
//                LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no",shallowLoc));
//                if (!Cools.isEmpty(locMast2) && locMast2.getLocSts().equals("D")){
//                    locMast = locMast1;
//                    break;
//                }
//            }
//        }
        // 靠近摆放规则 --- 空托 //互通版
        if (staDescId == 10 && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("loc_sts", "D").ge("row1", sRow).le("row1", eRow).eq("whs_type", rowLastnoType.getType().longValue()));
            if (!locMasts.isEmpty()) {
                for (LocMast loc : locMasts) {
                    if (Utils.isShallowLoc(slaveProperties, loc.getLocNo())) {
                        continue;
                    }
                    String shallowLocNo = Utils.getShallowLoc(slaveProperties, loc.getLocNo());
                    // 检测目标库位是否为空库位
                    LocMast shallowLoc = locMastService.selectById(shallowLocNo);
                    if (shallowLoc != null && shallowLoc.getLocSts().equals("O")) {
                        if (VersionUtils.locMoveCheckLocTypeComplete(shallowLoc, locTypeDto)) {
                            if (basCrnpService.checkSiteError(shallowLoc.getCrnNo(), true)) {
                                locMast = shallowLoc;
                                crnNo = locMast.getCrnNo();
                                break;
                            }
                        }
                    }
                }
            }
        }
        Wrapper<StaDesc> wrapper = null;
        StaDesc staDesc = null;
        BasDevp staNo = null;
        if (Utils.BooleanWhsTypeSta(rowLastno, staDescId)) {
            // 获取目标站
            wrapper = new EntityWrapper<StaDesc>()
                    .eq("type_no", staDescId)
                    .eq("stn_no", sourceStaNo)
                    .eq("crn_no", crnNo);
            staDesc = staDescService.selectOne(wrapper);
            if (Cools.isEmpty(staDesc)) {
                log.error("type_no={},stn_no={},crn_no={}", staDescId, sourceStaNo, crnNo);
//                throw new CoolException("入库路径不存在");
                crnNo = 0;
            } else {
                staNo = basDevpService.selectById(staDesc.getCrnStn());
                if (!staNo.getAutoing().equals("Y")) {
                    log.error("目标站" + staDesc.getCrnStn() + "不可用");
//                throw new CoolException("目标站"+staDesc.getCrnStn()+"不可用");
                    crnNo = 0;
                }
                startupDto.setStaNo(staNo.getDevNo());
            }
            // 更新库位排号
            if (Cools.isEmpty(locMast)) {
                rowLastno.setCurrentRow(curRow);
                rowLastnoService.updateById(rowLastno);
            }
        }
        // 开始查找库位 ==============================>>
        // 1.按规则查找库位
        if (Cools.isEmpty(locMast) && crnNo != 0) {
            List<LocMast> locMasts = locMastService.selectList(new EntityWrapper<LocMast>()
                    .eq("row1", nearRow)
                    .eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue())
                    .orderBy("lev1", true).orderBy("bay1", true));
            for (LocMast locMast1 : locMasts) {
                if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                    continue;
                }
                if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                    String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                    LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                            .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                    if (!Cools.isEmpty(locMast2)) {
                        locMast = locMast2;
                        break;
                    }
                } else {
                    if (!Cools.isEmpty(locMast1)) {
                        locMast = locMast1;
                        break;
                    }
                }
            }
            if (Cools.isEmpty(locMast) && Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                for (LocMast locMast1 : locMasts) {
                    if (!VersionUtils.locMoveCheckLocTypeComplete(locMast1, locTypeDto)) {
                        continue;
                    }
                    if (Utils.BooleanWhsTypeStaIoType(rowLastno)) {
                        String shallowLoc = Utils.getDeepLoc(slaveProperties, locMast1.getLocNo());
                        LocMast locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                .eq("loc_no", shallowLoc).eq("loc_sts", "O").eq("whs_type", rowLastnoType.getType().longValue()));
                        if (!Cools.isEmpty(locMast2)) {
                            locMast = locMast2;
                            break;
                        } else {
                            locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                    .eq("loc_no", shallowLoc).eq("loc_sts", "F").eq("whs_type", rowLastnoType.getType().longValue()));
                            if (!Cools.isEmpty(locMast2)) {
                                locMast = locMast1;
                                break;
                            } else {
                                locMast2 = locMastService.selectOne(new EntityWrapper<LocMast>()
                                        .eq("loc_no", shallowLoc).eq("loc_sts", "D").eq("whs_type", rowLastnoType.getType().longValue()));
                                if (!Cools.isEmpty(locMast2)) {
                                    locMast = locMast1;
                                    break;
                                }
                            }
                        }
                    } else {
                        if (!Cools.isEmpty(locMast1)) {
                            locMast = locMast1;
                            break;
                        }
                    }
                }
            }
        }
        if (!Cools.isEmpty(locMast) && !basCrnpService.checkSiteError(crnNo, true)) {
            locMast = null;
        }
        // 递归查询
        if (Cools.isEmpty(locMast) || !locMast.getLocSts().equals("O")) {
            // 当前巷道无空库位时,递归调整至下一巷道,检索全部巷道无果后,跳出递归
            if (times < rowCount * 2) {
                times = times + 1;
                return getLocNoRun(whsType, staDescId, sourceStaNo, findLocNoAttributeVo, moveCrnNo, locTypeDto, times);
            }
//            // 2.库位当前所属尺寸无空库位时,调整尺寸参数,向上兼容检索库位
//            if (locTypeDto.getLocType1() < 2) {
//                int i = locTypeDto.getLocType1() + 1;
//                locTypeDto.setLocType1((short)i);
//                return getLocNo(1, staDescId, sourceStaNo, matnr,batch,grade, locTypeDto, 0);
//            }
            log.error("系统没有空库位!!! 尺寸规格: {}, 轮询次数:{}", JSON.toJSONString(locTypeDto), times);
            throw new CoolException("没有空库位");
        }
        String locNo = locMast.getLocNo();
        StartupDto startupDto = new StartupDto();
         locMast = locMastService.selectOne(new EntityWrapper<LocMast>()
                .ne("row1", rowLastno.getsRow())
                .le("row1", rowLastno.geteRow())
                .eq("loc_sts", "O")
                .orderAsc(Arrays.asList("row1", "bay1", "lev1")));
//        int crnCountO = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("crn_no", crnNo).le("io_type", 100));
        // 生成工作号
        int workNo = getWorkNo(0);
        // 返回dto
        startupDto.setWorkNo(workNo);
        startupDto.setCrnNo(crnNo);
        startupDto.setCrnNo(locMast.getCrnNo());
        startupDto.setSourceStaNo(sourceStaNo);
        startupDto.setLocNo(locNo);
        startupDto.setLocNo(locMast.getLocNo());
        return startupDto;
    }
@@ -846,7 +586,6 @@
                        locMast = locMast2;
                        break;
                    }
                }
            }