Compare commits

...

5 Commits

Author SHA1 Message Date
aikai
0adb314b20 Merge branch 'dev' of http://git.znkjfw.com/ak/zn-cloud-wcs into aikai 2025-02-05 10:24:13 +08:00
aikai
4d49a7b7e0 feat(system): 新增设备信息管理功能
- 添加设备信息相关实体类、控制器、服务类和Mapper
- 实现设备信息的批量保存、编辑和删除功能
- 添加通过地图ID获取设备列表的接口
- 优化停车点相关代码,统一使用positionMapId和positionMapItemId字段
- 新增设备点位数据处理策略
2025-02-05 10:24:05 +08:00
cbs
7ed63a7388 开发移库任务 2025-01-23 11:55:40 +08:00
cbs
e2f46b2978 优化任务下发的更新顺序 2025-01-20 19:07:03 +08:00
cbs
39b34faa75 更新机器人任务 2025-01-20 15:13:49 +08:00
63 changed files with 1752 additions and 178 deletions

View File

@ -13,7 +13,7 @@ import lombok.Getter;
public enum NodeTypeEnum {
ROUTE(1, "路径点位"),
WARE(2, "库位点"),
EQUIPMENT(3, "设备点"),
DEVICE(3, "设备点"),
PARKING(4, "停车点"),
CHANGE(5, "区域变更点"),
WAIT(6, "等待点");

View File

@ -195,6 +195,7 @@ public interface ErrorCodeConstants {
ErrorCode TASK_CHECK_TASK_PRIORITY = new ErrorCode(1-002-035-007, "非新单据不能修改优先级");
ErrorCode TASK_CHECK_TASK_STATUS = new ErrorCode(1-002-035-100, "订单已完成");
ErrorCode TASK_CHECK_UPDATE_STATUS = new ErrorCode(1-002-035-101, "订单更新失败");
ErrorCode TASK_CHECK_EXIST_NO = new ErrorCode(1-002-035-102, "订单号已存在");
// ========== 机器人任务明细 1-002-036-000 ==========
ErrorCode TASK_DETAIL_NOT_EXISTS = new ErrorCode(1-002-036-001, "机器人任务明细不存在");
@ -213,4 +214,7 @@ public interface ErrorCodeConstants {
ErrorCode THERE_ARE_ALREADY_STORAGE_LOCATIONS_IN_OTHER_LINE_WAREHOUSES = new ErrorCode(1_002_038_007, "已有库位在其他线库内");
ErrorCode THERE_ARE_ALREADY_STORAGE_LOCATIONS_IN_OTHER_STORAGE_AREAS = new ErrorCode(1_002_038_008, "已有库位在其他库区内");
// ========== 机器人自动移库 1-002-039-000 ==========
ErrorCode TASK_AUTO_MOVE_NOT_EXISTS = new ErrorCode(1_002_039_001, "机器人自动移库不存在");
}

View File

@ -72,6 +72,13 @@ public class DeviceInformationController {
return success(BeanUtils.toBean(information, DeviceInformationRespVO.class));
}
@GetMapping("/list")
@Operation(summary = "获得设备信息列表")
public CommonResult<List<DeviceInformationRespVO>> getList(@Valid DeviceInformationPageReqVO pageReqVO) {
List<DeviceInformationDO> list = informationService.getList(pageReqVO);
return success(BeanUtils.toBean(list, DeviceInformationRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得设备信息分页")
@PreAuthorize("@ss.hasPermission('device:information:query')")

View File

@ -1,6 +1,9 @@
package cn.iocoder.yudao.module.system.controller.admin.information.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
@ -14,6 +17,23 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class DeviceInformationPageReqVO extends PageParam {
@Schema(description = "地图id", example = "6609")
private Long positionMapId;
@Schema(description = "地图子表节点id", example = "23591")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
private String locationX;
@Schema(description = "库位坐标y轴")
private String locationY;
@Schema(description = "宽度")
private BigDecimal locationWide;
@Schema(description = "深度")
private BigDecimal locationDeep;
@Schema(description = "设备类型1充电桩、2输送线、 3码垛机、4拆垛机、5自动门、6提升机、7信号灯、8按钮盒", example = "2")
private Integer deviceType;
@ -24,6 +44,9 @@ public class DeviceInformationPageReqVO extends PageParam {
@Schema(description = "mac地址")
private String macAddress;
@Schema(description = "设备在地图上图标")
private String mapImageUrl;
@Schema(description = "上传图片附件", example = "https://www.iocoder.cn")
private String url;
@ -47,4 +70,4 @@ public class DeviceInformationPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
}

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.information.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@ -16,6 +18,30 @@ public class DeviceInformationRespVO {
@ExcelProperty("主键ID")
private Long id;
@Schema(description = "地图id", example = "6609")
@ExcelProperty("地图id")
private Long positionMapId;
@Schema(description = "地图子表节点id", example = "23591")
@ExcelProperty("地图子表节点id")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
@ExcelProperty("库位坐标x轴")
private String locationX;
@Schema(description = "库位坐标y轴")
@ExcelProperty("库位坐标y轴")
private String locationY;
@Schema(description = "宽度")
@ExcelProperty("宽度")
private BigDecimal locationWide;
@Schema(description = "深度")
@ExcelProperty("深度")
private BigDecimal locationDeep;
@Schema(description = "设备类型1充电桩、2输送线、 3码垛机、4拆垛机、5自动门、6提升机、7信号灯、8按钮盒", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("设备类型1充电桩、2输送线、 3码垛机、4拆垛机、5自动门、6提升机、7信号灯、8按钮盒")
private Integer deviceType;
@ -28,6 +54,10 @@ public class DeviceInformationRespVO {
@ExcelProperty("mac地址")
private String macAddress;
@Schema(description = "设备在地图上图标")
@ExcelProperty("设备在地图上图标")
private String mapImageUrl;
@Schema(description = "上传图片附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
@ExcelProperty("上传图片附件")
private String url;
@ -56,4 +86,4 @@ public class DeviceInformationRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
}

View File

@ -2,6 +2,8 @@ package cn.iocoder.yudao.module.system.controller.admin.information.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.math.BigDecimal;
import java.util.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
@ -14,6 +16,24 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "14335")
private Long id;
@Schema(description = "地图id", example = "6609")
private Long positionMapId;
@Schema(description = "地图子表节点id", example = "23591")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
private String locationX;
@Schema(description = "库位坐标y轴")
private String locationY;
@Schema(description = "宽度")
private BigDecimal locationWide;
@Schema(description = "深度")
private BigDecimal locationDeep;
@Schema(description = "设备类型1充电桩、2输送线、 3码垛机、4拆垛机、5自动门、6提升机、7信号灯、8按钮盒", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "设备类型不能为空")
private Integer deviceType;
@ -24,6 +44,9 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "mac地址")
private String macAddress;
@Schema(description = "设备在地图上图标")
private String mapImageUrl;
@Schema(description = "上传图片附件", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")
private String url;
@ -42,4 +65,4 @@ public class DeviceInformationSaveReqVO {
@Schema(description = "设备最后通讯时间")
private LocalDateTime deviceLastTime;
}
}

View File

@ -17,10 +17,10 @@ import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_
public class ParkingSpotPageReqVO extends PageParam {
@Schema(description = "地图id", example = "6609")
private Long mapId;
private Long positionMapId;
@Schema(description = "地图表节点id", example = "23591")
private Long mapItemId;
@Schema(description = "地图表节点id", example = "23591")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
private String locationX;
@ -47,4 +47,4 @@ public class ParkingSpotPageReqVO extends PageParam {
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}
}

View File

@ -19,11 +19,11 @@ public class ParkingSpotRespVO {
@Schema(description = "地图id", example = "6609")
@ExcelProperty("地图id")
private Long mapId;
private Long positionMapId;
@Schema(description = "地图表节点id", example = "23591")
@ExcelProperty("地图表节点id")
private Long mapItemId;
@Schema(description = "地图表节点id", example = "23591")
@ExcelProperty("地图表节点id")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
@ExcelProperty("库位坐标x轴")
@ -57,4 +57,4 @@ public class ParkingSpotRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}
}

View File

@ -14,10 +14,10 @@ public class ParkingSpotSaveReqVO {
private Long id;
@Schema(description = "地图id", example = "6609")
private Long mapId;
private Long positionMapId;
@Schema(description = "地图表节点id", example = "23591")
private Long mapItemId;
@Schema(description = "地图表节点id", example = "23591")
private Long positionMapItemId;
@Schema(description = "库位坐标x轴")
private String locationX;

View File

@ -109,4 +109,12 @@ public class RobotInformationController {
return success(BeanUtils.toBean(result, RobotInformationRespVO.class));
}
@PostMapping("/getAllRobot")
@Operation(summary = "查询所有车辆")
@PreAuthorize("@ss.hasPermission('robot:information:getAllRobot')")
public CommonResult<List<RobotInformationRespVO>> getAllRobot() {
List<RobotInformationDO> result = informationService.getAllRobot();
return success(BeanUtils.toBean(result, RobotInformationRespVO.class));
}
}

View File

@ -0,0 +1,97 @@
package cn.iocoder.yudao.module.system.controller.admin.robot;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMovePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMoveRespVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMoveSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskAutoMoveDO;
import cn.iocoder.yudao.module.system.service.robot.job.RobotTaskAutoMoveService;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.security.access.prepost.PreAuthorize;
import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.Operation;
import javax.validation.constraints.*;
import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
import cn.iocoder.yudao.framework.excel.core.util.ExcelUtils;
import cn.iocoder.yudao.framework.apilog.core.annotation.ApiAccessLog;
import static cn.iocoder.yudao.framework.apilog.core.enums.OperateTypeEnum.*;
@Tag(name = "管理后台 - 机器人自动移库")
@RestController
@RequestMapping("/robot/task-auto-move")
@Validated
public class RobotTaskAutoMoveController {
@Resource
private RobotTaskAutoMoveService taskAutoMoveService;
@PostMapping("/create")
@Operation(summary = "创建机器人自动移库")
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:create')")
public CommonResult<Long> createTaskAutoMove(@Valid @RequestBody RobotTaskAutoMoveSaveReqVO createReqVO) {
return success(taskAutoMoveService.createTaskAutoMove(createReqVO));
}
@PutMapping("/update")
@Operation(summary = "更新机器人自动移库")
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:update')")
public CommonResult<Boolean> updateTaskAutoMove(@Valid @RequestBody RobotTaskAutoMoveSaveReqVO updateReqVO) {
taskAutoMoveService.updateTaskAutoMove(updateReqVO);
return success(true);
}
@DeleteMapping("/delete")
@Operation(summary = "删除机器人自动移库")
@Parameter(name = "id", description = "编号", required = true)
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:delete')")
public CommonResult<Boolean> deleteTaskAutoMove(@RequestParam("id") Long id) {
taskAutoMoveService.deleteTaskAutoMove(id);
return success(true);
}
@GetMapping("/get")
@Operation(summary = "获得机器人自动移库")
@Parameter(name = "id", description = "编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:query')")
public CommonResult<RobotTaskAutoMoveRespVO> getTaskAutoMove(@RequestParam("id") Long id) {
RobotTaskAutoMoveDO taskAutoMove = taskAutoMoveService.getTaskAutoMove(id);
return success(BeanUtils.toBean(taskAutoMove, RobotTaskAutoMoveRespVO.class));
}
@GetMapping("/page")
@Operation(summary = "获得机器人自动移库分页")
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:query')")
public CommonResult<PageResult<RobotTaskAutoMoveRespVO>> getTaskAutoMovePage(@Valid RobotTaskAutoMovePageReqVO pageReqVO) {
PageResult<RobotTaskAutoMoveDO> pageResult = taskAutoMoveService.getTaskAutoMovePage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RobotTaskAutoMoveRespVO.class));
}
@GetMapping("/export-excel")
@Operation(summary = "导出机器人自动移库 Excel")
@PreAuthorize("@ss.hasPermission('robot:task-auto-move:export')")
@ApiAccessLog(operateType = EXPORT)
public void exportTaskAutoMoveExcel(@Valid RobotTaskAutoMovePageReqVO pageReqVO,
HttpServletResponse response) throws IOException {
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
List<RobotTaskAutoMoveDO> list = taskAutoMoveService.getTaskAutoMovePage(pageReqVO).getList();
// 导出 Excel
ExcelUtils.write(response, "机器人自动移库.xls", "数据", RobotTaskAutoMoveRespVO.class,
BeanUtils.toBean(list, RobotTaskAutoMoveRespVO.class));
}
}

View File

@ -87,7 +87,7 @@ public class RobotTaskController {
@PreAuthorize("@ss.hasPermission('robot:task:query')")
public CommonResult<PageResult<RobotTaskRespVO>> getTaskPage(@Valid @RequestBody RobotTaskPageReqVO pageReqVO) {
PageResult<RobotTaskRespVO> pageResult = taskService.getTaskPage(pageReqVO);
return success(BeanUtils.toBean(pageResult, RobotTaskRespVO.class));
return success(pageResult);
}
@GetMapping("/export-excel")

View File

@ -0,0 +1,72 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import lombok.*;
import java.util.*;
import io.swagger.v3.oas.annotations.media.Schema;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
@Schema(description = "管理后台 - 机器人自动移库分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class RobotTaskAutoMovePageReqVO extends PageParam {
@Schema(description = "机器人任务主表id", example = "24553")
private Long robotTaskId;
@Schema(description = "机器人任务明细表id", example = "11392")
private Long robotTaskDetailId;
@Schema(description = "原库位编号")
private String fromLocationNo;
@Schema(description = "原库位id", example = "8838")
private Long fromLocationId;
@Schema(description = "搬去的目标库位编号")
private String toLocationNo;
@Schema(description = "搬去的目标库位id/停车点/充电点/移动终点", example = "19168")
private Long toLocationId;
@Schema(description = "任务状态(0:未开始、1执行中、2已完成、3已取消、4异常)", example = "1")
private Integer taskStatus;
@Schema(description = "取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id(目前设计不会用到此字段)")
private Long toLaneId;
@Schema(description = "优先级")
private Long priority;
@Schema(description = "AGV编号")
private String robotNo;
@Schema(description = "任务类型1自动移库、 ", example = "2")
private Integer taskType;
@Schema(description = "移动类型1去、 2", example = "2")
private Integer moveType;
@Schema(description = "开始时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] startTime;
@Schema(description = "结束时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] endTime;
@Schema(description = "robot_task_auto_move表id来回搬运需要记录上一次搬运的源库位", example = "32231")
private Long taskAutoMoveId;
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;
}

View File

@ -0,0 +1,87 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
import com.alibaba.excel.annotation.*;
@Schema(description = "管理后台 - 机器人自动移库 Response VO")
@Data
@ExcelIgnoreUnannotated
public class RobotTaskAutoMoveRespVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30110")
@ExcelProperty("主键ID")
private Long id;
@Schema(description = "机器人任务主表id", example = "24553")
@ExcelProperty("机器人任务主表id")
private Long robotTaskId;
@Schema(description = "机器人任务明细表id", example = "11392")
@ExcelProperty("机器人任务明细表id")
private Long robotTaskDetailId;
@Schema(description = "原库位编号")
@ExcelProperty("原库位编号")
private String fromLocationNo;
@Schema(description = "原库位id", example = "8838")
@ExcelProperty("原库位id")
private Long fromLocationId;
@Schema(description = "搬去的目标库位编号")
@ExcelProperty("搬去的目标库位编号")
private String toLocationNo;
@Schema(description = "搬去的目标库位id/停车点/充电点/移动终点", example = "19168")
@ExcelProperty("搬去的目标库位id/停车点/充电点/移动终点")
private Long toLocationId;
@Schema(description = "取货线库id")
@ExcelProperty("取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id(目前设计不会用到此字段)")
@ExcelProperty("放货线库id(目前设计不会用到此字段)")
private Long toLaneId;
@Schema(description = "任务状态(0:未开始、1执行中、2已完成、3已取消、4异常)", example = "1")
@ExcelProperty("任务状态(0:未开始、1执行中、2已完成、3已取消、4异常)")
private Integer taskStatus;
@Schema(description = "优先级")
@ExcelProperty("优先级")
private Long priority;
@Schema(description = "AGV编号")
@ExcelProperty("AGV编号")
private String robotNo;
@Schema(description = "任务类型1自动移库、 ", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("任务类型1自动移库、 ")
private Integer taskType;
@Schema(description = "移动类型1去、 2", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@ExcelProperty("移动类型1去、 2")
private Integer moveType;
@Schema(description = "开始时间")
@ExcelProperty("开始时间")
private LocalDateTime startTime;
@Schema(description = "结束时间")
@ExcelProperty("结束时间")
private LocalDateTime endTime;
@Schema(description = "robot_task_auto_move表id来回搬运需要记录上一次搬运的源库位", example = "32231")
@ExcelProperty("robot_task_auto_move表id来回搬运需要记录上一次搬运的源库位")
private Long taskAutoMoveId;
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
@ExcelProperty("创建时间")
private LocalDateTime createTime;
}

View File

@ -0,0 +1,68 @@
package cn.iocoder.yudao.module.system.controller.admin.robot.vo;
import com.alibaba.excel.annotation.ExcelProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import javax.validation.constraints.*;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDateTime;
@Schema(description = "管理后台 - 机器人自动移库新增/修改 Request VO")
@Data
public class RobotTaskAutoMoveSaveReqVO {
@Schema(description = "主键ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "30110")
private Long id;
@Schema(description = "机器人任务主表id", example = "24553")
private Long robotTaskId;
@Schema(description = "机器人任务明细表id", example = "11392")
private Long robotTaskDetailId;
@Schema(description = "原库位编号")
private String fromLocationNo;
@Schema(description = "原库位id", example = "8838")
private Long fromLocationId;
@Schema(description = "搬去的目标库位编号")
private String toLocationNo;
@Schema(description = "取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id(目前设计不会用到此字段)")
private Long toLaneId;
@Schema(description = "搬去的目标库位id/停车点/充电点/移动终点", example = "19168")
private Long toLocationId;
@Schema(description = "任务状态(0:未开始、1执行中、2已完成、3已取消、4异常)", example = "1")
private Integer taskStatus;
@Schema(description = "优先级")
private Long priority;
@Schema(description = "AGV编号")
private String robotNo;
@Schema(description = "任务类型1自动移库、 ", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "任务类型1自动移库、 )不能为空")
private Integer taskType;
@Schema(description = "移动类型1去、 2", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "移动类型1去、 2不能为空")
private Integer moveType;
@Schema(description = "开始时间")
private LocalDateTime startTime;
@Schema(description = "结束时间")
private LocalDateTime endTime;
@Schema(description = "robot_task_auto_move表id来回搬运需要记录上一次搬运的源库位", example = "32231")
private Long taskAutoMoveId;
}

View File

@ -37,6 +37,15 @@ public class RobotTaskDetailAddVO {
@Schema(description = "所选车辆电量(充电模式)")
private Integer electricity;
@Schema(description = "取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id")
private Long toLaneId;
@Schema(description = "取货库位的排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "计算后的来源库位编号(前端不用传此字段)")
private String fromLocationNo;
@Schema(description = "计算后的来源库位id(前端不用传此字段)")

View File

@ -46,6 +46,14 @@ public class RobotTaskDetailPageReqVO extends PageParam {
@Schema(description = "AGV动作")
private String robotAction;
@Schema(description = "取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id")
private Long toLaneId;
@Schema(description = "取货库位的排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "任务状态(0:未开始、1执行中、2已完成、3已取消)", example = "1")
private Integer taskStatus;

View File

@ -78,6 +78,18 @@ public class RobotTaskDetailRespVO {
@ExcelProperty("创建时间")
private LocalDateTime createTime;
@Schema(description = "取货线库id")
@ExcelProperty("取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id")
@ExcelProperty("放货线库id")
private Long toLaneId;
@Schema(description = "取货库位的排序的位置,越大越优先堆放")
@ExcelProperty("取货库位的排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "取货层数")
@ExcelProperty("取货层数")
private Integer fromLocationStorey;

View File

@ -38,6 +38,15 @@ public class RobotTaskDetailSaveReqVO {
@NotNull(message = "取货库位/线库/区域不能为空")
private Long takeId;
@Schema(description = "取货线库id")
private Long fromLaneId;
@Schema(description = "放货线库id")
private Long toLaneId;
@Schema(description = "取货库位的排序的位置,越大越优先堆放")
private Long locationNumber;
@Schema(description = "计算后的来源库位编号")
private String fromLocationNo;
@Schema(description = "计算后的来源库位id")

View File

@ -1,12 +1,14 @@
package cn.iocoder.yudao.module.system.dal.dataobject.information;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.KeySequence;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.*;
import java.math.BigDecimal;
import java.time.LocalDateTime;
/**
* 设备信息 DO
@ -28,6 +30,30 @@ public class DeviceInformationDO extends BaseDO {
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 地图id
*/
private Long positionMapId;
/**
* 地图子表节点id
*/
private Long positionMapItemId;
/**
* 库位坐标x轴
*/
private String locationX;
/**
* 库位坐标y轴
*/
private String locationY;
/**
* 宽度
*/
private BigDecimal locationWide;
/**
* 深度
*/
private BigDecimal locationDeep;
/**
* 设备类型1充电桩2输送线 3码垛机4拆垛机5自动门6提升机7信号灯8按钮盒
*/
@ -40,6 +66,10 @@ public class DeviceInformationDO extends BaseDO {
* mac地址
*/
private String macAddress;
/**
* 设备在地图上图标
*/
private String mapImageUrl;
/**
* 上传图片附件
*/
@ -65,4 +95,4 @@ public class DeviceInformationDO extends BaseDO {
*/
private LocalDateTime deviceLastTime;
}
}

View File

@ -32,11 +32,11 @@ public class ParkingSpotDO extends BaseDO {
/**
* 地图id
*/
private Long mapId;
private Long positionMapId;
/**
* 地图表节点id
* 地图表节点id
*/
private Long mapItemId;
private Long positionMapItemId;
/**
* 库位坐标x轴
*/

View File

@ -0,0 +1,98 @@
package cn.iocoder.yudao.module.system.dal.dataobject.robot;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.*;
import java.util.*;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import java.time.LocalDateTime;
import com.baomidou.mybatisplus.annotation.*;
import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
/**
* 机器人自动移库 DO
*
* @author 陈宾顺
*/
@TableName("robot_task_auto_move")
@KeySequence("robot_task_auto_move_seq") // 用于 OraclePostgreSQLKingbaseDB2H2 数据库的主键自增如果是 MySQL 等数据库可不写
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class RobotTaskAutoMoveDO extends BaseDO {
/**
* 主键ID
*/
@TableId(type = IdType.ASSIGN_ID)
private Long id;
/**
* 机器人任务主表id
*/
private Long robotTaskId;
/**
* 机器人任务明细表id
*/
private Long robotTaskDetailId;
/**
* 原库位编号
*/
private String fromLocationNo;
/**
* 原库位id
*/
private Long fromLocationId;
/**
* 搬去的目标库位编号
*/
private String toLocationNo;
/**
* 搬去的目标库位id/停车点/充电点/移动终点
*/
private Long toLocationId;
/**
* 取货线库id
*/
private Long fromLaneId;
/**
* 放货线库id (目前设计不会用到此字段)
*/
private Long toLaneId;
/**
* 任务状态(0:未开始1执行中2已完成3已取消4异常)
*/
private Integer taskStatus;
/**
* 优先级
*/
private Long priority;
/**
* AGV编号
*/
private String robotNo;
/**
* 任务类型1自动移库
*/
private Integer taskType;
/**
* 移动类型1 2
*/
private Integer moveType;
/**
* 开始时间
*/
private LocalDateTime startTime;
/**
* 结束时间
*/
private LocalDateTime endTime;
/**
* robot_task_auto_move表id来回搬运需要记录上一次搬运的源库位
*/
private Long taskAutoMoveId;
}

View File

@ -59,6 +59,18 @@ public class RobotTaskDetailDO extends BaseDO {
* 计算后的来源库位id
*/
private Long fromLocationId;
/**
* 取货线库id
*/
private Long fromLaneId;
/**
* 放货线库id
*/
private Long toLaneId;
/**
* 取货库位的排序的位置,越大越优先堆放
*/
private Long locationNumber;
/**
* 计算后的目标库位编号
*/

View File

@ -73,14 +73,6 @@ public interface WareHouseLocationMapper extends BaseMapperX<WareHouseLocationDO
*/
WareHouseLocationDO queryAllByLimit(WareHouseLocationDO wareHouseLocationDO);
/**
* 更新库位锁定状态
* @param id
* @param locationLock
*/
void updateLocationLockStatus(@Param("id") Long id,
@Param("locationLock") int locationLock,
@Param("taskId") Long taskId);
/**
* 查询库位
@ -93,7 +85,8 @@ public interface WareHouseLocationMapper extends BaseMapperX<WareHouseLocationDO
@Param("mapIds") Set<Long> mapIds);
void updateLocationLockList( @Param("locationIds") List<Long> locationIds,
@Param("taskId") Long taskId);
@Param("taskId") Long taskId,
@Param("locationLock") Integer locationLock);
/**
* 根据类型查库位/线库/区域
@ -101,4 +94,18 @@ public interface WareHouseLocationMapper extends BaseMapperX<WareHouseLocationDO
* @return
*/
List<WareHouseLocationRespVO> getLocationByName(WareHouseLocationVO requestVO);
/**
* 查询相通的线库 有货的 排序的位置较小的库位
* @param locations
* @return
*/
List<WareHouseLocationDO> selectLocationByList(@Param("locations") List<WareHouseLocationDO> locations);
/**
* 查询需要移库的库位
* @param locationIds
* @return
*/
List<WareHouseLocationDO> selectNeedMoveLocation(@Param("locationIds") Set<Long> locationIds);
}

View File

@ -1,13 +1,11 @@
package cn.iocoder.yudao.module.system.dal.mysql.parkingspot;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.system.controller.admin.parkingspot.vo.ParkingSpotPageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.parkingspot.ParkingSpotDO;
import org.apache.ibatis.annotations.Mapper;
import cn.iocoder.yudao.module.system.controller.admin.parkingspot.vo.*;
/**
* 停车点 Mapper
@ -19,8 +17,8 @@ public interface ParkingSpotMapper extends BaseMapperX<ParkingSpotDO> {
default PageResult<ParkingSpotDO> selectPage(ParkingSpotPageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<ParkingSpotDO>()
.eqIfPresent(ParkingSpotDO::getMapId, reqVO.getMapId())
.eqIfPresent(ParkingSpotDO::getMapItemId, reqVO.getMapItemId())
.eqIfPresent(ParkingSpotDO::getPositionMapId, reqVO.getPositionMapId())
.eqIfPresent(ParkingSpotDO::getPositionMapItemId, reqVO.getPositionMapItemId())
.eqIfPresent(ParkingSpotDO::getLocationX, reqVO.getLocationX())
.eqIfPresent(ParkingSpotDO::getLocationY, reqVO.getLocationY())
.eqIfPresent(ParkingSpotDO::getLocationWide, reqVO.getLocationWide())
@ -32,4 +30,4 @@ public interface ParkingSpotMapper extends BaseMapperX<ParkingSpotDO> {
.orderByDesc(ParkingSpotDO::getId));
}
}
}

View File

@ -32,11 +32,6 @@ public interface RobotInformationMapper extends BaseMapperX<RobotInformationDO>
.orderByDesc(RobotInformationDO::getId));
}
/**
* 查询空闲的机器人
* @return
*/
List<RobotInformationDO> selectFreeRobot();
/**
* 更新机器人状态
@ -64,4 +59,12 @@ public interface RobotInformationMapper extends BaseMapperX<RobotInformationDO>
* @return
*/
List<RobotInformationDO> selectByRobotNos(@Param("robotNos") Set<String> robotNos);
/**
* 更新任务模式0拒收任务1正常
* @param robotNos
* @param robotTaskModel
*/
void updateRobotTaskModel(@Param("robotNos") Set<String> robotNos,
@Param("robotTaskModel") Integer robotTaskModel);
}

View File

@ -0,0 +1,40 @@
package cn.iocoder.yudao.module.system.dal.mysql.robot;
import java.util.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.mapper.BaseMapperX;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMovePageReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskAutoMoveDO;
import org.apache.ibatis.annotations.Mapper;
/**
* 机器人自动移库 Mapper
*
* @author 陈宾顺
*/
@Mapper
public interface RobotTaskAutoMoveMapper extends BaseMapperX<RobotTaskAutoMoveDO> {
default PageResult<RobotTaskAutoMoveDO> selectPage(RobotTaskAutoMovePageReqVO reqVO) {
return selectPage(reqVO, new LambdaQueryWrapperX<RobotTaskAutoMoveDO>()
.eqIfPresent(RobotTaskAutoMoveDO::getRobotTaskId, reqVO.getRobotTaskId())
.eqIfPresent(RobotTaskAutoMoveDO::getRobotTaskDetailId, reqVO.getRobotTaskDetailId())
.eqIfPresent(RobotTaskAutoMoveDO::getFromLocationNo, reqVO.getFromLocationNo())
.eqIfPresent(RobotTaskAutoMoveDO::getFromLocationId, reqVO.getFromLocationId())
.eqIfPresent(RobotTaskAutoMoveDO::getToLocationNo, reqVO.getToLocationNo())
.eqIfPresent(RobotTaskAutoMoveDO::getToLocationId, reqVO.getToLocationId())
.eqIfPresent(RobotTaskAutoMoveDO::getTaskStatus, reqVO.getTaskStatus())
.eqIfPresent(RobotTaskAutoMoveDO::getPriority, reqVO.getPriority())
.eqIfPresent(RobotTaskAutoMoveDO::getRobotNo, reqVO.getRobotNo())
.eqIfPresent(RobotTaskAutoMoveDO::getTaskType, reqVO.getTaskType())
.eqIfPresent(RobotTaskAutoMoveDO::getMoveType, reqVO.getMoveType())
.betweenIfPresent(RobotTaskAutoMoveDO::getStartTime, reqVO.getStartTime())
.betweenIfPresent(RobotTaskAutoMoveDO::getEndTime, reqVO.getEndTime())
.eqIfPresent(RobotTaskAutoMoveDO::getTaskAutoMoveId, reqVO.getTaskAutoMoveId())
.betweenIfPresent(RobotTaskAutoMoveDO::getCreateTime, reqVO.getCreateTime())
.orderByDesc(RobotTaskAutoMoveDO::getId));
}
}

View File

@ -32,7 +32,7 @@ public interface RobotTaskMapper extends BaseMapperX<RobotTaskDO> {
.eqIfPresent(RobotTaskDO::getDoMoveAll, reqVO.getDoMoveAll())
.eqIfPresent(RobotTaskDO::getCycleNumber, reqVO.getCycleNumber())
.eqIfPresent(RobotTaskDO::getRemainingCycleNumber, reqVO.getRemainingCycleNumber())
.eqIfPresent(RobotTaskDO::getTaskNo, reqVO.getTaskNo())
.likeIfPresent(RobotTaskDO::getTaskNo, reqVO.getTaskNo())
.eqIfPresent(RobotTaskDO::getTaskStatus, reqVO.getTaskStatus())
.eqIfPresent(RobotTaskDO::getTaskStage, reqVO.getTaskStage())
.betweenIfPresent(RobotTaskDO::getStartTime, reqVO.getStartTime())

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_auto_move的task_status
*/
@Getter
@AllArgsConstructor
public enum AutoMoveTaskStatusEnum {
NEW(0),//未开始
DOING(1),//执行中
DONE(2),//已完成
CLOSE(3), //已取消
Exc(4); //异常
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,18 @@
package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_auto_move的task_type
*/
@Getter
@AllArgsConstructor
public enum AutoMoveTaskTypeEnum {
AUTO_MOVE(1); //自动移库
/**
* 类型
*/
private final Integer type;
}

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_auto_move的move_type
*/
@Getter
@AllArgsConstructor
public enum AutoMoveTypeEnum {
GO(1), //
BACK(1); //
/**
* 类型
*/
private final Integer type;
}

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 下发给车机的类型
*/
@Getter
@AllArgsConstructor
public enum CommandTypeEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task的do_cycle
*/
@Getter
@AllArgsConstructor
public enum DoCycleEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* ware_house_location的location_enable
*/
@Getter
@AllArgsConstructor
public enum LocationEnableEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* ware_house_location的location_lock
*/
@Getter
@AllArgsConstructor
public enum LocationLockEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* ware_house_location的location_use_status
*/
@Getter
@AllArgsConstructor
public enum LocationUseStatusEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task的montage_task
*/
@Getter
@AllArgsConstructor
public enum MontageTaskEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task的do_move_all
*/
@Getter
@AllArgsConstructor
public enum MoveAllEnum {

View File

@ -4,7 +4,7 @@ import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* 放货类型
* 放货类型robot_task_detail的release_type
*/
@Getter
@AllArgsConstructor

View File

@ -0,0 +1,21 @@
package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_auto_move表的task_status状态
*/
@Getter
@AllArgsConstructor
public enum RobotMoveStatusEnum {
NEW(0),//未开始
DOING(1),//执行中
DONE(2),//已完成
CLOSE(3), //已取消
Exc(4); //异常
/**
* 类型
*/
private final Integer type;
}

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_detail的task_status
*/
@Getter
@AllArgsConstructor
public enum RobotTaskDetailStatusEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_information的robot_task_model
*/
@Getter
@AllArgsConstructor
public enum RobotTaskModelEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task表的task_status
*/
@Getter
@AllArgsConstructor
public enum RobotTaskStatusEnum {

View File

@ -3,6 +3,9 @@ package cn.iocoder.yudao.module.system.enums.robot;
import lombok.AllArgsConstructor;
import lombok.Getter;
/**
* robot_task_detail的task_type
*/
@Getter
@AllArgsConstructor
public enum RobotTaskTypeEnum {

View File

@ -3,18 +3,12 @@ package cn.iocoder.yudao.module.system.handler.mapnode;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.enums.NodeTypeEnum;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.positionmap.PositionMapItemDO;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.HouseLocationStrategyImpl;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.MapNodeStrategyImpl;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.NodeProcessingStrategy;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.ParkingSpotStrategyImpl;
import cn.iocoder.yudao.module.system.handler.mapnode.strategy.*;
import cn.iocoder.yudao.module.system.service.positionmap.PositionMapItemService;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
@ -23,16 +17,13 @@ import javax.annotation.PostConstruct;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import static com.baomidou.mybatisplus.core.toolkit.IdWorker.getId;
@Component
public class NodeProcessingContext {
private final Map<Integer, NodeProcessingStrategy> strategyMap = new HashMap<>();
@Autowired
private PositionMapItemService positionMapItemService;
@Autowired
private MapNodeStrategyImpl mapNodeStrategyImpl;
@Autowired
@ -40,7 +31,7 @@ public class NodeProcessingContext {
@Autowired
private ParkingSpotStrategyImpl parkingSpotStrategyImpl;
@Autowired
private PositionMapItemService positionMapItemService;
private DeviceStrategyImpl deviceStrategyImpl;
/**
* 项目启动时 初始化策略
@ -52,7 +43,7 @@ public class NodeProcessingContext {
// 库位
strategyMap.put(NodeTypeEnum.WARE.getType(), houseLocationStrategyImpl);
// 设备点
// strategyMap.put(NodeTypeEnum.EQUIPMENT.getType(), houseLocationStrategyImpl);
strategyMap.put(NodeTypeEnum.DEVICE.getType(), deviceStrategyImpl);
// 停车点
strategyMap.put(NodeTypeEnum.PARKING.getType(), parkingSpotStrategyImpl);
// 路径点

View File

@ -0,0 +1,51 @@
package cn.iocoder.yudao.module.system.handler.mapnode.strategy;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.module.system.controller.admin.positionmap.dto.NodeBaseDTO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
import cn.iocoder.yudao.module.system.service.information.DeviceInformationService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import static com.baomidou.mybatisplus.core.toolkit.IdWorker.getId;
@Component
public class DeviceStrategyImpl implements NodeProcessingStrategy {
@Resource
private DeviceInformationService deviceInformationService;
@Override
public void processNodes(Long positionMapId, List<NodeBaseDTO> nodeBaseDTOS) {
// -- 策略3 处理设备点
// -- 将data里面的json 数据转为实体类 - 再对比节点id - 然后做新增删除修改操作
// --------------- dataJSON里面没有具体的类的id - 然后库位要根据层数添加 多个库位数据 一个点位 对应多个库位
List<DeviceInformationDO> newList = new ArrayList<>();
nodeBaseDTOS.forEach(item -> {
if (item.getId() == null) {
item.setId(getId());
}
item.setPositionMapId(positionMapId);
DeviceInformationDO deviceInformationDO = JSONUtil.toBean(item.getDataJson(), DeviceInformationDO.class);
if (deviceInformationDO.getId() == null) {
deviceInformationDO.setId(getId());
}
deviceInformationDO.setLocationX(item.getLocationX());
deviceInformationDO.setLocationY(item.getLocationY());
deviceInformationDO.setPositionMapId(positionMapId);
deviceInformationDO.setPositionMapItemId(item.getId());
newList.add(deviceInformationDO);
item.setDataJson(JSONUtil.toJsonStr(deviceInformationDO));
});
List<DeviceInformationDO> oldList = deviceInformationService.getByMapId(positionMapId);
List<List<DeviceInformationDO>> list = CollectionUtils.diffList(oldList, newList,
(oldVal, newVal) -> ObjectUtil.equal(oldVal.getId(), newVal.getId()));
deviceInformationService.batchSaveOrEditOrDel(positionMapId, list);
}
}

View File

@ -30,7 +30,6 @@ public class ParkingSpotStrategyImpl implements NodeProcessingStrategy {
item.setId(getId());
}
item.setPositionMapId(positionMapId);
// -- 如果是库位点 - 可能是一对多情况 - 需要将多个库位点的id set进去
ParkingSpotDO parkingSpotDO = JSONUtil.toBean(item.getDataJson(), ParkingSpotDO.class);
if (parkingSpotDO.getId() == null) {
parkingSpotDO.setId(getId());
@ -38,8 +37,8 @@ public class ParkingSpotStrategyImpl implements NodeProcessingStrategy {
parkingSpotDO.setLocationX(item.getLocationX());
parkingSpotDO.setLocationY(item.getLocationY());
parkingSpotDO.setMapId(positionMapId);
parkingSpotDO.setMapItemId(item.getId());
parkingSpotDO.setPositionMapId(positionMapId);
parkingSpotDO.setPositionMapItemId(item.getId());
newList.add(parkingSpotDO);
item.setDataJson(JSONUtil.toJsonStr(parkingSpotDO));
});

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.job.robot;
import cn.iocoder.yudao.framework.tenant.core.job.TenantJob;
import cn.iocoder.yudao.module.system.enums.redis.RobotCacheLockEnum;
import cn.iocoder.yudao.module.system.service.robot.job.DistributeTasksService;
import cn.iocoder.yudao.module.system.service.robot.job.RobotTaskAutoMoveService;
import cn.iocoder.yudao.module.system.util.redis.RedissonUtils;
import com.xxl.job.core.handler.annotation.XxlJob;
import lombok.extern.slf4j.Slf4j;
@ -12,6 +13,12 @@ import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashSet;
import java.util.Set;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.REDISSON_NOT_OBTAIN_LOCK;
@Component
@Slf4j
@ -23,6 +30,9 @@ public class RobotJob {
@Autowired
private DistributeTasksService distributeTasksService;
@Autowired
private RobotTaskAutoMoveService robotTaskAutoMoveService;
//下发任务给车机
@XxlJob("DistributeTasksJob")
@TenantJob
@ -37,6 +47,32 @@ public class RobotJob {
} finally {
lock.unlock();
}
}else {
log.info("下发任务未获取到锁");
throw exception(REDISSON_NOT_OBTAIN_LOCK);
}
}
//下发自动移库任务
@XxlJob("DistributeAutoMoveJob")
@TenantJob
public void distributeAutoMoveJob() throws InterruptedException {
log.info("----下发自动移库任务----");
Set<String> locks = new HashSet<>();
locks.add(RobotCacheLockEnum.ROBOT_TASK_DISTRIBUTE_LOCK.getKey());
locks.add(RobotCacheLockEnum.ROBOT_TASK_ADD_LOCK.getKey());
RLock lock = redissonUtils.getLocks(locks);
if (lock.tryLock()){
try {
robotTaskAutoMoveService.distributeAutoMoveJob();
} catch (Exception e) {
log.error("下发自动移库任务出现异常 :{}",e.getMessage());
} finally {
lock.unlock();
}
}else {
log.info("下发自动移库任务未获取到锁");
throw exception(REDISSON_NOT_OBTAIN_LOCK);
}
}

View File

@ -1,13 +1,13 @@
package cn.iocoder.yudao.module.system.service.information;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
import javax.validation.Valid;
import java.util.List;
/**
* 设备信息 Service 接口
*
@ -53,4 +53,27 @@ public interface DeviceInformationService {
*/
PageResult<DeviceInformationDO> getInformationPage(DeviceInformationPageReqVO pageReqVO);
}
/**
* 批量新增删除修改
*
* @param positionMapId
* @param list
*/
void batchSaveOrEditOrDel(Long positionMapId, List<List<DeviceInformationDO>> list);
/**
* 通过地图id获取设备列表
*
* @param positionMapId
* @return
*/
List<DeviceInformationDO> getByMapId(Long positionMapId);
/**
* 获取设备列表
*
* @param pageReqVO
* @return
*/
List<DeviceInformationDO> getList(@Valid DeviceInformationPageReqVO pageReqVO);
}

View File

@ -1,25 +1,29 @@
package cn.iocoder.yudao.module.system.service.information;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.module.grpc.api.GrpcServiceApi;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationPageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.information.vo.DeviceInformationSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.information.DeviceInformationDO;
import cn.iocoder.yudao.module.system.dal.mysql.information.DeviceInformationMapper;
import cn.iocoder.yudao.module.system.enums.device.DeviceInformationEnum;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
import static cn.hutool.core.collection.CollUtil.isNotEmpty;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.*;
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.INFORMATION_MAC_EXIST;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.INFORMATION_NOT_EXISTS;
/**
* 设备信息 Service 实现类
@ -42,7 +46,7 @@ public class DeviceInformationServiceImpl implements DeviceInformationService {
DeviceInformationPageReqVO pageReqVO = new DeviceInformationPageReqVO();
pageReqVO.setMacAddress(createReqVO.getMacAddress());
PageResult<DeviceInformationDO> pageResult = informationMapper.selectPage(pageReqVO);
if(ObjectUtil.isNotEmpty(pageResult.getList())){
if (ObjectUtil.isNotEmpty(pageResult.getList())) {
throw exception(INFORMATION_MAC_EXIST);
}
// 插入
@ -87,4 +91,31 @@ public class DeviceInformationServiceImpl implements DeviceInformationService {
return informationMapper.selectPage(pageReqVO);
}
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchSaveOrEditOrDel(Long positionMapId, List<List<DeviceInformationDO>> list) {
//批量添加修改删除
if (isNotEmpty(list.get(0))) {
informationMapper.insertBatch(list.get(0));
}
if (isNotEmpty(list.get(1))) {
informationMapper.updateBatch(list.get(1));
}
if (isNotEmpty(list.get(2))) {
informationMapper.deleteByIds(convertList(list.get(2), DeviceInformationDO::getId));
}
}
@Override
public List<DeviceInformationDO> getByMapId(Long positionMapId) {
return informationMapper.selectList(new LambdaQueryWrapperX<DeviceInformationDO>()
.eq(DeviceInformationDO::getPositionMapId, positionMapId));
}
@Override
public List<DeviceInformationDO> getList(DeviceInformationPageReqVO pageReqVO) {
return informationMapper.selectList(new LambdaQueryWrapper<DeviceInformationDO>()
.eq(pageReqVO.getDeviceType() != null, DeviceInformationDO::getDeviceType, pageReqVO.getDeviceType()));
}
}

View File

@ -9,6 +9,7 @@ import cn.iocoder.yudao.module.system.dal.dataobject.parkingspot.ParkingSpotDO;
import cn.iocoder.yudao.module.system.dal.mysql.parkingspot.ParkingSpotMapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import javax.annotation.Resource;
@ -65,10 +66,11 @@ public class ParkingSpotServiceImpl extends ServiceImpl<ParkingSpotMapper, Parki
@Override
public List<ParkingSpotDO> getByMapId(Long positionMapId) {
return parkingSpotMapper.selectList(new LambdaQueryWrapperX<ParkingSpotDO>()
.eq(ParkingSpotDO::getMapId, positionMapId));
.eq(ParkingSpotDO::getPositionMapId, positionMapId));
}
@Override
@Transactional(rollbackFor = Exception.class)
public void batchSaveOrEditOrDel(Long positionMapId, List<List<ParkingSpotDO>> list) {
//批量添加修改删除
if (isNotEmpty(list.get(0))) {

View File

@ -66,4 +66,11 @@ public interface RobotInformationService {
* @return
*/
List<RobotInformationDO> getCanUseRobot();
/**
* 查询所有车辆
* @return
*/
List<RobotInformationDO> getAllRobot();
}

View File

@ -173,4 +173,10 @@ public class RobotInformationServiceImpl implements RobotInformationService {
return informationMapper.queryAllByLimit(query);
}
@Override
public List<RobotInformationDO> getAllRobot() {
RobotInformationDO query = new RobotInformationDO();
return informationMapper.queryAllByLimit(query);
}
}

View File

@ -3,6 +3,7 @@ package cn.iocoder.yudao.module.system.service.robot;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.mybatis.core.util.MyBatisUtils;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
@ -93,7 +94,7 @@ public class RobotTaskServiceImpl implements RobotTaskService {
RLock lock = redissonUtils.getLock(RobotCacheLockEnum.ROBOT_TASK_ADD_LOCK.getKey());
String addResult = "";
if (lock.tryLock(30l,TimeUnit.MINUTES)){
if (lock.tryLock(60l,TimeUnit.MINUTES)){
try {
addResult = addTask(createReqVO);
} catch (Exception e) {
@ -155,6 +156,14 @@ public class RobotTaskServiceImpl implements RobotTaskService {
throw exception0(TASK_CHECK_EXCEPTION.getCode(), "以下机器人已被禁用 ",robotNo);
}
}
//校验任务号是否重复
if (ObjectUtil.isNotEmpty(createReqVO.getTaskNo())) {
List<RobotTaskDO> taskDOS = taskMapper.selectList(new LambdaQueryWrapperX<RobotTaskDO>()
.eq(RobotTaskDO::getTaskNo, createReqVO.getTaskNo()));
if (ObjectUtil.isNotEmpty(taskDOS)) {
throw exception(TASK_CHECK_EXIST_NO);
}
}
}
/**
@ -166,11 +175,14 @@ public class RobotTaskServiceImpl implements RobotTaskService {
RobotTaskDO task = BeanUtils.toBean(createReqVO, RobotTaskDO.class);
taskMapper.insert(task);
// todo 更新数据库顺序 后续改为xxl-job一致
//查找库位
List<Long> locationIds = new ArrayList<>();
if (MoveAllEnum.NO.getType().equals(createReqVO.getDoMoveAll())) {
setSingleLocationIdNo(createReqVO.getTaskDetailList(),task);
locationIds = setSingleLocationIdNo(createReqVO.getTaskDetailList(),task);
} else {
setAllLocationIdNo(createReqVO,task.getId());
locationIds = setAllLocationIdNo(createReqVO,task.getId());
}
// 插入
@ -180,6 +192,11 @@ public class RobotTaskServiceImpl implements RobotTaskService {
});
robotTaskDetailService.insertRobotDetailList(createReqVO.getTaskDetailList());
List<List<Long>> fromPartition = Lists.partition(locationIds, 100);
fromPartition.forEach(list-> {
locationMapper.updateLocationLockList(list,task.getId(),LocationLockEnum.NO.getType());
});
return RESULT;
}
@ -189,7 +206,7 @@ public class RobotTaskServiceImpl implements RobotTaskService {
* @param taskId
*/
@Transactional(rollbackFor = Exception.class)
public void setAllLocationIdNo(RobotTaskSaveReqVO createReqVO, Long taskId) {
public List<Long> setAllLocationIdNo(RobotTaskSaveReqVO createReqVO, Long taskId) {
List<RobotTaskDetailAddVO> taskDetailList = createReqVO.getTaskDetailList();
List<RobotTaskDetailAddVO> newTaskDetailList = new ArrayList<>();
@ -266,17 +283,11 @@ public class RobotTaskServiceImpl implements RobotTaskService {
}
createReqVO.setTaskDetailList(newTaskDetailList);
//跟新库位状态为锁定
List<List<Long>> toPartition = Lists.partition(toLocationIds, 100);
toPartition.forEach(list-> {
locationMapper.updateLocationLockList(list,taskId);
});
List<List<Long>> fromPartition = Lists.partition(fromLocationIds, 100);
fromPartition.forEach(list-> {
locationMapper.updateLocationLockList(list,taskId);
});
if (ObjectUtil.isNotEmpty(fromLocationIds)) {
toLocationIds.addAll(fromLocationIds);
}
return toLocationIds;
}
/**
@ -304,6 +315,9 @@ public class RobotTaskServiceImpl implements RobotTaskService {
robotTaskDetailAddVo.setFromLocationId(stockList.get(i).getId());
robotTaskDetailAddVo.setToLocationNo(releaseStockList.get(i).getLocationNo());
robotTaskDetailAddVo.setToLocationId(releaseStockList.get(i).getId());
robotTaskDetailAddVo.setFromLaneId(stockList.get(i).getLaneId());
robotTaskDetailAddVo.setToLaneId(releaseStockList.get(i).getLaneId());
robotTaskDetailAddVo.setLocationNumber(stockList.get(i).getLocationNumber());
robotTaskDetailAddVo.setRobotTaskId(taskId);
robotTaskDetailAddVo.setPriority(robotTaskVo.getPriority());
robotTaskDetailAddVo.setFromLocationStorey(stockList.get(i).getLocationStorey());
@ -322,7 +336,7 @@ public class RobotTaskServiceImpl implements RobotTaskService {
* @return
*/
@Transactional(rollbackFor = Exception.class)
public void setSingleLocationIdNo(List<RobotTaskDetailAddVO> taskDetailList, RobotTaskDO task){
public List<Long> setSingleLocationIdNo(List<RobotTaskDetailAddVO> taskDetailList, RobotTaskDO task){
List<Long> locationIds = new ArrayList<>();
for (RobotTaskDetailAddVO robotTaskVo : taskDetailList) {
robotTaskVo.setRobotTaskId(task.getId());
@ -348,16 +362,17 @@ public class RobotTaskServiceImpl implements RobotTaskService {
doRelease(robotTaskVo,locationIds);
break;
case SCAN:
doScan(robotTaskVo);
doScan(robotTaskVo,locationIds);
break;
case DETECTING_TRAYS:
doDetectingTrays(robotTaskVo);
doDetectingTrays(robotTaskVo,locationIds);
break;
default :
log.error("任务类型不存在 ");
throw new RuntimeException("任务类型不存在");
}
}
return locationIds;
}
/**
@ -365,9 +380,9 @@ public class RobotTaskServiceImpl implements RobotTaskService {
* @param robotTaskVo
*/
@Transactional(rollbackFor = Exception.class)
public void doDetectingTrays(RobotTaskDetailAddVO robotTaskVo) {
public void doDetectingTrays(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds) {
setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),new ArrayList<>());
locationMapper.updateLocationLockStatus(robotTaskVo.getToLocationId(),0,robotTaskVo.getRobotTaskId());
locationIds.add(robotTaskVo.getToLocationId());
}
/**
@ -375,9 +390,9 @@ public class RobotTaskServiceImpl implements RobotTaskService {
* @param robotTaskVo
*/
@Transactional(rollbackFor = Exception.class)
public void doScan(RobotTaskDetailAddVO robotTaskVo) {
public void doScan(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds) {
setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),new ArrayList<>());
locationMapper.updateLocationLockStatus(robotTaskVo.getToLocationId(),0,robotTaskVo.getRobotTaskId());
locationIds.add(robotTaskVo.getToLocationId());
}
/**
@ -387,7 +402,6 @@ public class RobotTaskServiceImpl implements RobotTaskService {
@Transactional(rollbackFor = Exception.class)
public void doRelease(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds) {
setToLocation(robotTaskVo,getMapIdsByRobotNo(robotTaskVo.getRobotNo()),locationIds);
locationMapper.updateLocationLockStatus(robotTaskVo.getToLocationId(),0,robotTaskVo.getRobotTaskId());
locationIds.add(robotTaskVo.getToLocationId());
}
@ -397,7 +411,11 @@ public class RobotTaskServiceImpl implements RobotTaskService {
*/
@Transactional(rollbackFor = Exception.class)
public void doTake(RobotTaskDetailAddVO robotTaskVo, List<Long> locationIds) {
locationMapper.updateLocationLockStatus(robotTaskVo.getFromLocationId(),0,robotTaskVo.getRobotTaskId());
Set<Long> mapIds = new HashSet<>();
if (ObjectUtil.isNotEmpty(robotTaskVo.getRobotNo())) {
mapIds = getMapIdsByRobotNo(robotTaskVo.getRobotNo());
}
setFromLocation(robotTaskVo,mapIds,locationIds);
locationIds.add(robotTaskVo.getFromLocationId());
}
@ -459,6 +477,7 @@ public class RobotTaskServiceImpl implements RobotTaskService {
robotTaskVo.setToLocationNo(locationDO.getLocationNo());
robotTaskVo.setToLocationId(robotTaskVo.getReleaseId());
robotTaskVo.setToLocationStorey(locationDO.getLocationStorey());
robotTaskVo.setToLaneId(locationDO.getLaneId());
if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
log.error("机器人不能在此放货库位放货 :{}, 机器人编号 :{}", locationDO.getLocationNo(),robotTaskVo.getRobotNo());
throw new RuntimeException("机器人不能在此放货库位放货 "+ robotTaskVo.getReleaseId());
@ -474,6 +493,7 @@ public class RobotTaskServiceImpl implements RobotTaskService {
robotTaskVo.setToLocationNo(wareHouseLocationDO.getLocationNo());
robotTaskVo.setToLocationId(wareHouseLocationDO.getId());
robotTaskVo.setToLocationStorey(wareHouseLocationDO.getLocationStorey());
robotTaskVo.setToLaneId(wareHouseLocationDO.getLaneId());
}
}
@ -491,6 +511,8 @@ public class RobotTaskServiceImpl implements RobotTaskService {
robotTaskVo.setFromLocationNo(locationDO.getLocationNo());
robotTaskVo.setFromLocationId(robotTaskVo.getTakeId());
robotTaskVo.setFromLocationStorey(locationDO.getLocationStorey());
robotTaskVo.setFromLaneId(locationDO.getLaneId());
robotTaskVo.setLocationNumber(locationDO.getLocationNumber());
if (ObjectUtil.isNotEmpty(mapIds) && !mapIds.contains(locationDO.getMapId())) {
log.error("机器人不能在此取货库位取货 :{}, 机器人编号 :{}", locationDO.getLocationNo(),robotTaskVo.getRobotNo());
throw new RuntimeException("机器人不能在此取货库位取货 "+ robotTaskVo.getTakeId());
@ -506,6 +528,8 @@ public class RobotTaskServiceImpl implements RobotTaskService {
robotTaskVo.setFromLocationNo(wareHouseLocationDO.getLocationNo());
robotTaskVo.setFromLocationId(wareHouseLocationDO.getId());
robotTaskVo.setFromLocationStorey(wareHouseLocationDO.getLocationStorey());
robotTaskVo.setFromLaneId(wareHouseLocationDO.getLaneId());
robotTaskVo.setLocationNumber(wareHouseLocationDO.getLocationNumber());
}
}
@ -537,9 +561,6 @@ public class RobotTaskServiceImpl implements RobotTaskService {
throw new RuntimeException("取货库位,存在未完成的任务 ");
}
//设置为锁定
locationMapper.updateLocationLockStatus(robotTaskVo.getToLocationId(),0,robotTaskVo.getRobotTaskId());
locationMapper.updateLocationLockStatus(robotTaskVo.getFromLocationId(),0,robotTaskVo.getRobotTaskId());
}
@Override
@ -574,7 +595,11 @@ public class RobotTaskServiceImpl implements RobotTaskService {
&& !robotTaskDO.getTaskStatus().equals(updateReqVO.getTaskStatus())) {
throw exception(TASK_CHECK_TASK_STATUS);
}
List<Long> locationIds = new ArrayList<>();
Set<String> robotNos = new HashSet<>();
if (ObjectUtil.isNotEmpty(updateReqVO.getTaskStatus())
&& RobotTaskStatusEnum.CLOSE.getType().equals(updateReqVO.getTaskStatus())
&& !robotTaskDO.getTaskStatus().equals(updateReqVO.getTaskStatus())) {
for (RobotTaskDetailDO taskDetailDO : taskDetailDOS) {
if (RobotTaskDetailStatusEnum.DONE.getType().equals(taskDetailDO.getTaskStatus())) {
@ -582,6 +607,18 @@ public class RobotTaskServiceImpl implements RobotTaskService {
}
//后期需做状态映射
taskDetailDO.setTaskStatus(updateReqVO.getTaskStatus());
// todo 关闭需要下发任务给车机 还需要考虑下处理中的任务怎么处理
if (ObjectUtil.isNotEmpty(taskDetailDO.getFromLocationId())) {
locationIds.add(taskDetailDO.getFromLocationId());
}
if (ObjectUtil.isNotEmpty(taskDetailDO.getToLocationId())) {
locationIds.add(taskDetailDO.getToLocationId());
}
if (ObjectUtil.isNotEmpty(taskDetailDO.getRobotNo())) {
robotNos.add(taskDetailDO.getRobotNo());
}
}
}
@ -589,6 +626,17 @@ public class RobotTaskServiceImpl implements RobotTaskService {
taskMapper.updateById(updateObj);
taskDetailMapper.updateBatch(taskDetailDOS);
if (ObjectUtil.isNotEmpty(locationIds)) {
locationMapper.updateLocationLockList(locationIds,robotTaskDO.getId()
,LocationLockEnum.YES.getType());
}
// todo 执行中的需要锁车 需要添加执行中的判断
if (ObjectUtil.isNotEmpty(robotNos)) {
// informationMapper.updateRobotTaskModel(robotNos,RobotTaskModelEnum.REJECTION.getType());
}
} catch (Exception e) {
log.error("更新任务失败 :{}",e.getMessage());
msg = e.getMessage();

View File

@ -1,5 +1,19 @@
package cn.iocoder.yudao.module.system.service.robot.job;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import org.apache.commons.lang3.tuple.Pair;
import java.util.List;
public interface DistributeTasksService {
/**
* 下发搬运任务
*/
void distributeTasks();
/**
* 获取待执行的机器人和任务
*/
Pair<List<RobotInformationDO>, List<RobotTaskDetailDO>> getRobotAndTaskDetails();
}

View File

@ -1,6 +1,7 @@
package cn.iocoder.yudao.module.system.service.robot.job;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.mqtt.api.task.RobotTaskApi;
import cn.iocoder.yudao.module.mqtt.api.task.dto.Pose2ds;
@ -18,6 +19,7 @@ import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskMapper;
import cn.iocoder.yudao.module.system.enums.robot.*;
import com.alibaba.fastjson.JSON;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.ImmutableTriple;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
@ -74,13 +76,42 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
@Override
@Transactional(rollbackFor = Exception.class)
public void distributeTasks() {
TenantContextHolder.setTenantId(1L);
List<RobotInformationDO> robots = robotInformationMapper.selectFreeRobot();
if (robots.isEmpty()) {
log.info("暂无空闲的机器人");
Pair<List<RobotInformationDO>, List<RobotTaskDetailDO>> robotAndTaskDetails = getRobotAndTaskDetails();
List<RobotInformationDO> robots = robotAndTaskDetails.getLeft();
if (ObjectUtil.isEmpty(robots)) {
return;
}
List<RobotTaskDetailDO> taskDetailDOS = robotAndTaskDetails.getRight();
if (ObjectUtil.isEmpty(taskDetailDOS)) {
return;
}
//任务下发给机器人
distributeTasks(robots,taskDetailDOS);
}
/**
* 获取待执行的机器人和任务
*/
@Override
@Transactional(rollbackFor = Exception.class)
public Pair<List<RobotInformationDO>, List<RobotTaskDetailDO>> getRobotAndTaskDetails() {
Pair<List<RobotInformationDO>, List<RobotTaskDetailDO>> pair = Pair.of(new ArrayList<>(), new ArrayList<>());;
TenantContextHolder.setTenantId(1L);
List<RobotInformationDO> robots = robotInformationMapper.selectList(new LambdaQueryWrapperX<RobotInformationDO>()
.eq(RobotInformationDO::getRobotStatus, (RobotStatusEnum.STAND_BY.getType()))
.eq(RobotInformationDO::getRobotTaskModel, RobotTaskModelEnum.NORMAL.getType())
.orderByDesc(RobotInformationDO::getUpdateTime));
if (robots.isEmpty()) {
log.info("暂无空闲的机器人");
return pair;
}
//todo 还需要根据车机上报的信息过滤掉不能用的机器人
//拼接任务id
List<Long> detailDongIds = robotTaskDetailMapper.getDoingTaskIds();
List<Long> montageTaskIds = robotTaskMapper.getUnDoAndDoingTaskIds(MontageTaskEnum.YES.getType(),detailDongIds);
@ -89,20 +120,16 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
if (ObjectUtil.isEmpty(montageTaskIds) && ObjectUtil.isEmpty(singleTaskIds)) {
log.info("暂无需要处理的主任务");
return;
return pair;
}
List<RobotTaskDetailDO> taskDetailDOS = getTaskDetail(montageTaskIds,singleTaskIds);
if (taskDetailDOS.isEmpty()) {
log.info("暂无需要处理的明细任务");
return;
return pair;
}
//如果系统暂停 则不下发任务
//任务下发给机器人
distributeTasks(robots,taskDetailDOS);
return ImmutablePair.of(robots, taskDetailDOS);
}
/**
@ -128,6 +155,12 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
@Transactional(rollbackFor = Exception.class)
public void distributeTasks(List<RobotInformationDO> robots, List<RobotTaskDetailDO> taskDetailDOS) {
List<RobotAcceptTaskDTO> robotTaskDOS = new ArrayList<>();
//需要更新的任务明细id
List<RobotTaskDetailDO> updateTaskDetails = new ArrayList<>();
//需要更新的任务id
Set<Long> taskIds = new HashSet<>();
//需要更新的机器人编号
Set<String> robotNos = new HashSet<>();
for (RobotTaskDetailDO taskDetailDO : taskDetailDOS) {
if (ObjectUtil.isEmpty(robots)) {
break;
@ -136,7 +169,7 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
RobotTaskTypeEnum robotTaskType = RobotTaskTypeEnum.getRobotTaskType(taskDetailDO.getTaskType());
switch (robotTaskType) {
case TAKE_RELEASE:
doTakeReleaseDistribute(taskDetailDO, robots,robotTaskDOS);
doTakeReleaseDistribute(taskDetailDO, robots,robotTaskDOS,taskIds,updateTaskDetails,robotNos);
break;
/*case PARK:
doParkDistribute(taskDetailDO, robots,robotTaskDOS);
@ -168,6 +201,27 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
log.info("任务下发给车机 :{}", JSON.toJSONString(robotTaskDOS));
robotTaskApi.sendTaskToRobot(robotTaskDOS);
}
if (ObjectUtil.isNotEmpty(taskIds)) {
List<RobotTaskDO> taskDOS = robotTaskMapper.selectBatchIds(taskIds);
for (RobotTaskDO taskDO : taskDOS) {
if (RobotTaskStatusEnum.NEW.getType().equals(taskDO.getTaskStatus())) {
taskDO.setTaskStatus(RobotTaskStatusEnum.DOING.getType());
taskDO.setStartTime(LocalDateTime.now());
}
}
robotTaskMapper.updateBatch(taskDOS);
}
if (ObjectUtil.isNotEmpty(updateTaskDetails)) {
robotTaskDetailMapper.updateBatch(updateTaskDetails);
}
if (ObjectUtil.isNotEmpty(robotNos)) {
List<RobotInformationDO> robotInformationDOS = robotInformationMapper.selectByRobotNos(robotNos);
robotInformationDOS.stream().forEach(robotInformationDO -> {
robotInformationDO.setRobotStatus(RobotStatusEnum.DOING.getType());
});
robotInformationMapper.updateBatch(robotInformationDOS);
}
}
/**
@ -342,7 +396,8 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
*/
@Transactional(rollbackFor = Exception.class)
public void doTakeReleaseDistribute(RobotTaskDetailDO taskDetailDO, List<RobotInformationDO> robots,
List<RobotAcceptTaskDTO> robotTaskDOS) {
List<RobotAcceptTaskDTO> robotTaskDOS,Set<Long> taskIdSet,
List<RobotTaskDetailDO> updateTaskDetail, Set<String> robotNos) {
WareHouseLocationDO query = WareHouseLocationDO.builder().id(taskDetailDO.getFromLocationId()).build();
WareHouseLocationDO fromLocation = locationMapper.queryAllByLimit(query);
@ -358,6 +413,8 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
return;
}
// todo 需要校验取放线库 都没有移库的任务
RobotAcceptTaskDTO robotTaskDO = new RobotAcceptTaskDTO();
robotTaskDO.setOrder_id(taskDetailDO.getId().toString());
robotTaskDO.setOrder_type("出库");//未定
@ -455,26 +512,6 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
}
/*Pose2ds poseOne = new Pose2ds();
poseOne.setX(-2.097);
poseOne.setY(-0.325);
poseOne.setYaw(1.571);
Pose2ds poseTwo = new Pose2ds();
poseTwo.setX(-0.856);
poseTwo.setY(1.622);
poseTwo.setYaw(0.034);
Pose2ds poseThree = new Pose2ds();
poseThree.setX(1.955);
poseThree.setY(-0.381);
poseThree.setYaw(-1.540);
Pose2ds poseFour = new Pose2ds();
poseFour.setX(3.046);
poseFour.setY(3.219);
poseFour.setYaw(-3.141);
pose2dsNight.add(poseOne);
pose2dsNight.add(poseTwo);
pose2dsNight.add(poseThree);
pose2dsNight.add(poseFour);*/
taskNigth.setPose2ds(pose2dsNight);
//10
@ -557,10 +594,16 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
final String mac = macAddress;
robots.removeIf(v -> v.getMacAddress().equals(mac));
updateTaskStatus(robotNo,taskDetailDO);
taskDetailDO.setRobotNo(robotNo);
taskDetailDO.setStartTime(LocalDateTime.now());
taskDetailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
updateTaskDetail.add(taskDetailDO);
robotNos.add(robotNo);
taskIdSet.add(taskDetailDO.getRobotTaskId());
}
private Pair<String, String> getMadAddressRobotNo(RobotTaskDetailDO taskDetailDO, List<RobotInformationDO> robots,
public Pair<String, String> getMadAddressRobotNo(RobotTaskDetailDO taskDetailDO, List<RobotInformationDO> robots,
WareHouseLocationDO fromLocation, WareHouseLocationDO toLocation) {
String macAddress = "";
String robotNo = taskDetailDO.getRobotNo();
@ -572,7 +615,9 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
.orElse("");
} else {
RobotInformationDO robotInformationDO = robots.stream()
.filter(v -> v.getFloorAreaJson().contains(fromLocation.getAreaId())
.filter(v ->
ObjectUtil.isNotEmpty(v.getMacAddress())
&& v.getFloorAreaJson().contains(fromLocation.getAreaId())
&& v.getFloorAreaJson().contains(toLocation.getAreaId()))
.findFirst()
.orElse(new RobotInformationDO());
@ -585,18 +630,20 @@ public class DistributeTasksServiceImpl implements DistributeTasksService {
@Transactional(rollbackFor = Exception.class)
public void updateTaskStatus(String robotNo, RobotTaskDetailDO taskDetailDO) {
robotInformationMapper.updateRobotStatus(robotNo, RobotStatusEnum.DOING.getType());
RobotTaskDetailDO detailDO = new RobotTaskDetailDO();
detailDO.setId(taskDetailDO.getId());
detailDO.setStartTime(LocalDateTime.now());
detailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
robotTaskDetailMapper.updateRobotDetailById(detailDO);
RobotTaskDO robotTaskDO = new RobotTaskDO();
robotTaskDO.setId(taskDetailDO.getRobotTaskId());
robotTaskDO.setStartTime(LocalDateTime.now());
robotTaskDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
robotTaskMapper.updateRobot(robotTaskDO);
RobotTaskDetailDO detailDO = new RobotTaskDetailDO();
detailDO.setId(taskDetailDO.getId());
detailDO.setStartTime(LocalDateTime.now());
detailDO.setTaskStatus(RobotTaskDetailStatusEnum.DOING.getType());
robotTaskDetailMapper.updateRobotDetailById(detailDO);
robotInformationMapper.updateRobotStatus(robotNo, RobotStatusEnum.DOING.getType());
}

View File

@ -0,0 +1,60 @@
package cn.iocoder.yudao.module.system.service.robot.job;
import java.util.*;
import javax.validation.*;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMovePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMoveSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskAutoMoveDO;
/**
* 机器人自动移库 Service 接口
*
* @author 陈宾顺
*/
public interface RobotTaskAutoMoveService {
/**
* 创建机器人自动移库
*
* @param createReqVO 创建信息
* @return 编号
*/
Long createTaskAutoMove(@Valid RobotTaskAutoMoveSaveReqVO createReqVO);
/**
* 更新机器人自动移库
*
* @param updateReqVO 更新信息
*/
void updateTaskAutoMove(@Valid RobotTaskAutoMoveSaveReqVO updateReqVO);
/**
* 删除机器人自动移库
*
* @param id 编号
*/
void deleteTaskAutoMove(Long id);
/**
* 获得机器人自动移库
*
* @param id 编号
* @return 机器人自动移库
*/
RobotTaskAutoMoveDO getTaskAutoMove(Long id);
/**
* 获得机器人自动移库分页
*
* @param pageReqVO 分页查询
* @return 机器人自动移库分页
*/
PageResult<RobotTaskAutoMoveDO> getTaskAutoMovePage(RobotTaskAutoMovePageReqVO pageReqVO);
/**
* 自动移库
*/
void distributeAutoMoveJob();
}

View File

@ -0,0 +1,412 @@
package cn.iocoder.yudao.module.system.service.robot.job;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.mqtt.api.task.RobotTaskApi;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMovePageReqVO;
import cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotTaskAutoMoveSaveReqVO;
import cn.iocoder.yudao.module.system.dal.dataobject.houselocation.WareHouseLocationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotInformationDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskAutoMoveDO;
import cn.iocoder.yudao.module.system.dal.dataobject.robot.RobotTaskDetailDO;
import cn.iocoder.yudao.module.system.dal.mysql.houselocation.WareHouseLocationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.positionmap.PositionMapItemMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotInformationMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskAutoMoveMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskDetailMapper;
import cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskMapper;
import cn.iocoder.yudao.module.system.enums.robot.*;
import com.alibaba.fastjson.JSON;
import com.google.common.collect.Lists;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import org.springframework.validation.annotation.Validated;
import org.springframework.transaction.annotation.Transactional;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.TASK_AUTO_MOVE_NOT_EXISTS;
/**
* 机器人自动移库 Service 实现类
*
* @author 陈宾顺
*/
@Service
@Validated
@Slf4j
public class RobotTaskAutoMoveServiceImpl implements RobotTaskAutoMoveService {
@Resource
private RobotTaskAutoMoveMapper taskAutoMoveMapper;
@Autowired
private RobotInformationMapper robotInformationMapper;
@Autowired
private RobotTaskMapper robotTaskMapper;
@Autowired
private RobotTaskDetailMapper robotTaskDetailMapper;
@Resource
private RobotTaskApi robotTaskApi;
@Resource
private PositionMapItemMapper positionMapItemMapper;
@Resource
private WareHouseLocationMapper locationMapper;
@Autowired
private DistributeTasksService distributeTasksService;
@Value("${zn.lane_auto_move:true}")
private Boolean laneAutoMove;
@Override
public Long createTaskAutoMove(RobotTaskAutoMoveSaveReqVO createReqVO) {
// 插入
RobotTaskAutoMoveDO taskAutoMove = BeanUtils.toBean(createReqVO, RobotTaskAutoMoveDO.class);
taskAutoMoveMapper.insert(taskAutoMove);
// 返回
return taskAutoMove.getId();
}
@Override
public void updateTaskAutoMove(RobotTaskAutoMoveSaveReqVO updateReqVO) {
// 校验存在
validateTaskAutoMoveExists(updateReqVO.getId());
// 更新
RobotTaskAutoMoveDO updateObj = BeanUtils.toBean(updateReqVO, RobotTaskAutoMoveDO.class);
taskAutoMoveMapper.updateById(updateObj);
}
@Override
public void deleteTaskAutoMove(Long id) {
// 校验存在
validateTaskAutoMoveExists(id);
// 删除
taskAutoMoveMapper.deleteById(id);
}
private void validateTaskAutoMoveExists(Long id) {
if (taskAutoMoveMapper.selectById(id) == null) {
throw exception(TASK_AUTO_MOVE_NOT_EXISTS);
}
}
@Override
public RobotTaskAutoMoveDO getTaskAutoMove(Long id) {
return taskAutoMoveMapper.selectById(id);
}
@Override
public PageResult<RobotTaskAutoMoveDO> getTaskAutoMovePage(RobotTaskAutoMovePageReqVO pageReqVO) {
return taskAutoMoveMapper.selectPage(pageReqVO);
}
/**
* 自动移库
*/
@Override
@Transactional(rollbackFor = Exception.class)
public void distributeAutoMoveJob() {
TenantContextHolder.setTenantId(1L);
Pair<List<RobotInformationDO>, List<RobotTaskDetailDO>> robotAndTaskDetails =
distributeTasksService.getRobotAndTaskDetails();
List<RobotInformationDO> robots = robotAndTaskDetails.getLeft();
if (ObjectUtil.isEmpty(robots)) {
log.info("没有空闲的机器人能执行移库任务");
return;
}
List<RobotTaskDetailDO> taskDetailDOS = robotAndTaskDetails.getRight();
if (ObjectUtil.isEmpty(taskDetailDOS)) {
log.info("没有需要自动移库的明细任务");
return;
}
//查询需要移库的普通库位(非线库)
List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> ordinaryPairs = getOrdinaryAutoMoveLocation(taskDetailDOS);
//查询需要移库的库位(线库)
List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> pairs = getLaneAutoMoveLocation(taskDetailDOS);
if (ObjectUtil.isEmpty(ordinaryPairs) && ObjectUtil.isEmpty(pairs)) {
log.info("查不到需要移库的库位");
return;
}
ordinaryPairs.addAll(pairs);
//下发任务
List<RobotTaskAutoMoveDO> robotTaskAutoMoveDOS = allocationRobot(robots, ordinaryPairs);
if (ObjectUtil.isEmpty(robotTaskAutoMoveDOS)) {
log.info("暂无需要下发移库的任务");
return;
}
taskAutoMoveMapper.insert(robotTaskAutoMoveDOS);
Set<String> robotNos = robotTaskAutoMoveDOS.stream().map(RobotTaskAutoMoveDO::getRobotNo).collect(Collectors.toSet());
List<RobotInformationDO> robotInformationDOS = robotInformationMapper.selectByRobotNos(robotNos);
robotInformationDOS.stream().forEach(robotInformationDO -> {
robotInformationDO.setRobotStatus(RobotStatusEnum.DOING.getType());
});
robotInformationMapper.updateBatch(robotInformationDOS);
List<Long> locationIds = new ArrayList<>();
robotTaskAutoMoveDOS.forEach(robotTaskAutoMoveDO -> {
locationIds.add(robotTaskAutoMoveDO.getFromLocationId());
locationIds.add(robotTaskAutoMoveDO.getToLocationId());
});
List<List<Long>> fromPartition = Lists.partition(locationIds, 100);
fromPartition.forEach(list-> {
locationMapper.updateLocationLockList(list,0l,LocationLockEnum.NO.getType());
});
// todo 搬运任务下发给机器人
}
/**
* 查询需要移库的普通库位(非线库)
* @param taskDetailDOS
* @return
*/
private List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> getOrdinaryAutoMoveLocation(List<RobotTaskDetailDO> taskDetailDOS) {
List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> result = new ArrayList<>();
List<RobotTaskDetailDO> details = taskDetailDOS.stream().filter(v ->
(RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(v.getTaskType())
|| RobotTaskTypeEnum.TAKE.getType().equals(v.getTaskType())
|| RobotTaskTypeEnum.RELEASE.getType().equals(v.getTaskType()))
&& ObjectUtil.isEmpty(v.getFromLaneId()))
.collect(Collectors.toList());
if (ObjectUtil.isEmpty(details)) {
log.info("普通库位, 不需要执行移库");
return result;
}
for (RobotTaskDetailDO robotTaskDetailDO : details) {
Set<Long> doingLocationIds = new HashSet<>();
if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLocationId())) {
doingLocationIds.add(robotTaskDetailDO.getFromLocationId());
}
if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getToLocationId())) {
doingLocationIds.add(robotTaskDetailDO.getToLocationId());
}
if (ObjectUtil.isEmpty(doingLocationIds)) {
continue;
}
List<WareHouseLocationDO> locationDOS = locationMapper.selectNeedMoveLocation(doingLocationIds);
if (ObjectUtil.isEmpty(locationDOS)) {
log.info("暂无需要自动移库的库位 :{}" ,robotTaskDetailDO);
continue;
}
boolean enableOrLock = locationDOS.stream().anyMatch(v -> LocationEnableEnum.NO.getType().equals(v.getLocationEnable())
|| LocationLockEnum.NO.getType().equals(v.getLocationLock()));
if (enableOrLock) {
log.info("此库位被锁定或者禁用,无法执行移库 :{}",locationDOS);
//todo 后期加到告警表里面 方便排查问题
continue;
}
Pair<RobotTaskDetailDO, List<WareHouseLocationDO>> pair = Pair.of(robotTaskDetailDO, locationDOS);
result.add(pair);
}
return result;
}
/**
* 下发任务
* @param robots
* @param pairs
*/
@Transactional(rollbackFor = Exception.class)
public List<RobotTaskAutoMoveDO> allocationRobot(List<RobotInformationDO> robots, List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> pairs) {
List<RobotTaskAutoMoveDO> list = new ArrayList<>();
if (ObjectUtil.isEmpty(robots) || ObjectUtil.isEmpty(pairs)) {
return list;
}
//查找空库位
// todo 并且 map_item_id没有处理中的任务
List<WareHouseLocationDO> emptyLocations = locationMapper.selectList(new LambdaQueryWrapperX<WareHouseLocationDO>()
.isNull(WareHouseLocationDO::getLaneId)
.eq(WareHouseLocationDO::getLocationUseStatus, LocationUseStatusEnum.NO.getType())
.eq(WareHouseLocationDO::getLocationEnable, LocationEnableEnum.YES.getType())
.eq(WareHouseLocationDO::getLocationLock, LocationLockEnum.YES.getType())
.orderByDesc(WareHouseLocationDO::getLocationNumber));
if (ObjectUtil.isEmpty(emptyLocations)) {
log.info("查不到空库位,无法执行移库任务");
return list;
}
for (Pair<RobotTaskDetailDO, List<WareHouseLocationDO>> pair : pairs) {
RobotTaskDetailDO detailDO = pair.getLeft();
for (WareHouseLocationDO wareHouseLocationDO : pair.getRight()) {
if (ObjectUtil.isEmpty(robots) || ObjectUtil.isEmpty(emptyLocations)) {
return list;
}
// 校验机器人工作区域
RobotInformationDO robotInformationDO = robots.stream()
.filter(v ->
ObjectUtil.isNotEmpty(v.getMacAddress())
&& v.getFloorAreaJson().contains(wareHouseLocationDO.getAreaId())
&& v.getFloorAreaJson().contains(emptyLocations.get(0).getAreaId()))
.findFirst()
.orElse(new RobotInformationDO());
if (ObjectUtil.isEmpty(robotInformationDO) || ObjectUtil.isEmpty(robotInformationDO.getRobotNo())) {
continue;
}
RobotTaskAutoMoveDO autoMoveDO = new RobotTaskAutoMoveDO();
autoMoveDO.setRobotTaskDetailId(detailDO.getId());
autoMoveDO.setRobotTaskId(detailDO.getRobotTaskId());
autoMoveDO.setFromLocationId(wareHouseLocationDO.getId());
autoMoveDO.setFromLocationNo(wareHouseLocationDO.getLocationNo());
autoMoveDO.setToLocationId(emptyLocations.get(0).getId());
autoMoveDO.setToLocationNo(emptyLocations.get(0).getLocationNo());
autoMoveDO.setFromLaneId(wareHouseLocationDO.getLaneId());
autoMoveDO.setTaskStatus(AutoMoveTaskStatusEnum.DOING.getType());
autoMoveDO.setPriority(wareHouseLocationDO.getLocationNumber());
autoMoveDO.setRobotNo(robotInformationDO.getRobotNo());
autoMoveDO.setTaskType(AutoMoveTaskTypeEnum.AUTO_MOVE.getType());
autoMoveDO.setMoveType(AutoMoveTypeEnum.GO.getType());
autoMoveDO.setStartTime(LocalDateTime.now());
list.add(autoMoveDO);
robots.removeIf(v -> v.getRobotNo().equals(autoMoveDO.getRobotNo()));
emptyLocations.removeIf(v -> v.getId().equals(autoMoveDO.getToLocationId()));
}
}
return list;
}
/**
* 查询需要移库的库位(线库)
* @param taskDetailDOS
* @return
*/
public List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> getLaneAutoMoveLocation(List<RobotTaskDetailDO> taskDetailDOS) {
List<Pair<RobotTaskDetailDO, List<WareHouseLocationDO>>> result = new ArrayList<>();
if (ObjectUtil.isEmpty(taskDetailDOS) || !laneAutoMove) {
log.info("没有线库的任务明细, 不需要执行线库移库");
return result;
}
//此线库不能有移动过来的任务
List<RobotTaskDetailDO> doingTaskDetail = robotTaskDetailMapper.selectList(new LambdaQueryWrapperX<RobotTaskDetailDO>()
.eq(RobotTaskDetailDO::getTaskStatus, (RobotTaskStatusEnum.DOING.getType()))
.in(RobotTaskDetailDO::getTaskType, RobotTaskTypeEnum.TAKE_RELEASE.getType(), RobotTaskTypeEnum.TAKE.getType()));
Set<Long> doingTaskDetailLaneIds = new HashSet<>();
if (ObjectUtil.isNotEmpty(doingTaskDetail)) {
for (RobotTaskDetailDO robotTaskDetailDO : doingTaskDetail) {
if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getFromLaneId())) {
doingTaskDetailLaneIds.add(robotTaskDetailDO.getFromLaneId());
}
if (ObjectUtil.isNotEmpty(robotTaskDetailDO.getToLaneId())) {
doingTaskDetailLaneIds.add(robotTaskDetailDO.getToLaneId());
}
}
}
//自动移库的任务
List<RobotTaskAutoMoveDO> robotTaskAutoMoveDOS = taskAutoMoveMapper.selectList(new LambdaQueryWrapperX<RobotTaskAutoMoveDO>()
.eq(RobotTaskAutoMoveDO::getTaskStatus, RobotTaskStatusEnum.DOING.getType()));
Set<Long> doingAutoMoveLaneIds = new HashSet<>();
Set<Long> doingDetailIds = new HashSet<>();
if (ObjectUtil.isNotEmpty(robotTaskAutoMoveDOS)) {
robotTaskAutoMoveDOS.forEach(robotTaskAutoMoveDO -> {
if (ObjectUtil.isNotEmpty(robotTaskAutoMoveDO.getFromLaneId())) {
doingAutoMoveLaneIds.add(robotTaskAutoMoveDO.getFromLaneId());
}
if (ObjectUtil.isNotEmpty(robotTaskAutoMoveDO.getRobotTaskDetailId())) {
doingDetailIds.add(robotTaskAutoMoveDO.getRobotTaskDetailId());
}
});
}
//只有库位为线库且任务类型为取放货和仅取货的需要移库
List<RobotTaskDetailDO> details = taskDetailDOS.stream().filter(v ->
(RobotTaskTypeEnum.TAKE_RELEASE.getType().equals(v.getTaskType())
|| RobotTaskTypeEnum.TAKE.getType().equals(v.getTaskType()))
&& ObjectUtil.isNotEmpty(v.getFromLaneId())
&& (/*ObjectUtil.isNotEmpty(doingAutoMoveLaneIds) &&*/ !doingAutoMoveLaneIds.contains(v.getFromLaneId()))
&& (/*ObjectUtil.isNotEmpty(doingDetailIds) &&*/ !doingDetailIds.contains(v.getId()))
&& (/*ObjectUtil.isNotEmpty(doingTaskDetailLaneIds) &&*/ !doingTaskDetailLaneIds.contains(v.getFromLaneId())))
.collect(Collectors.toList());
if (ObjectUtil.isEmpty(details)) {
log.info("没有线库的任务, 不需要执行线库移库");
return result;
}
Map<Long, List<RobotTaskDetailDO>> detailMaps =
details.stream().collect(Collectors.groupingBy(RobotTaskDetailDO::getFromLaneId));
//查找每一个线库最小的一个库位
for (Map.Entry<Long, List<RobotTaskDetailDO>> detaiMap : detailMaps.entrySet()) {
List<WareHouseLocationDO> locations = new ArrayList<>();
RobotTaskDetailDO robotTaskDetail = detaiMap.getValue()
.stream()
.min(Comparator.comparing(RobotTaskDetailDO::getLocationNumber)).get();
if (ObjectUtil.isNotEmpty(robotTaskDetail) && ObjectUtil.isNotEmpty(robotTaskDetail.getLocationNumber())) {
WareHouseLocationDO location = WareHouseLocationDO.builder().locationNumber(robotTaskDetail.getLocationNumber())
.locationUseStatus(LocationUseStatusEnum.YES.getType())
.locationLock(LocationLockEnum.YES.getType())
.laneId(detaiMap.getKey()).build();
locations.add(location);
}
log.info("查询是否需要执行移库任务的线库id和对应的排序位置 :{}", JSON.toJSONString(locations));
if (ObjectUtil.isNotEmpty(locations)) {
List<WareHouseLocationDO> wareHouseLocationDOS = locationMapper.selectLocationByList(locations);
if (ObjectUtil.isNotEmpty(wareHouseLocationDOS)) {
Pair<RobotTaskDetailDO, List<WareHouseLocationDO>> pair = Pair.of(robotTaskDetail, wareHouseLocationDOS);
result.add(pair);
}
}
}
return result;
}
}

View File

@ -225,4 +225,5 @@ zn:
scan_height: 0.4 #扫描高度
parm: 5000 #等待时间
lift_height: 0.1 #抬高托盘高度
move_height: 0.1 #行走高度
move_height: 0.1 #行走高度
lane_auto_move: true #线库是否自动移库 true:线库执行自动移库 、false线库关闭执行自动移库

View File

@ -481,26 +481,13 @@
where id = #{id}
</update>
<update id="updateLocationLockStatus">
update
ware_house_location
<set>
<if test="taskId != null">
task_id = #{taskId},
</if>
<if test="locationLock != null">
location_lock = #{locationLock},
</if>
</set>
where
id = #{id}
</update>
<update id="updateLocationLockList">
update
ware_house_location
set
location_lock = '0',
location_lock = #{locationLock},
task_id = #{taskId}
where
id in
@ -690,4 +677,84 @@
</choose>
</select>
<select id="selectLocationByList" resultMap="BaseResultMap">
select
<include refid="base_sql"></include>
from
ware_house_location
<where>
<foreach collection="locations" item="item" open="(" close=")"
separator=",">
1=1
<if test="item.laneId != null">
and lane_id = #{item.laneId}
</if>
<if test="item.locationNumber != null">
and location_number &lt; #{item.locationNumber}
</if>
<if test="item.locationLock != null">
and location_lock = #{item.locationLock}
</if>
<if test="item.locationUseStatus != null">
and location_use_status = #{item.locationUseStatus}
</if>
<if test="1==1">
and deleted = '0'
</if>
</foreach>
</where>
order by location_number asc
</select>
<select id="selectNeedMoveLocation" resultMap="BaseResultMap">
select
t2.id,
t2.lane_id,
t2.lane_name,
t2.area_id,
t2.area_name,
t2.location_no,
t2.location_yaw,
t2.group_name,
t2.sku_info,
t2.sku_batch,
t2.sku_number,
t2.tray_info,
t2.location_enable,
t2.location_lock,
t2.location_use_status,
t2.location_x,
t2.location_y,
t2.location_wide,
t2.location_deep,
t2.location_height,
t2.location_default_height,
t2.location_total_height,
t2.location_tray_height,
t2.location_storey,
t2.location_type,
t2.location_number,
t2.map_id,
t2.map_item_id
from
ware_house_location t1, ware_house_location t2
WHERE
t1.map_item_id = t2.map_item_id
and t1.id in
<foreach collection="locationIds" item="id" index="index" open="(" close=")"
separator=",">
#{id}
</foreach>
and t2.location_number &lt; t1.location_number
and t2.location_use_status = '1'
and t2.id not in
<foreach collection="locationIds" item="id" index="index" open="(" close=")"
separator=",">
#{id}
</foreach>
order by t2.location_number asc
</select>
</mapper>

View File

@ -251,6 +251,19 @@
robot_no = #{robotNo}
</update>
<update id="updateRobotTaskModel">
update
robot_information
set
robot_task_model = #{robotTaskModel}
where
robot_no in
<foreach collection="robotNos" item="robotNo" index="index" open="(" close=")"
separator=",">
#{robotNo}
</foreach>
</update>
<!--通过主键删除-->
<delete id="deleteById">
delete
@ -258,17 +271,6 @@
where id = #{id}
</delete>
<select id="selectFreeRobot" resultMap="BaseResultMap">
select
<include refid="base_sql"></include>
from
robot_information
where
robot_task_model = '1'
and deleted = '0'
and robot_status = '3'
order by update_time asc
</select>
<select id="statisticsInformation"
resultType="cn.iocoder.yudao.module.system.controller.admin.robot.vo.RobotInformationStatisticsVO">

View File

@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.iocoder.yudao.module.system.dal.mysql.robot.RobotTaskAutoMoveMapper">
<!--
一般情况下,尽可能使用 Mapper 进行 CRUD 增删改查即可。
无法满足的场景,例如说多表关联查询,才使用 XML 编写 SQL。
代码生成器暂时只生成 Mapper XML 文件本身,更多推荐 MybatisX 快速开发插件来生成查询。
文档可见https://www.iocoder.cn/MyBatis/x-plugins/
-->
</mapper>

View File

@ -13,6 +13,9 @@
<result property="takeId" column="take_id" jdbcType="INTEGER"/>
<result property="fromLocationNo" column="from_location_no" jdbcType="VARCHAR"/>
<result property="fromLocationId" column="from_location_id" jdbcType="INTEGER"/>
<result property="fromLaneId" column="from_lane_id" jdbcType="INTEGER"/>
<result property="toLaneId" column="to_lane_id" jdbcType="INTEGER"/>
<result property="locationNumber" column="location_number" jdbcType="INTEGER"/>
<result property="toLocationNo" column="to_location_no" jdbcType="VARCHAR"/>
<result property="toLocationId" column="to_location_id" jdbcType="INTEGER"/>
<result property="fromLocationStorey" column="from_location_storey" jdbcType="INTEGER"/>
@ -42,6 +45,9 @@
take_id,
from_location_no,
from_location_id,
from_lane_id,
to_lane_id,
location_number
to_location_no,
to_location_id,
robot_no,
@ -360,13 +366,13 @@
<insert id="insertBatchList" >
insert into robot_task_detail(robot_task_id, task_type, release_type, take_type, release_id, take_id,
from_location_no, from_location_id, to_location_no, to_location_id, robot_no,from_location_storey,
to_location_storey,priority)
to_location_storey,priority,from_lane_id,to_lane_id,location_number)
values
<foreach collection="taskDetailList" item="entity" separator=",">
(#{entity.robotTaskId}, #{entity.taskType}, #{entity.releaseType}, #{entity.takeType}, #{entity.releaseId},
#{entity.takeId}, #{entity.fromLocationNo}, #{entity.fromLocationId}, #{entity.toLocationNo},
#{entity.toLocationId}, #{entity.robotNo}, #{entity.fromLocationStorey}, #{entity.toLocationStorey}
, #{entity.priority})
, #{entity.priority}, #{entity.fromLaneId}, #{entity.toLaneId}, #{entity.locationNumber})
</foreach>
</insert>