自动化立体仓库 - WMS系统
chen.llin
23 小时以前 6923315545b3f97c86719148f85dac1220a14a63
agv空托入库接口以及机器人组站点配置
1个文件已添加
8个文件已修改
315 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/AppVersionController.java 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java 62 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/task/handler/AgvHandler.java 61 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/constant/ApiInterfaceConstant.java 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/properties/AgvProperties.java 102 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/common/web/RouterController.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-dev.yml 22 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application-prod.yml 26 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/AppVersionController.java
@@ -12,6 +12,10 @@
import com.zy.asrs.entity.AppVersion;
import com.zy.asrs.service.AppVersionService;
import com.zy.common.web.BaseController;
import com.zy.system.entity.Permission;
import com.zy.system.entity.RolePermission;
import com.zy.system.service.PermissionService;
import com.zy.system.service.RolePermissionService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.util.ClassUtils;
@@ -22,10 +26,15 @@
import java.io.*;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
@RestController
public class AppVersionController extends BaseController {
    @Autowired
    private PermissionService permissionService;
    @Autowired
    private RolePermissionService rolePermissionService;
    @Autowired
    private AppVersionService appVersionService;
@@ -57,6 +66,7 @@
    public R checkUpdate(@PathVariable("version") String version,
                         @PathVariable("type") Integer type) {
        EntityWrapper<AppVersion> wrapper = new EntityWrapper<>();
        wrapper.eq("type", type);
        AppVersion appVersion = appVersionService.selectOne(wrapper);
        if (Cools.isEmpty(appVersion)) {
            return R.ok("已是最新版本");
@@ -220,4 +230,23 @@
            response.setStatus(404);
        }
    }
    @RequestMapping("/menu/pda/auth")
    @ManagerAuth
    public R menuPda(){
        Long userId = getUserId();
        List<RolePermission> rolePermissions;
        if (userId == 9527L) {
            rolePermissions = rolePermissionService.selectList(new EntityWrapper<>());
        } else {
            Long roleId = getUser().getRoleId();
            rolePermissions = rolePermissionService.selectList(new EntityWrapper<RolePermission>().eq("role_id", roleId));
        }
        if (Cools.isEmpty(rolePermissions)) {
            return R.ok();
        }
        List<Long> collect = rolePermissions.stream().map(RolePermission::getPermissionId).distinct().collect(Collectors.toList());
        List<Permission> permissions = permissionService.selectBatchIds(collect);
        return R.ok().add(permissions);
    }
}
src/main/java/com/zy/asrs/service/impl/MobileServiceImpl.java
@@ -23,6 +23,7 @@
import com.zy.common.model.DetlDto;
import com.zy.common.model.MesCombParam;
import com.zy.common.model.enums.WorkNoType;
import com.zy.common.properties.AgvProperties;
import com.zy.common.service.CommonService;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
@@ -122,6 +123,9 @@
    @Resource
    private BasDevpMapper basDevpMapper;
    @Resource
    private AgvProperties agvProperties;
    @Override
    public R inLocCallAgv(CallAgvParam param,Long userId) {
        int type = param.getType();
@@ -159,23 +163,33 @@
                locCacheService.updateById(locCache);
                break;
            case 3:
                // 判断条码在wms不存在,是空托盘
                // 已组托
                // 判断是否为空托入库:检查条码在wms中不存在,确认为空托盘
                log.info("开始判断是否为空托入库,条码:{}", barcode);
                // 检查是否已组托
                int waitPakInCount = waitPakinService.selectCount(new EntityWrapper<WaitPakin>().eq("zpallet", barcode));
                if (waitPakInCount != 0) {
                    log.warn("条码组托档已存在,不是空托盘:{}", barcode);
                    throw new CoolException("条码组托档已存在:" + barcode);
                }
                // 有任务
                // 检查是否有任务
                int wrkMastCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", barcode));
                if (wrkMastCount != 0) {
                    log.warn("条码任务档已存在,不是空托盘:{}", barcode);
                    throw new CoolException("条码任务档已存在:" + barcode);
                }
                // 有库存
                // 检查是否有库存
                int locDetlCount = locDetlService.selectCount(new EntityWrapper<LocDetl>().eq("zpallet", barcode));
                if (locDetlCount != 0) {
                    log.warn("条码库存已存在,不是空托盘:{}", barcode);
                    throw new CoolException("条码库存已存在:" + barcode);
                }
                // 通过所有检查,确认为空托盘,设置为空托入库
                ioType = 10;
                log.info("确认为空托盘,设置为空托入库,条码:{},ioType:{}", barcode, ioType);
                break;
            default:
                throw new CoolException("入库类型错误,type:" + type);
@@ -186,15 +200,47 @@
            throw new CoolException(barcode+ ":条码存在agv搬运任务!");
        }
        // 根据whs_type选择站点和机器人组
        Long whsType = locCache.getWhsType();
        List<String> targetStations;
        String robotGroup;
        if (whsType != null && whsType.equals(agvProperties.getWhsTypeMapping().getInboundArea())) {
            // whs_type = 1: 入库区,使用东侧站点和Group-001
            targetStations = agvProperties.getEastStations();
            robotGroup = agvProperties.getRobotGroupEast();
            log.info("库位whs_type={},使用入库区配置(东侧站点和Group-001)", whsType);
        } else if (whsType != null && whsType.equals(agvProperties.getWhsTypeMapping().getCacheArea())) {
            // whs_type = 2: 缓存区,使用西侧站点和Group-002
            targetStations = agvProperties.getWestStations();
            robotGroup = agvProperties.getRobotGroupWest();
            log.info("库位whs_type={},使用缓存区配置(西侧站点和Group-002)", whsType);
        } else {
            // whs_type为空或其他值,根据type判断(兼容旧逻辑)
            if (type == 1) {
                targetStations = agvProperties.getEastStations();
                robotGroup = agvProperties.getRobotGroupEast();
            } else {
                targetStations = agvProperties.getWestStations();
                robotGroup = agvProperties.getRobotGroupWest();
            }
            log.warn("库位whs_type={}未配置或不在映射范围内,使用type={}的默认逻辑", whsType, type);
        }
        // 将站点字符串列表转换为整数列表
        List<Integer> siteIntList = targetStations.stream()
                .map(Integer::parseInt)
                .collect(Collectors.toList());
        // 判断能入站点
        List<Integer> sites = basDevpMapper.selectList(
                new EntityWrapper<BasDevp>()
                        .eq("canining", "Y")
                        .in("dev_no", type == 1 ? Arrays.asList(1003, 1005, 1007) : Arrays.asList(1044, 1046, 1048))
                        .in("dev_no", siteIntList)
        ).stream().map(BasDevp::getDevNo).collect(Collectors.toList());
        if (sites.isEmpty()) {
            throw new CoolException("没有能入站点,type:" + type);
            throw new CoolException("没有能入站点,whs_type:" + whsType + ",type:" + type);
        }
        // 获取没有出库任务的站点
@@ -228,10 +274,12 @@
                .setTaskType("agv")
                .setIoPri(10D)
                .setStaNo(String.valueOf(endSite))
                .setSourceStaNo(sourceSite) // 设置源站点
                .setInvWh(robotGroup) // 根据whs_type设置机器人组
                .setFullPlt(ioType != 10 ? "N" : "Y")// 满板:Y
                .setPicking("N") // 拣料
                .setExitMk("N")// 退出
                .setSourceLocNo(sourceSite)
                .setSourceLocNo(locCache.getLocNo()) // 设置源库位编号,用于AGV fromBin
                .setEmptyMk(ioType == 10 ? "Y" : "N")// 空板
                .setBarcode(barcode)// 托盘码
                .setLinkMis("N")
src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -61,7 +61,7 @@
    @Override
    @Transactional(rollbackFor = Exception.class)
    public R agvCallback(AgvCallbackDto param) {
        log.debug("agvCallback param:{}", param);
        log.debug("agv回调 param:{}", param);
        // 优先使用taskId,如果没有则使用id(向后兼容)
        String taskId = Cools.isEmpty(param.getTaskId()) ? param.getId() : param.getTaskId();
        if (Cools.isEmpty(taskId)) {
src/main/java/com/zy/asrs/task/handler/AgvHandler.java
@@ -12,17 +12,19 @@
import com.zy.asrs.service.TaskLogService;
import com.zy.asrs.service.TaskService;
import com.zy.common.constant.ApiInterfaceConstant;
import com.zy.common.properties.AgvProperties;
import com.zy.common.utils.HttpHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
@@ -49,15 +51,15 @@
    @Resource
    private BasStationMapper basStationMapper;
    @Value("${Agv.sendTask}")
    private boolean agvSendTask;
    @Resource
    private AgvProperties agvProperties;
    /**
     * 呼叫agv搬运
     */
    public void callAgv(List<Task> taskList) {
        if (!agvSendTask) {
        if (!agvProperties.isSendTask()) {
            return;
        }
@@ -99,6 +101,7 @@
                    success = true;
                    task.setWrkSts(8L);
                    taskService.updateById(task);
                    log.info(namespace + "呼叫agv搬运请求参数:{}", body);
                    log.info(namespace + "呼叫agv搬运成功:{}", task.getId());
                } else {
                    log.error(namespace + "呼叫agv搬运失败!!!url:{};request:{};response:{}", url, body, response);
@@ -131,19 +134,34 @@
        JSONObject object = new JSONObject();
        // taskId使用任务ID,格式:T + 任务ID
        object.put("taskId", "T" + task.getId());
        object.put("fromBin", task.getSourceStaNo());
        // fromBin使用源库位编号(sourceLocNo),如果为空则使用源站点编号(sourceStaNo)作为备选
        String fromBin = task.getSourceLocNo();
        if (fromBin == null || fromBin.isEmpty()) {
            fromBin = task.getSourceStaNo();
        }
        if (fromBin == null || fromBin.isEmpty() || "0".equals(fromBin)) {
            log.warn("任务{}的源库位和源站点都为空,使用默认值", task.getId());
            fromBin = "0";
        }
        object.put("fromBin", fromBin);
        // toBin使用目标站点编号
        object.put("toBin", task.getStaNo());
        // robotGroup从invWh字段获取,如果没有则使用默认值
        // robotGroup从invWh字段获取,如果没有则根据站点编号判断
        String robotGroup = task.getInvWh();
        if (robotGroup == null || robotGroup.isEmpty()) {
            robotGroup = "Group-001"; // 默认机器人组
            robotGroup = determineRobotGroupByStation(task.getStaNo());
        }
        object.put("robotGroup", robotGroup);
        // kind根据任务类型映射
        String kind = "";
        switch (nameSpace) {
            case "入库":
                kind = "实托入库";
                // 判断是否为空托入库:ioType=10 或 emptyMk="Y"
                if (task.getIoType() == 10 || "Y".equals(task.getEmptyMk())) {
                    kind = "空托入库";
                } else {
                    kind = "实托入库";
                }
                break;
            case "出库":
                kind = "实托出库";
@@ -156,6 +174,31 @@
        }
        object.put("kind", kind);
        return object.toJSONString();
    }
    /**
     * 根据站点编号判断机器人组
     * @param staNo 站点编号
     * @return 机器人组名称
     */
    private String determineRobotGroupByStation(String staNo) {
        if (staNo == null || staNo.isEmpty()) {
            return agvProperties.getRobotGroupEast(); // 默认使用东侧机器人组
        }
        // 从配置中获取站点列表
        Set<String> eastStations = new HashSet<>(agvProperties.getEastStations());
        Set<String> westStations = new HashSet<>(agvProperties.getWestStations());
        // 判断站点属于哪一侧
        if (eastStations.contains(staNo)) {
            return agvProperties.getRobotGroupEast(); // 东侧机器人
        } else if (westStations.contains(staNo)) {
            return agvProperties.getRobotGroupWest(); // 西侧机器人
        } else {
            log.warn("站点编号不在配置列表中,使用默认机器人组:{}", staNo);
            return agvProperties.getRobotGroupEast(); // 默认使用东侧机器人组
        }
    }
    /**
@@ -231,7 +274,7 @@
     * @return 是否成功
     */
    public boolean cancelAgvTask(Task task) {
        if (!agvSendTask) {
        if (!agvProperties.isSendTask()) {
            return false;
        }
src/main/java/com/zy/common/constant/ApiInterfaceConstant.java
@@ -33,7 +33,7 @@
     */
//    public static final String AGV_IP = "http://192.168.99.130:80";
    // 测试地址
    public static final String AGV_IP = "http://127.0.0.1:8080/yhfzwms/open/asrs";
    public static final String AGV_IP = "http://10.10.10.200:8080/agv";
    /**
     * 仙工M4 - 创建任务(货物转运、实托入库,实托出库)
src/main/java/com/zy/common/properties/AgvProperties.java
New file
@@ -0,0 +1,102 @@
package com.zy.common.properties;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import java.util.ArrayList;
import java.util.List;
/**
 * AGV配置属性
 *
 * @author system
 */
@Data
@Configuration
@ConfigurationProperties(prefix = "agv")
public class AgvProperties {
    /**
     * 是否发送任务
     */
    private boolean sendTask = false;
    /**
     * 东侧配置
     */
    private RobotGroupConfig east = new RobotGroupConfig();
    /**
     * 西侧配置
     */
    private RobotGroupConfig west = new RobotGroupConfig();
    /**
     * whs_type映射配置
     * 1: 入库区(东侧),2: 缓存区(西侧)
     */
    private WhsTypeMapping whsTypeMapping = new WhsTypeMapping();
    /**
     * whs_type映射配置内部类
     */
    @Data
    public static class WhsTypeMapping {
        /**
         * 入库区对应的whs_type值(默认1)
         */
        private Long inboundArea = 1L;
        /**
         * 缓存区对应的whs_type值(默认2)
         */
        private Long cacheArea = 2L;
    }
    /**
     * 机器人组配置内部类
     */
    @Data
    public static class RobotGroupConfig {
        /**
         * 机器人组编号
         */
        private String robotGroup = "";
        /**
         * 站点列表
         */
        private List<String> stations = new ArrayList<>();
    }
    /**
     * 获取东侧站点列表(兼容旧代码)
     */
    public List<String> getEastStations() {
        return east != null ? east.getStations() : new ArrayList<>();
    }
    /**
     * 获取西侧站点列表(兼容旧代码)
     */
    public List<String> getWestStations() {
        return west != null ? west.getStations() : new ArrayList<>();
    }
    /**
     * 获取东侧机器人组编号(兼容旧代码)
     */
    public String getRobotGroupEast() {
        return east != null && east.getRobotGroup() != null && !east.getRobotGroup().isEmpty()
            ? east.getRobotGroup() : "Group-001";
    }
    /**
     * 获取西侧机器人组编号(兼容旧代码)
     */
    public String getRobotGroupWest() {
        return west != null && west.getRobotGroup() != null && !west.getRobotGroup().isEmpty()
            ? west.getRobotGroup() : "Group-002";
    }
}
src/main/java/com/zy/common/web/RouterController.java
@@ -51,4 +51,13 @@
        }
    }
    @RequestMapping("/rfid")
    public void rfid(HttpServletResponse response) {
        try {
            response.sendRedirect(contextPath + "/views/rfid.html");
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
src/main/resources/application-dev.yml
@@ -68,6 +68,28 @@
Agv:
  sendTask: false
  # 东侧配置
  east:
    robotGroup: "Group-001"
    stations:
      - "1001"
      - "1003"
      - "1005"
      - "1007"
  # 西侧配置
  west:
    robotGroup: "Group-002"
    stations:
      - "1042"
      - "1044"
      - "1046"
      - "1048"
  # whs_type映射配置
  whsTypeMapping:
    # 入库区whs_type值(对应东侧)
    inboundArea: 1
    # 缓存区whs_type值(对应西侧)
    cacheArea: 2
# 越库配置
cross-dock:
src/main/resources/application-prod.yml
@@ -66,6 +66,31 @@
  # 右深库位排号
  doubleLocsRight: 4,8,12,16,20,24,28,32
Agv:
  sendTask: false
  # 东侧配置
  east:
    robotGroup: "Group-001"
    stations:
      - "1001"
      - "1003"
      - "1005"
      - "1007"
  # 西侧配置
  west:
    robotGroup: "Group-002"
    stations:
      - "1042"
      - "1044"
      - "1046"
      - "1048"
  # whs_type映射配置
  whsTypeMapping:
    # 入库区whs_type值(对应东侧)
    inboundArea: 1
    # 缓存区whs_type值(对应西侧)
    cacheArea: 2
# 越库配置
cross-dock:
  # 越库入库单类型ID
@@ -74,4 +99,3 @@
  outbound-doc-type-id: 36
  # 虚拟库位编号
  virtual-location-no: VIRTUAL