package com.zy.asrs.wcs.core.service.impl;
|
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.zy.asrs.framework.common.Cools;
|
import com.zy.asrs.framework.common.SnowflakeIdWorker;
|
import com.zy.asrs.wcs.core.entity.*;
|
import com.zy.asrs.wcs.core.kernel.AnalyzeService;
|
import com.zy.asrs.wcs.core.model.enums.DeviceCtgType;
|
import com.zy.asrs.wcs.core.model.enums.MotionStsType;
|
import com.zy.asrs.wcs.core.model.enums.TaskStsType;
|
import com.zy.asrs.wcs.core.service.*;
|
import com.zy.asrs.wcs.core.utils.ShuttleDispatcher;
|
import com.zy.asrs.wcs.core.utils.Utils;
|
import com.zy.asrs.wcs.rcs.News;
|
import com.zy.asrs.wcs.rcs.cache.SlaveConnection;
|
import com.zy.asrs.wcs.rcs.entity.Device;
|
import com.zy.asrs.wcs.rcs.entity.DeviceType;
|
import com.zy.asrs.wcs.rcs.model.enums.ShuttleProtocolStatusType;
|
import com.zy.asrs.wcs.rcs.model.enums.SlaveType;
|
import com.zy.asrs.wcs.rcs.model.protocol.ShuttleProtocol;
|
import com.zy.asrs.wcs.rcs.model.protocol.StaProtocol;
|
import com.zy.asrs.wcs.rcs.service.DeviceService;
|
import com.zy.asrs.wcs.rcs.service.DeviceTypeService;
|
import com.zy.asrs.wcs.rcs.thread.DevpThread;
|
import com.zy.asrs.wcs.rcs.thread.ShuttleThread;
|
import com.zy.asrs.wcs.system.entity.Dict;
|
import com.zy.asrs.wcs.system.service.DictService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
|
import java.util.ArrayList;
|
import java.util.Date;
|
import java.util.List;
|
|
/**
|
* 立体仓库WCS系统主流程业务
|
* Created by vincent on 2020/8/6
|
*/
|
@Slf4j
|
@Service("mainService")
|
@Transactional
|
public class MainServiceImpl {
|
|
@Autowired
|
private TaskService taskService;
|
@Autowired
|
private AnalyzeService analyzeService;
|
@Autowired
|
private MotionService motionService;
|
@Autowired
|
private DeviceService deviceService;
|
@Autowired
|
private DeviceTypeService deviceTypeService;
|
@Autowired
|
private LocCtgService locCtgService;
|
@Autowired
|
private LocService locService;
|
@Autowired
|
private SnowflakeIdWorker snowflakeIdWorker;
|
@Autowired
|
private TaskCtgService taskCtgService;
|
@Autowired
|
private DictService dictService;
|
@Autowired
|
private ShuttleDispatcher shuttleDispatcher;
|
|
/**
|
* 组托
|
* 入库站,根据条码扫描生成入库工作档,工作状态 2
|
*/
|
public synchronized void generateInboundWrk() {
|
|
}
|
|
// 解析入库工作档
|
public synchronized void analyzeInBoundTask() {
|
for (Task task : taskService.selectWaitAnalyzeInBoundTask()) {
|
// generate motion list
|
List<Motion> motionList = analyzeService.generateMotion(task);
|
if (motionList.isEmpty()) {
|
continue;
|
}
|
motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
|
|
// 更新工作主档
|
task.setTaskSts(TaskStsType.ANALYZE_INBOUND.sts); // 工作状态
|
task.setUpdateTime(new Date());
|
if (!taskService.updateById(task)) {
|
News.error("更新工作档失败!!! [工作号:{}]", task.getTaskNo());
|
}
|
}
|
}
|
|
/**
|
* 出库 ====>> 同一时间一台穿梭车只能有一个出库任务
|
*/
|
public synchronized void generateOutboundWrkMast() {
|
List<Task> tasks = taskService.selectPakOut();
|
if (tasks.isEmpty()) {
|
return;
|
}
|
|
for (Task task : tasks) {
|
DevpThread devpThread = (DevpThread) SlaveConnection.get(SlaveType.Devp, 1);
|
StaProtocol staProtocol = devpThread.getStation().get(Integer.parseInt(task.getOriginSite()));//源站
|
StaProtocol staProtocol1 = devpThread.getStation().get(Integer.parseInt(task.getDestSite()));//目标站
|
if (staProtocol == null || staProtocol1 == null) {
|
continue;
|
} else {
|
staProtocol = staProtocol.clone();
|
staProtocol1 = staProtocol1.clone();
|
}
|
|
// // 查询站点详细信息
|
// BasDevp staDetl = basDevpService.selectById(outSta.getStaNo());
|
// if (staDetl == null) {
|
// log.error("出库 ===>> 站点在数据库不存在, 站点编号={}", outSta.getStaNo());
|
// continue;
|
// }
|
// 判断堆垛机出库站状态
|
if (staProtocol.isAutoing() && !staProtocol.isLoading() && staProtocol.getWorkNo() == 0 && staProtocol.isOutEnable()) {
|
|
if (!(staProtocol1.isAutoing() && !staProtocol1.isLoading() && staProtocol1.getWorkNo() == 0 && staProtocol1.isOutEnable())) {
|
continue;
|
}
|
|
// //同库位组校验
|
// List<String> outerLoc = Utils.getGroupOuterLoc(wrkMast.getSourceLocNo());
|
// List<LocMast> outerLocMasts = locMastService.selectNotEmptyLocNos(outerLoc);
|
// if (!outerLocMasts.isEmpty()) {
|
// News.info("{}任务,浅库位存在货物,系统等待中", wrkMast.getWrkNo());
|
// continue;//浅库位存在未执行任务
|
// }
|
|
// generate motion list
|
List<Motion> motionList = analyzeService.generateMotion(task);
|
if (Cools.isEmpty(motionList)) {
|
log.error("出库 ===>> 暂时没有空闲小车, 任务号={}", task.getTaskNo());
|
continue;
|
}
|
motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
|
|
// 更新工作主档
|
task.setTaskSts(TaskStsType.ANALYZE_OUTBOUND.sts); // 工作状态
|
task.setUpdateTime(new Date());
|
if (!taskService.updateById(task)) {
|
News.error("更新工作档失败!!! [工作号:{}]", task.getTaskNo());
|
}
|
|
}
|
}
|
}
|
|
/**
|
* 四向穿梭车电量检测 ===>> 发起充电
|
*/
|
public synchronized void loopShuttleCharge() {
|
// 获取充电桩库位类型
|
LocCtg locCtg = locCtgService.getOne(new LambdaQueryWrapper<LocCtg>()
|
.eq(LocCtg::getFlag, "CHARGE")
|
.eq(LocCtg::getStatus, 1));
|
if (locCtg == null) {
|
return;
|
}
|
|
//获取充电任务类型
|
TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>()
|
.eq(TaskCtg::getFlag, "CHARGE")
|
.eq(TaskCtg::getStatus, 1));
|
if (taskCtg == null) {
|
return;
|
}
|
|
DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper<DeviceType>()
|
.eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle))
|
.eq(DeviceType::getStatus, 1));
|
if (deviceType == null) {
|
return;
|
}
|
|
List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
|
.eq(Device::getDeviceType, deviceType.getId())
|
.eq(Device::getStatus, 1));
|
for (Device device : list) {
|
//获取四向穿梭车线程
|
ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue());
|
if (shuttleThread == null) {
|
continue;
|
}
|
|
ShuttleProtocol shuttleProtocol = shuttleThread.getStatus();
|
if (shuttleProtocol == null) {
|
continue;
|
}
|
|
if (!shuttleProtocol.getProtocolStatusType().equals(ShuttleProtocolStatusType.IDLE)) {
|
continue;
|
}
|
|
String currentLocNo = shuttleProtocol.getCurrentLocNo();
|
int lev = Utils.getLev(currentLocNo);//获取小车楼层
|
//搜索小车当前楼层充电桩
|
ArrayList<Loc> allChargeLoc = new ArrayList<>();
|
List<Loc> list1 = locService.list(new LambdaQueryWrapper<Loc>()
|
.eq(Loc::getLocCtg, locCtg.getId())
|
.eq(Loc::getStatus, 1)
|
.eq(Loc::getLev, lev));
|
if (!list1.isEmpty()) {
|
allChargeLoc.addAll(list1);
|
}
|
|
//搜索其他楼层充电桩
|
List<Loc> list2 = locService.list(new LambdaQueryWrapper<Loc>()
|
.eq(Loc::getLocCtg, locCtg.getId())
|
.eq(Loc::getStatus, 1)
|
.notIn(Loc::getLev, lev));
|
if (!list2.isEmpty()) {
|
allChargeLoc.addAll(list2);
|
}
|
|
//没有找到充电桩
|
if (allChargeLoc.isEmpty()) {
|
continue;
|
}
|
|
//选择空闲充电桩
|
Loc chargeLoc = null;
|
for (Loc loc : allChargeLoc) {
|
// 判断充电位是否被占用(车辆位置)
|
if (Utils.hasShuttleInLoc(loc.getLocNo(), device.getId())) {
|
continue;
|
}
|
|
// 盘点充电位是否存在任务档
|
List<Task> tasks = taskService.hasChargeInLoc(loc.getLocNo());
|
if (!tasks.isEmpty()) {
|
continue;
|
}
|
|
chargeLoc = loc;
|
break;
|
}
|
|
if (chargeLoc == null) {
|
continue;//未找到充电桩
|
}
|
|
if (motionService.count(new LambdaQueryWrapper<Motion>()
|
.eq(Motion::getDeviceCtg, DeviceCtgType.SHUTTLE.val())
|
.eq(Motion::getDevice, device.getDeviceNo())
|
.eq(Motion::getMotionSts, MotionStsType.EXECUTING.val())) > 0) {
|
continue;
|
}
|
|
//判断当前小车是否满足需要充电要求
|
if (!shuttleThread.isRequireCharge()) {
|
continue;
|
}
|
|
Task taskCharge = taskService.selectChargeWorking(Integer.valueOf(device.getDeviceNo()));
|
if (taskCharge != null) {//已有充电任务
|
continue;
|
}
|
|
String chargeLocNo = chargeLoc.getLocNo();
|
Task task = new Task();
|
task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
|
task.setTaskNo(String.valueOf(Utils.getTaskNo("CHARGE")));
|
task.setTaskSts(TaskStsType.NEW_CHARGE.sts);
|
task.setTaskCtg(taskCtg.getId());
|
task.setPriority(10);
|
task.setOriginSite(null);
|
task.setOriginLoc(null);
|
task.setDestSite(null);
|
task.setDestLoc(chargeLocNo);
|
task.setIoTime(new Date());
|
task.setStartTime(new Date());
|
task.setHostId(device.getHostId());
|
task.setStatus(1);
|
task.setMemo("charge");
|
task.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
|
|
// generate motion list
|
List<Motion> motionList = analyzeService.generateChargeMotion(task);
|
if (Cools.isEmpty(motionList)) {
|
News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
|
continue;
|
}
|
motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
|
|
task.setTaskSts(TaskStsType.ANALYZE_CHARGE.sts);
|
if (!taskService.save(task)) {
|
News.error("保存{}号四向穿梭车充电任务失败!!!", device.getDeviceNo());
|
continue;
|
}
|
|
News.info("保存{}号四向穿梭车充电任务成功!!!", device.getDeviceNo());
|
}
|
}
|
|
/**
|
* 四向穿梭车电量检测 ===>> 满电后回到待机位
|
*/
|
public synchronized void loopShuttleToStandbyCauseCharge() {
|
Integer enoughPower = 90;
|
Dict dict = dictService.getOne(new LambdaQueryWrapper<Dict>()
|
.eq(Dict::getFlag, "chargeMaxValue")
|
.eq(Dict::getStatus, 1));
|
if (dict != null) {
|
enoughPower = Integer.parseInt(dict.getValue());
|
}
|
|
//获取迁移任务类型
|
TaskCtg taskCtg = taskCtgService.getOne(new LambdaQueryWrapper<TaskCtg>()
|
.eq(TaskCtg::getFlag, "MOVE")
|
.eq(TaskCtg::getStatus, 1));
|
if (taskCtg == null) {
|
return;
|
}
|
|
DeviceType deviceType = deviceTypeService.getOne(new LambdaQueryWrapper<DeviceType>()
|
.eq(DeviceType::getFlag, String.valueOf(SlaveType.Shuttle))
|
.eq(DeviceType::getStatus, 1));
|
if (deviceType == null) {
|
return;
|
}
|
|
List<Device> list = deviceService.list(new LambdaQueryWrapper<Device>()
|
.eq(Device::getDeviceType, deviceType.getId())
|
.eq(Device::getStatus, 1));
|
for (Device device : list) {
|
//获取四向穿梭车线程
|
ShuttleThread shuttleThread = (ShuttleThread) SlaveConnection.get(SlaveType.Shuttle, device.getId().intValue());
|
if (shuttleThread == null) {
|
continue;
|
}
|
|
if (!shuttleThread.isCharging()) {
|
continue;
|
}
|
|
if (!shuttleThread.isChargingCompleted()) {
|
continue;
|
}
|
|
//查找充电任务
|
Task chargeTask = taskService.getOne(new LambdaQueryWrapper<Task>()
|
.eq(Task::getTaskSts, TaskStsType.CHARGE_WORKING.sts)
|
.eq(Task::getShuttleNo, device.getDeviceNo()));
|
if (chargeTask == null) {
|
continue;
|
}
|
|
//充电完成
|
// 已有迁移任务
|
if (taskService.selectMoveWorking(Integer.valueOf(device.getDeviceNo())) != null) {
|
continue;
|
}
|
|
//获取避让位置
|
String standByLocNo = shuttleDispatcher.searchStandByLocNo(Integer.valueOf(device.getDeviceNo()), device.getHostId(), shuttleThread.getStatus().getCurrentLocNo());
|
|
Task task = new Task();
|
task.setUuid(String.valueOf(snowflakeIdWorker.nextId()));
|
task.setTaskNo(String.valueOf(Utils.getTaskNo("MOVE")));
|
task.setTaskSts(TaskStsType.NEW_MOVE.sts);
|
task.setTaskCtg(taskCtg.getId());
|
task.setPriority(10);
|
task.setOriginSite(null);
|
task.setOriginLoc(null);
|
task.setDestSite(null);
|
task.setDestLoc(standByLocNo); // 避让位置
|
task.setIoTime(new Date());
|
task.setStartTime(new Date());
|
task.setHostId(device.getHostId());
|
task.setStatus(1);
|
task.setMemo("charge");
|
task.setShuttleNo(Integer.valueOf(device.getDeviceNo()));
|
|
// generate motion list
|
List<Motion> motionList = analyzeService.generateShuttleChargeWrkComplete(task);
|
if (Cools.isEmpty(motionList)) {
|
News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo());
|
continue;
|
}
|
motionService.batchInsert(motionList, task.getUuid(), Integer.valueOf(task.getTaskNo()));
|
|
task.setTaskSts(TaskStsType.ANALYZE_MOVE.sts);
|
|
if (!taskService.save(task)) {
|
News.error("保存{}号四向穿梭车迁移任务失败!!!", device.getDeviceNo());
|
continue;
|
}
|
|
chargeTask.setTaskSts(TaskStsType.COMPLETE_CHARGE.sts);
|
chargeTask.setIoTime(new Date());
|
taskService.updateById(chargeTask);
|
}
|
}
|
|
}
|