package com.vincent.rsf.openApi.service.impl;
|
|
import com.alibaba.fastjson.JSONArray;
|
import com.alibaba.fastjson.JSONObject;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.fasterxml.jackson.core.JsonProcessingException;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.cfg.CoercionAction;
|
import com.fasterxml.jackson.databind.cfg.CoercionInputShape;
|
import com.vincent.rsf.framework.common.R;
|
import com.vincent.rsf.framework.exception.CoolException;
|
import com.vincent.rsf.openApi.config.PlatformProperties;
|
import com.vincent.rsf.openApi.entity.Loc;
|
import com.vincent.rsf.openApi.entity.constant.WmsConstant;
|
import com.vincent.rsf.openApi.entity.dto.CommonResponse;
|
import com.vincent.rsf.openApi.entity.constant.RcsConstant;
|
import com.vincent.rsf.openApi.entity.dto.SyncLocsDto;
|
import com.vincent.rsf.openApi.entity.params.ExMsgCallbackParams;
|
import com.vincent.rsf.openApi.entity.params.LocSiteParams;
|
import com.vincent.rsf.openApi.entity.params.RcsPubTaskParams;
|
import com.vincent.rsf.openApi.entity.params.SyncRcsLocsParam;
|
import com.vincent.rsf.openApi.entity.params.TaskReportParams;
|
import com.vincent.rsf.openApi.mapper.LocMapper;
|
import com.vincent.rsf.openApi.service.WmsRcsService;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.http.HttpEntity;
|
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpMethod;
|
import org.springframework.http.ResponseEntity;
|
import org.springframework.stereotype.Service;
|
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.web.client.RestTemplate;
|
|
import java.util.List;
|
import java.util.Map;
|
import java.util.Objects;
|
|
|
@Slf4j
|
@Service("wmsRcsService")
|
public class WmsRcsServiceImpl extends ServiceImpl<LocMapper, Loc> implements WmsRcsService {
|
|
@Autowired
|
private PlatformProperties rcsApi;
|
@Autowired
|
private PlatformProperties.WmsApi wmsApi;
|
@Autowired
|
private RestTemplate restTemplate;
|
|
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 任务下发
|
* @version 1.0
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResponse pubTasks(RcsPubTaskParams params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.pubTask;
|
log.info("========== 开始下发任务到RCS ==========");
|
log.info("RCS请求地址:{}", rcsUrl);
|
if (params != null) {
|
log.info("批次编号:{}", params.getBatchNo());
|
if (params.getTasks() != null) {
|
log.info("任务数量:{}", params.getTasks().size());
|
}
|
}
|
log.info("请求参数:{}", JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
long startTime = System.currentTimeMillis();
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
long endTime = System.currentTimeMillis();
|
log.info("RCS响应耗时:{}ms", (endTime - startTime));
|
log.info("RCS响应状态码:{}", exchange.getStatusCode());
|
log.info("RCS响应头:{}", exchange.getHeaders());
|
log.info("RCS响应体:{}", exchange.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
log.error("========== RCS任务下发失败 ==========");
|
log.error("RCS响应体为空,无法解析响应结果");
|
log.error("请求地址:{}", rcsUrl);
|
log.error("请求参数:{}", JSONObject.toJSONString(params));
|
throw new CoolException("任务下发失败,RCS响应体为空!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
log.info("RCS响应解析结果 - code:{},msg:{},data:{}",
|
result.getCode(), result.getMsg(), result.getData());
|
if (result.getCode() == 200) {
|
log.info("========== RCS任务下发成功 ==========");
|
return result;
|
} else {
|
log.error("========== RCS任务下发失败 ==========");
|
log.error("RCS返回错误 - code:{},msg:{},data:{}",
|
result.getCode(), result.getMsg(), result.getData());
|
return result;
|
}
|
} catch (JsonProcessingException e) {
|
log.error("========== RCS任务下发异常 ==========");
|
log.error("解析RCS响应失败,响应体:{}", exchange.getBody(), e);
|
throw new CoolException("解析RCS响应失败:" + e.getMessage());
|
} catch (Exception e) {
|
log.error("========== RCS任务下发异常 ==========");
|
log.error("任务下发过程中发生异常", e);
|
throw e;
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 取消任务
|
* @version 1.0
|
*/
|
@Override
|
@Transactional(rollbackFor = Exception.class)
|
public CommonResponse cancelTasks(Map<String, Object> params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.cancelTask;
|
log.info("========== 开始取消RCS任务(open-rcs接口) ==========");
|
log.info("RCS取消任务请求地址:{}", rcsUrl);
|
log.info("RCS取消任务请求参数:{}", JSONObject.toJSONString(params));
|
|
// 打印详细的请求参数信息
|
if (params != null) {
|
Object batchNo = params.get("batchNo");
|
Object tasks = params.get("tasks");
|
if (batchNo != null) {
|
log.info("批次编号:{}", batchNo);
|
}
|
if (tasks != null) {
|
if (tasks instanceof List) {
|
log.info("任务数量:{}", ((List<?>) tasks).size());
|
log.info("任务编号列表:{}", tasks);
|
} else {
|
log.info("任务参数:{}", tasks);
|
}
|
}
|
}
|
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
|
long startTime = System.currentTimeMillis();
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
long endTime = System.currentTimeMillis();
|
|
log.info("RCS取消任务响应耗时:{}ms", (endTime - startTime));
|
log.info("RCS取消任务响应状态码:{}", exchange.getStatusCode());
|
log.info("RCS取消任务响应头:{}", exchange.getHeaders());
|
log.info("RCS取消任务响应体:{}", exchange.getBody());
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("取消任务失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
log.info("========== RCS任务取消成功(open-rcs接口) ==========");
|
log.info("成功取消的任务编号:{}", params.get("tasks"));
|
return result;
|
} else {
|
log.error("========== RCS任务取消失败(open-rcs接口) ==========");
|
log.error("RCS返回错误码:{},错误信息:{}", result.getCode(), result.getMsg());
|
throw new CoolException("取消任务失败!!" + (result.getMsg() != null ? ":" + result.getMsg() : ""));
|
}
|
} catch (JsonProcessingException e) {
|
log.error("RCS取消任务响应解析失败:{}", e.getMessage(), e);
|
throw new CoolException("RCS取消任务响应解析失败:" + e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: RCS状态回写
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse callBackEvent(ExMsgCallbackParams params) {
|
// 参数校验
|
if (Objects.isNull(params)) {
|
log.error("RCS回调事件参数为空!");
|
throw new CoolException("参数不能为空!!");
|
}
|
|
// 详细记录接收到的参数
|
log.info("RCS回调事件接收参数 - seqNum: {}, eventType: {}, robotCode: {}, zpallet: {}",
|
params.getSeqNum(), params.getEventType(), params.getRobotCode(), params.getZpallet());
|
|
// 检查关键字段是否为空
|
if (Objects.isNull(params.getSeqNum()) || params.getSeqNum().isEmpty()) {
|
log.warn("RCS回调事件参数seqNum为空!完整参数:{}", JSONObject.toJSONString(params));
|
}
|
if (Objects.isNull(params.getEventType()) || params.getEventType().isEmpty()) {
|
log.warn("RCS回调事件参数eventType为空!完整参数:{}", JSONObject.toJSONString(params));
|
}
|
|
String callUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.callBack;
|
/**WMS基础配置链接*/
|
log.info("任务执行状态上报,请求地址: {}, 请求参数: {}", callUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(callUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("任务执行状态上报,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
return new CommonResponse();
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
return result;
|
} else {
|
return result;
|
// throw new CoolException("任务执行状态上报失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/27
|
* @description: 库位信息同步
|
* @version 1.0
|
*/
|
@Override
|
public List<SyncLocsDto> syncLocs(SyncRcsLocsParam params) {
|
return syncRcsLocs(params);
|
}
|
|
|
/**
|
* @author Ryan
|
* @date 2025/11/10
|
* @description: 修改库位或站点状态
|
* @version 1.0
|
*/
|
@Override
|
public R modifyLocOrSite(LocSiteParams params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.modifystatus;
|
log.info("库位或站点状态修改,请求地址: {}, 请求参数: {}", rcsUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("库位或站点状态修改,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("状态修改失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
return R.ok();
|
} else {
|
throw new CoolException("状态修改失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2025/8/28
|
* @description: 拉取RCS库位,同步至本地
|
* @version 1.0
|
*/
|
@Transactional(rollbackFor = Exception.class)
|
public List<SyncLocsDto> syncRcsLocs(SyncRcsLocsParam params) {
|
/**RCS基础配置链接*/
|
String rcsUrl = rcsApi.getHost() + ":" + rcsApi.getPort() + RcsConstant.syncLocs;
|
log.info("任务下发,请求地址2: {}, 请求参数: {}", rcsUrl , JSONObject.toJSONString(params));
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(params, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(rcsUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("任务下发后,响应结果: {}", exchange);
|
if (Objects.isNull(exchange.getBody())) {
|
throw new CoolException("任务下发失败!!");
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
JSONObject jsonObject = JSONObject.parseObject(exchange.getBody()).getJSONObject("data");
|
List<SyncLocsDto> array = JSONArray.parseArray(jsonObject.getJSONArray("records").toJSONString(), SyncLocsDto.class);
|
log.info("records结果: {}", array);
|
return array;
|
} else {
|
throw new CoolException("任务下发失败!!");
|
}
|
} catch (JsonProcessingException e) {
|
throw new CoolException(e.getMessage());
|
}
|
}
|
}
|
|
/**
|
* @author Ryan
|
* @date 2026/2/3
|
* @description: 任务执行通知上报(RCS回调接口)
|
* @version 1.0
|
*/
|
@Override
|
public CommonResponse reportTask(TaskReportParams params) {
|
log.info("RCS回调,请求参数: {}", JSONObject.toJSONString(params));
|
|
// 参数校验
|
if (Objects.isNull(params)) {
|
throw new CoolException("参数不能为空!!");
|
}
|
if (Objects.isNull(params.getBatchNo()) || params.getBatchNo().isEmpty()) {
|
throw new CoolException("任务批次不能为空!!");
|
}
|
if (Objects.isNull(params.getTaskNo()) || params.getTaskNo().isEmpty()) {
|
throw new CoolException("任务编号不能为空!!");
|
}
|
if (Objects.isNull(params.getTimestamp()) || params.getTimestamp().isEmpty()) {
|
throw new CoolException("时间戳不能为空!!");
|
}
|
|
// 将TaskReportParams转换为ExMsgParams格式(taskNo -> seqNum)
|
// 根据RCS新接口规范,taskNo对应旧接口的seqNum
|
JSONObject exMsgParams = new JSONObject();
|
exMsgParams.put("seqNum", params.getTaskNo()); // taskNo映射到seqNum
|
// eventType设置为END,表示任务完成(根据业务需求可能需要调整)
|
exMsgParams.put("eventType", "END");
|
exMsgParams.put("robotCode", null);
|
exMsgParams.put("zpallet", null);
|
|
// 将任务上报回调转发到WMS系统
|
String callUrl = wmsApi.getHost() + ":" + wmsApi.getPort() + WmsConstant.callBack;
|
log.info("RCS回调,请求地址: {}, 转换后参数: {}", callUrl, exMsgParams.toJSONString());
|
HttpHeaders headers = new HttpHeaders();
|
headers.add("Content-Type", "application/json");
|
headers.add("api-version", "v2.0");
|
HttpEntity httpEntity = new HttpEntity(exMsgParams, headers);
|
ResponseEntity<String> exchange = restTemplate.exchange(callUrl, HttpMethod.POST, httpEntity, String.class);
|
log.info("RCS回调,响应结果: {}", exchange);
|
|
if (Objects.isNull(exchange.getBody())) {
|
// 如果回调失败,返回成功响应(避免RCS重复回调)
|
CommonResponse response = new CommonResponse();
|
response.setCode(200);
|
response.setMsg("接收成功");
|
log.warn("RCS回调失败,但返回成功响应,任务编号:{},批次:{}", params.getTaskNo(), params.getBatchNo());
|
return response;
|
} else {
|
ObjectMapper objectMapper = new ObjectMapper();
|
objectMapper.coercionConfigDefaults()
|
.setCoercion(CoercionInputShape.EmptyString, CoercionAction.AsEmpty);
|
try {
|
CommonResponse result = objectMapper.readValue(exchange.getBody(), CommonResponse.class);
|
if (result.getCode() == 200) {
|
log.info("RCS回调上报成功,任务编号:{},批次:{}", params.getTaskNo(), params.getBatchNo());
|
return result;
|
} else {
|
log.warn("RCS回调上报回调返回非200状态,任务编号:{},批次:{},响应:{}", params.getTaskNo(), params.getBatchNo(), exchange.getBody());
|
return result;
|
}
|
} catch (JsonProcessingException e) {
|
log.error("RCS回调上报回调响应解析失败,任务编号:{},批次:{},错误:{}", params.getTaskNo(), params.getBatchNo(), e.getMessage());
|
// 解析失败时返回成功响应,避免RCS重复回调
|
CommonResponse response = new CommonResponse();
|
response.setCode(200);
|
response.setMsg("接收成功");
|
return response;
|
}
|
}
|
}
|
}
|