package com.zy.asrs.service.impl;
|
|
import com.alibaba.excel.util.StringUtils;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.mapper.EntityWrapper;
|
import com.zy.asrs.entity.*;
|
import com.zy.asrs.entity.mes.TransArrivalStation;
|
import com.zy.asrs.entity.mes.TransParent;
|
import com.zy.asrs.entity.rcs.*;
|
import com.zy.asrs.enums.RcsRetMethodEnum;
|
import com.zy.asrs.mapper.BlockStationMapper;
|
import com.zy.asrs.mapper.BlockTaskMapper;
|
import com.zy.asrs.service.*;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.stereotype.Service;
|
|
import javax.annotation.Resource;
|
import java.io.*;
|
import java.net.ConnectException;
|
import java.net.SocketTimeoutException;
|
import java.net.URL;
|
import java.net.URLConnection;
|
import java.nio.charset.StandardCharsets;
|
import java.util.ArrayList;
|
import java.util.Date;
|
import java.util.List;
|
import java.util.Objects;
|
import java.util.regex.Matcher;
|
import java.util.regex.Pattern;
|
|
@Slf4j
|
@Service
|
public class RcsServiceImpl implements RcsService {
|
|
// 海康RCS地址
|
@Value("${hik.url}")
|
private String HIK_URL;
|
// 华晓RCS地址
|
@Value("${hx.url}")
|
private String HX_URL;
|
@Value("${mes.defaultUserId}")
|
public long defaultUserId;
|
|
|
@Resource
|
private MesService mesService;
|
@Resource
|
private TaskService taskService;
|
@Resource
|
private BlockStationMapper blockStationMapper;
|
@Resource
|
private BlockTaskMapper blockTaskMapper;
|
@Resource
|
private TaskDetlServiceImpl taskDetlService;
|
@Resource
|
private WrkMastService wrkMastService;
|
|
|
// region 封锁区逻辑,目前只有一个大封锁区,任务全部转到滑块库处理,或直接写到滑块库
|
|
/**
|
* 申请封锁区请求
|
*
|
* @param apply
|
* @return
|
*/
|
private int applyBlock(RcsReporterEqpt apply) {
|
|
BlockTask blockTask = new BlockTask();
|
blockTask.setTaskCode(apply.getTaskCode());
|
blockTask.setApplyTime(new Date());
|
blockTask.setBlockNo(apply.getEqptCode());
|
blockTask.setBlockName(apply.getEqptName());
|
blockTask.setMethod(apply.getMethod());
|
blockTask.setCompleted(0);
|
|
return blockTaskMapper.insert(blockTask);
|
}
|
|
/**
|
* 管理封锁区进入
|
* TODO:增加锁防冲突,可能为分布式锁,定期5秒循环调用
|
*
|
*/
|
public void managerBlock() {
|
|
try {
|
BlockTask firstTask = blockTaskMapper.findTop();
|
if (firstTask == null) {
|
return;
|
}
|
EntityWrapper<BlockStation> wrapper = new EntityWrapper<>();
|
wrapper.eq("block_no", firstTask.getBlockNo());
|
List<BlockStation> stations = blockStationMapper.selectList(wrapper);
|
if (!stations.isEmpty()) {
|
boolean locked = false;
|
for (BlockStation station : stations) {
|
// 只允许1个厂家设备进入封锁区,status状态:0 空闲;1 海康封锁中;2 华晓封锁中;-1 异常;
|
if (station.getStatus() > 0 && !station.getStatus().equals(firstTask.getAgvFactory())) {
|
locked = true;
|
break;
|
}
|
}
|
|
if (!locked) {
|
// 封锁状态
|
int success = blockStationMapper.addByBlockNo(firstTask.getBlockNo(), firstTask.getAgvFactory());
|
if (success > 0) {
|
// 通知RCS
|
RcsEqptNotify notify = new RcsEqptNotify();
|
notify.setEqptCode(firstTask.getBlockNo());
|
notify.setTaskCode(firstTask.getTaskCode());
|
notify.setActionStatus("1");
|
notifyEqpt(notify, firstTask.getAgvFactory());
|
}
|
}
|
}
|
} catch (Exception e) {
|
log.error("管理封锁区异常", e);
|
}
|
}
|
|
/**
|
* 离开释放封锁区请求
|
* TODO:增加锁防冲突,可能为分布式锁
|
*
|
* @param apply
|
* @return
|
*/
|
private int releaseBlock(RcsReporterEqpt apply) {
|
|
BlockTask task = blockTaskMapper.findByTaskCode(apply.getTaskCode());
|
|
EntityWrapper<BlockStation> wrapper = new EntityWrapper<>();
|
wrapper.eq("block_no", task.getBlockNo());
|
List<BlockStation> stations = blockStationMapper.selectList(wrapper);
|
if (!stations.isEmpty()) {
|
// 先完成任务
|
task.setCompleted(1);
|
task.setCompletedTime(new Date());
|
int updateTask = blockTaskMapper.updateById(task);
|
// 再更新封锁区数量
|
for (BlockStation station : stations) {
|
if (station.getAgvNum() - 1 == 0) {
|
station.setStatus(0);
|
}
|
station.setAgvNum(station.getAgvNum() - 1);
|
int updateBlock = blockStationMapper.updateById(station);
|
}
|
}
|
|
return 1;
|
}
|
|
// endregion
|
|
|
// region 海康RCS,AGV
|
|
/**
|
* 2.1.2任务下发接口
|
* 厂家:海量、华晓
|
*
|
* @param rcsTaskSubmit
|
* @param rcsFactory 1 海康;2 华晓;
|
* @return
|
*/
|
public int submitTask(RcsTaskSubmit rcsTaskSubmit, int rcsFactory){
|
|
String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/submit";
|
String response = sendPost(url, rcsTaskSubmit.toString());
|
if (!StringUtils.isEmpty(response) && response.contains("code")){
|
RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class);
|
if("SUCCESS".equals(rcsReturn.getCode())) {
|
JSONObject data = rcsReturn.getData();
|
String robotTaskCode = data.getString("robotTaskCode");
|
if (robotTaskCode.equals(rcsTaskSubmit.getRobotTaskCode())){
|
return 1;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
/**
|
* 2.1.3任务继续执行接口
|
*
|
* @param rcsTaskContinue
|
* @param rcsFactory
|
* @return
|
*/
|
public int continueTask(RcsTaskContinue rcsTaskContinue, int rcsFactory){
|
|
String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/extend/continue";
|
String response = sendPost(url, rcsTaskContinue.toString());
|
if (!StringUtils.isEmpty(response) && response.contains("code")){
|
RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class);
|
if("SUCCESS".equals(rcsReturn.getCode())) {
|
JSONObject data = rcsReturn.getData();
|
String robotTaskCode = data.getString("robotTaskCode");
|
if (robotTaskCode.equals(rcsTaskContinue.getRobotTaskCode())) {
|
return 1;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
/**
|
* 2.1.4任务取消接口
|
*
|
* @param rcsTaskCancel
|
* @param rcsFactory
|
* @return
|
*/
|
public int cancelTask(RcsTaskCancel rcsTaskCancel, int rcsFactory){
|
|
String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/robot/controller/task/cancel";
|
String response = sendPost(url, rcsTaskCancel.toString());
|
if (!StringUtils.isEmpty(response) && response.contains("code")){
|
RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class);
|
if("SUCCESS".equals(rcsReturn.getCode())) {
|
JSONObject data = rcsReturn.getData();
|
String robotTaskCode = data.getString("robotTaskCode");
|
if (robotTaskCode.equals(rcsTaskCancel.getRobotTaskCode())) {
|
return 1;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
/**
|
* 2.1.15外设执行通知接口,通知进入封锁区
|
*
|
* @param rcsEqptNotify
|
* @param rcsFactory
|
* @return
|
*/
|
private int notifyEqpt(RcsEqptNotify rcsEqptNotify, int rcsFactory){
|
|
String url = rcsFactory == 2 ? HIK_URL : HX_URL + "api/wcs/robot/eqpt/notify";
|
String response = sendPost(url, rcsEqptNotify.toString());
|
if (!StringUtils.isEmpty(response) && response.contains("code")){
|
RcsReturn rcsReturn = JSONObject.parseObject(response, RcsReturn.class);
|
if("SUCCESS".equals(rcsReturn.getCode())) {
|
JSONObject data = rcsReturn.getData();
|
String applyCode = data.getString("taskCode"); //申请请求编号,非任务编号
|
if (applyCode.equals(rcsEqptNotify.getTaskCode())) {
|
return 1;
|
}
|
}
|
}
|
|
return 0;
|
}
|
|
/**
|
* 2.2.1任务执行回馈
|
* 厂家:海量、华晓
|
*
|
* @param rcsReporterTask
|
* @return
|
*/
|
public RcsReturn reporterTask(RcsReporterTask rcsReporterTask) {
|
|
RcsReturn rcsReturn = new RcsReturn();
|
|
String robotTaskCode = rcsReporterTask.getRobotTaskCode();
|
String singleRobotCode = rcsReporterTask.getSingleRobotCode();
|
JSONObject values = rcsReporterTask.getExtra().getJSONObject("values");
|
// start : 任务开始;outbin : 走出储位;end : 任务完成
|
String method = values.getString("method");
|
String carrierType = values.getString("carrierType");
|
String slotCategory = values.getString("slotCategory");
|
String slotCode = values.getString("slotCode");
|
|
try {
|
if ("Q3".equals(carrierType) || "Q8".equals(carrierType)) { //AGV
|
EntityWrapper<Task> wrapper = new EntityWrapper<>();
|
wrapper.eq("task_no", robotTaskCode);
|
Task task = taskService.selectOne(wrapper);
|
if (task == null || !task.getTaskNo().equals(robotTaskCode)) {
|
rcsReturn.setCode("Err_RobotCodeNotMatch");
|
rcsReturn.setMessage("");
|
JSONObject data = new JSONObject();
|
data.put("robotTaskCode", robotTaskCode);
|
rcsReturn.setData(data);
|
return rcsReturn;
|
}
|
JSONObject memo = JSONObject.parseObject(task.getMemo());
|
|
switch (Objects.requireNonNull(RcsRetMethodEnum.getEnum(method))) {
|
case TASK_START: {
|
task.setWrkSts(302L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束
|
task.setModiTime(new Date());
|
task.setModiUser(defaultUserId);
|
taskService.updateById(task);
|
} break;
|
case TASK_OUT_BIN: {
|
// TODO:立库出库一托,AGV开始运输后,给MES发送出库完成(一托发一次)
|
JSONObject taskMemo = JSONObject.parseObject(task.getMemo());
|
mesService.outFeedbackByTuo(taskMemo.getString("OrderNo"), task);
|
} break;
|
case TASK_END: {
|
// 更新任务状态等内部逻辑
|
task.setWrkSts(304L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束
|
task.setModiTime(new Date());
|
task.setModiUser(defaultUserId);
|
taskService.updateById(task);
|
// 任务完成
|
// mesService.reporterTask(rcsReporterTask);
|
|
// EntityWrapper<TaskDetl> wapper2 = new EntityWrapper<>();
|
// wapper2.eq("wrk_no", task.getWrkNo())
|
// .eq("matnr", memo.getString("ItemNo"))
|
// .eq("order_no", memo.getString("OrderNo"));
|
// TaskDetl taskDetl = taskDetlService.selectOne(wapper2);
|
// taskDetl.setAnfme()
|
// taskDetlService.updateById();
|
|
// // 301 任务下发、302 任务执行、303 任务中断、304 任务结束
|
// taskService.completeWrkMast();
|
// taskDetlService.
|
|
} break;
|
case APPLY_IN_STATION:
|
case APPLY_OFF_STATION:
|
case ARRIVE_OFF_STATION: {
|
TransParent apply = new TransParent();
|
apply.setTaskno(robotTaskCode);
|
apply.setTaskname(memo.getString("taskName"));
|
apply.setAgvCode(singleRobotCode);
|
String transType = memo.getString("TransType");
|
apply.setTransType(transType);
|
apply.setProductLineId(memo.getString("ProductLineId"));
|
if(transType.equals("02") || transType.equals("04") || transType.equals("06")) {
|
apply.setStationId(task.getSourceStaNo());
|
} else {
|
apply.setStationId(task.getStaNo());
|
}
|
|
if (RcsRetMethodEnum.APPLY_IN_STATION.getCode().equals(method)) {
|
mesService.applyInStation(apply);
|
} else if (RcsRetMethodEnum.APPLY_OFF_STATION.getCode().equals(method)) {
|
mesService.applyOutStation(apply);
|
} else if (RcsRetMethodEnum.ARRIVE_OFF_STATION.getCode().equals(method)) {
|
mesService.outStation(apply);
|
}
|
} break;
|
case ARRIVE_ON_STATION: {
|
// TODO: 如果产线是运输起点,则不发送到站完成,暂时调试使用lG,未实现判断
|
if (rcsReporterTask.getCurrentSeq() == 0 && task.getSourceStaNo().startsWith("LG")) {
|
break;
|
}
|
|
EntityWrapper<TaskDetl> wapper2 = new EntityWrapper<>();
|
wapper2.eq("wrk_no", task.getWrkNo())
|
.eq("matnr", memo.getString("Itemno"))
|
.eq("order_no", memo.getString("OrderNo"));
|
TaskDetl taskDetl = taskDetlService.selectOne(wapper2);
|
TransArrivalStation arrivalStation = new TransArrivalStation();
|
arrivalStation.setTaskno(robotTaskCode);
|
arrivalStation.setTaskname(memo.getString("taskName"));
|
arrivalStation.setTuoPanId(taskDetl.getZpallet()); // memo.getString("TuoPanId")
|
arrivalStation.setProductLineId(memo.getString("ProductLineId"));
|
String transType = memo.getString("TransType");
|
arrivalStation.setDaotype(transType);
|
if(transType.equals("02") || transType.equals("04") || transType.equals("06")) {
|
arrivalStation.setStationID(task.getSourceStaNo());
|
} else {
|
arrivalStation.setStationID(task.getStaNo());
|
}
|
arrivalStation.setOrderNo(memo.getString("OrderNo"));
|
arrivalStation.setAgvCode(singleRobotCode);
|
arrivalStation.setItemno(memo.getString("Itemno"));
|
String memo2 = taskDetl.getMemo();
|
List<String> itemBarCode = new ArrayList<>();
|
Matcher matcher = Pattern.compile("\"([^\"]*)\"").matcher(memo2);
|
while (matcher.find()) {
|
itemBarCode.add(matcher.group(1));
|
}
|
arrivalStation.setItemBarcode(itemBarCode);
|
mesService.arriveOnStation(arrivalStation);
|
} break;
|
default: {} break;
|
}
|
} else if ("CTU".equals(carrierType)) { //CTU
|
EntityWrapper<WrkMast> wrapper = new EntityWrapper<>();
|
wrapper.eq("task_no", robotTaskCode);
|
WrkMast task = wrkMastService.selectOne(wrapper);
|
if (task == null || !task.getTaskNo().equals(robotTaskCode)) {
|
rcsReturn.setCode("Err_RobotCodeNotMatch");
|
rcsReturn.setMessage("");
|
JSONObject data = new JSONObject();
|
data.put("robotTaskCode", robotTaskCode);
|
rcsReturn.setData(data);
|
return rcsReturn;
|
}
|
// JSONObject memo = JSONObject.parseObject(task.getMemo());
|
|
switch (Objects.requireNonNull(RcsRetMethodEnum.getEnum(method))) {
|
case TASK_START: {
|
// task.setWrkSts(302L); // 301 任务下发、302 任务执行、303 任务中断、304 任务结束
|
// task.setModiTime(new Date());
|
// task.setModiUser(defaultUserId);
|
// taskService.updateById(task);
|
} break;
|
// case TASK_OUT_BIN: {} break;
|
case TASK_END: {
|
// 更新任务状态等内部逻辑
|
long wrkSts = task.getWrkSts(); // 1.入库;101.出库;
|
if (task.getIoType() == 1) {
|
wrkSts = 4L;
|
} else if (task.getIoType() == 101) {
|
wrkSts = 14L;
|
}
|
|
task.setWrkSts(wrkSts); // 4.入库完成;14.已出库未确认;
|
task.setModiTime(new Date());
|
task.setModiUser(defaultUserId);
|
wrkMastService.updateById(task);
|
|
// TODO:任务完成触发出入库变更操作
|
|
|
// // 入库完成
|
// mesService.inFeedback(memo.getString("OrderNo"));
|
// // 出库完成
|
// mesService.outFeedback(memo.getString("OrderNo"));
|
} break;
|
default: {} break;
|
}
|
}
|
|
// 返回RCS
|
rcsReturn.setCode("SUCCESS");
|
rcsReturn.setMessage("");
|
JSONObject data = new JSONObject();
|
data.put("robotTaskCode", robotTaskCode);
|
rcsReturn.setData(data);
|
} catch (Exception e) {
|
log.error("RCS反馈任务进度处理异常 - {}", rcsReporterTask, e);
|
rcsReturn.setCode("Err_Internal");
|
rcsReturn.setMessage("内部处理异常");
|
JSONObject data = new JSONObject();
|
data.put("robotTaskCode", robotTaskCode);
|
rcsReturn.setData(data);
|
}
|
|
return rcsReturn;
|
}
|
|
/**
|
* 2.2.4请求外设接口(请求封锁区)
|
* 厂家:海量、华晓
|
*
|
* @param rcsReporterEqpt
|
* @return
|
*/
|
public RcsReturn reporterEqpt(RcsReporterEqpt rcsReporterEqpt){
|
|
int success = 0;
|
if ("APPLY_LOCK".equals(rcsReporterEqpt.getMethod())) { //申请
|
success = applyBlock(rcsReporterEqpt);
|
} else if ("RELEASE_EQPT".equals(rcsReporterEqpt.getMethod())) { //释放
|
success = releaseBlock(rcsReporterEqpt);
|
}
|
|
// 返回RCS
|
RcsReturn rcsReturn = new RcsReturn();
|
rcsReturn.setCode(success > 0 ? "SUCCESS" : "Err_Internal");
|
rcsReturn.setMessage(success > 0 ? "" : "内部错误");
|
JSONObject data = new JSONObject();
|
data.put("extra", null);
|
rcsReturn.setData(data);
|
|
return rcsReturn;
|
}
|
|
// endregion
|
|
|
// region 海康CTU 刀具库
|
|
// TODO: CTU上层组参引用,
|
|
// 2.1.2任务下发接口
|
|
// 2.1.3任务继续执行接口
|
|
// 2.1.4任务取消接口
|
|
// 2.2.1任务执行回馈
|
|
//// @Transactional(rollbackFor = Exception.class)
|
// public void receiveTaskStatus(RcsReporterTask callbackParam, String method, String stockType, Long hostId) {
|
//
|
// JSONObject values = callbackParam.getExtra().getJSONObject("values");
|
// EntityWrapper<Task> wapper = new EntityWrapper<>();
|
// wapper.eq("task_no", callbackParam.getRobotTaskCode());
|
// Task task = taskService.selectOne(wapper);
|
// if (task == null && !StringUtils.isEmpty(task.getWrkNo())) {
|
// if (1 == task.getIoType()) { // 入库
|
// // 更新库存
|
//
|
// // 更新任务状态
|
// } else if (101 == task.getIoType()) { // 出库
|
// // 更新库存
|
//
|
// // 更新任务状态
|
//
|
// // 货物和托盘解绑
|
// }
|
// }
|
// }
|
|
// endregion
|
|
|
// region 华晓RCS
|
|
/**
|
* 9.7申请进入生产线
|
*
|
* @param apply
|
* @return
|
*/
|
public JSONObject hxApplyInLine(TransParent apply) {
|
|
String status = mesService.applyInLine(apply);
|
JSONObject result = new JSONObject();
|
result.put("Success", 1);
|
result.put("Message", status);
|
JSONObject data = new JSONObject();
|
data.put("status", status);
|
result.put("Data", data);
|
|
return result;
|
}
|
|
// endregion
|
|
// region httpUtil
|
|
/**
|
* 向指定 URL 发送POST方法的请求
|
*
|
* @param url 发送请求的 URL
|
* @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
|
* @return 所代表远程资源的响应结果
|
*/
|
public static String sendPost(String url, String param) {
|
PrintWriter out = null;
|
BufferedReader in = null;
|
StringBuilder result = new StringBuilder();
|
try
|
{
|
log.info("sendPost - {} - {}", url, param);
|
URL realUrl = new URL(url);
|
URLConnection conn = realUrl.openConnection();
|
conn.setRequestProperty("accept", "*/*");
|
conn.setRequestProperty("connection", "Keep-Alive");
|
conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
|
conn.setRequestProperty("Accept-Charset", "utf-8");
|
conn.setRequestProperty("Content-Type", "application/json;charset=utf-8");
|
conn.setConnectTimeout(5000);
|
conn.setReadTimeout(5000);
|
conn.setDoOutput(true);
|
conn.setDoInput(true);
|
out = new PrintWriter(conn.getOutputStream());
|
out.print(param);
|
out.flush();
|
in = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
String line;
|
while ((line = in.readLine()) != null)
|
{
|
result.append(line);
|
}
|
log.info("recv - {}", result);
|
}
|
catch (ConnectException e)
|
{
|
log.error("调用HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
|
}
|
catch (SocketTimeoutException e)
|
{
|
log.error("调用HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
|
}
|
catch (IOException e)
|
{
|
log.error("调用HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
|
}
|
catch (Exception e)
|
{
|
log.error("调用HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
|
}
|
finally
|
{
|
try
|
{
|
if (out != null)
|
{
|
out.close();
|
}
|
if (in != null)
|
{
|
in.close();
|
}
|
}
|
catch (IOException ex)
|
{
|
log.error("调用in.close Exception, url=" + url + ",param=" + param, ex);
|
}
|
}
|
return result.toString();
|
}
|
|
// endregion
|
}
|