no message
parent
d73d0d454f
commit
d8b84477ad
|
|
@ -181,7 +181,7 @@ public class ScanTrayProcessor {
|
|||
*/
|
||||
private String getAreaCode(Integer orderType) {
|
||||
String areaCode = "";
|
||||
if (Set.of(0, 1, 2, 3).contains(orderType)) {
|
||||
if (Set.of(0, 1, 2, 3, 8).contains(orderType)) {
|
||||
areaCode = AreaTypeEnum.CPCCQ.getValue();
|
||||
} else {
|
||||
areaCode = AreaTypeEnum.MJCCQ.getValue();
|
||||
|
|
@ -199,51 +199,32 @@ public class ScanTrayProcessor {
|
|||
* @return 目标库位
|
||||
*/
|
||||
public Point allocatePoint(List<ItemKey> itemKeys, Point station, String areaCode, String type) {
|
||||
//1.优先寻找同物料/同仓库/同项目号/同任务号/同批次/同外部库存状态的库位
|
||||
List<Long> itemKeyIds = itemKeys.stream().map(ItemKey::getId).toList();
|
||||
List<Point> availablePoints = pointService.findClusterPoint(itemKeyIds, areaCode);
|
||||
// 1. 获取可用库位
|
||||
List<Point> availablePoints = getAvailablePoints(itemKeys, areaCode, type);
|
||||
if (CollectionUtils.isEmpty(availablePoints)) {
|
||||
//2.获取所有可用库位
|
||||
availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||
throw new RuntimeException("系统无可用库位");
|
||||
}
|
||||
|
||||
//根据巷道分组,得到每个巷道有多个库位,<巷道编号,库位个数>
|
||||
Map<String, Long> colMap = getColMap(areaCode);
|
||||
|
||||
//根据layerNum层来分组
|
||||
Map<String, List<Point>> layerMap = availablePoints.stream().collect(Collectors.groupingBy(Point::getLayerNum));
|
||||
|
||||
List<PointScore> firstScoredPoints = new ArrayList<>();
|
||||
List<PointScore> firstScoredPoints;
|
||||
List<PointScore> secondScoredPoints = new ArrayList<>();
|
||||
|
||||
//移位选择最优库位
|
||||
if (type.equals(BusinessTypeEnum.MOVE.getValue())) {
|
||||
String layerNum = station.getLayerNum();
|
||||
Station currentStation = new Station(station.getPositionX(), station.getPositionY());
|
||||
List<Point> firstLevelPoints = layerMap.get(layerNum);
|
||||
if (CollectionUtils.isNotEmpty(firstLevelPoints)) {
|
||||
firstScoredPoints = firstLevelPoints.stream()
|
||||
.map(point -> clusterPointScore(point, currentStation, itemKeys, colMap))
|
||||
.toList();
|
||||
}
|
||||
firstScoredPoints = selectBestPointForMove(station, itemKeys,colMap,layerMap);
|
||||
} else {
|
||||
//入库选择最优库位
|
||||
//计算第一层的库位分数
|
||||
Station firstStation = new Station(station.getPositionX(), station.getPositionY());
|
||||
List<Point> firstLevelPoints = layerMap.get(String.valueOf(CommonStatusEnum.ONE.getValue()));
|
||||
if (CollectionUtils.isNotEmpty(firstLevelPoints)) {
|
||||
firstScoredPoints = firstLevelPoints.stream()
|
||||
.map(point -> clusterPointScore(point, firstStation, itemKeys, colMap))
|
||||
.toList();
|
||||
}
|
||||
firstScoredPoints = selectBestPointForStorage(firstStation, itemKeys, CommonStatusEnum.ONE.getValue(), colMap, layerMap);
|
||||
|
||||
//计算第二层的库位分数
|
||||
Station secondStation = new Station(station.getPositionTwoX(), station.getPositionTwoY());
|
||||
List<Point> secondLevelPoints = layerMap.get(String.valueOf(CommonStatusEnum.TWO.getValue()));
|
||||
if (CollectionUtils.isNotEmpty(secondLevelPoints)) {
|
||||
secondScoredPoints = secondLevelPoints.stream()
|
||||
.map(point -> clusterPointScore(point, secondStation, itemKeys, colMap))
|
||||
.toList();
|
||||
}
|
||||
secondScoredPoints= selectBestPointForStorage(secondStation, itemKeys, CommonStatusEnum.TWO.getValue(), colMap, layerMap);
|
||||
}
|
||||
|
||||
//合并获取最优库位
|
||||
|
|
@ -254,7 +235,7 @@ public class ScanTrayProcessor {
|
|||
.sorted(Comparator.comparing(PointScore::getScore).reversed())
|
||||
.toList();
|
||||
|
||||
if (!scoredPoints.isEmpty()) {
|
||||
if (CollectionUtils.isNotEmpty(scoredPoints)) {
|
||||
log.info("最优【{}】库位评分结果:{}", scoredPoints.get(0).getPoint().getPointCode(), scoredPoints.get(0).getScore());
|
||||
return scoredPoints.get(0).getPoint();
|
||||
}
|
||||
|
|
@ -262,6 +243,60 @@ public class ScanTrayProcessor {
|
|||
throw new RuntimeException("系统无可用库位");
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取所有可用库位
|
||||
*/
|
||||
private List<Point> getAvailablePoints(List<ItemKey> itemKeys, String areaCode, String type) {
|
||||
//移位
|
||||
if (BusinessTypeEnum.MOVE.getValue().equals(type)) {
|
||||
return pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||
}
|
||||
|
||||
//入库
|
||||
List<Long> itemKeyIds = itemKeys.stream().map(ItemKey::getId).toList();
|
||||
List<Point> availablePoints = pointService.findClusterPoint(itemKeyIds, areaCode);
|
||||
if (CollectionUtils.isEmpty(availablePoints)) {
|
||||
//2.获取所有可用库位
|
||||
availablePoints = pointMapper.queryPoints(null, CommonStatusEnum.FREE.getValue(), areaCode);
|
||||
}
|
||||
return availablePoints;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移位选择最优库位评分
|
||||
*/
|
||||
private List<PointScore> selectBestPointForMove(Point station, List<ItemKey> itemKeys, Map<String, Long> colMap, Map<String, List<Point>> layerMap) {
|
||||
|
||||
//当前库位的层数
|
||||
String layerNum = station.getLayerNum();
|
||||
//当前库位的坐标
|
||||
Station currentStation = new Station(station.getPositionX(), station.getPositionY());
|
||||
//当前层的所有可用库位
|
||||
List<Point> currentLayerPoints = layerMap.get(layerNum);
|
||||
//过滤掉当前巷道的库位
|
||||
currentLayerPoints = currentLayerPoints.stream().filter(point -> !point.getColNum().equals(station.getColNum())).toList();
|
||||
if (CollectionUtils.isNotEmpty(currentLayerPoints)) {
|
||||
return currentLayerPoints.stream()
|
||||
.map(point -> clusterPointScore(point, currentStation, itemKeys, colMap))
|
||||
.toList();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库选择最优库位评分
|
||||
*/
|
||||
private List<PointScore> selectBestPointForStorage(Station station, List<ItemKey> itemKeys, Integer layerNum, Map<String, Long> colMap, Map<String, List<Point>> layerMap) {
|
||||
List<Point> currLayerPoints = layerMap.get(String.valueOf(layerNum));
|
||||
if (CollectionUtils.isNotEmpty(currLayerPoints)) {
|
||||
return currLayerPoints.stream()
|
||||
.map(point -> clusterPointScore(point, station, itemKeys, colMap))
|
||||
.toList();
|
||||
}
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 库位评分计算
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -11,6 +11,7 @@ import org.quartz.Job;
|
|||
import org.quartz.JobExecutionContext;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
|
@ -41,37 +42,53 @@ public class AllocateJob implements Job {
|
|||
// 缓存最大大小,防止内存溢出
|
||||
private static final int MAX_CACHE_SIZE = 1000;
|
||||
|
||||
// 使用静态变量跟踪当前分配位置
|
||||
private static volatile int currentIndex = 0;
|
||||
|
||||
@Override
|
||||
public void execute(JobExecutionContext jobExecutionContext) {
|
||||
// 查询未分配或者部分分配的出库
|
||||
List<Long> pickList = pickMapper.queryUnallocatedPick();
|
||||
if (CollectionUtils.isNotEmpty(pickList)) {
|
||||
// 分配出库
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<String> resultMsg = pickService.allocatePick(pickList);
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("分配出库明细耗时:{}ms", endTime - startTime);
|
||||
if (CollectionUtils.isNotEmpty(resultMsg)) {
|
||||
// 生成缓存键
|
||||
String cacheKey = generateCacheKey(resultMsg);
|
||||
// 轮询分配,每次只处理一个ID
|
||||
if (currentIndex < pickList.size()) {
|
||||
Long currentPickId = pickList.get(currentIndex);
|
||||
List<Long> singlePickList = List.of(currentPickId);
|
||||
long startTime = System.currentTimeMillis();
|
||||
List<String> resultMsg;
|
||||
try {
|
||||
resultMsg = pickService.allocatePick(singlePickList);
|
||||
}catch (Exception e){
|
||||
resultMsg=List.of(e.getMessage());
|
||||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("分配出库明细耗时:{}ms,处理ID:{}", endTime - startTime, currentPickId);
|
||||
|
||||
// 检查是否已经处理过相同的内容
|
||||
if (!processedCache.containsKey(cacheKey)) {
|
||||
// 新内容,记录日志
|
||||
baseCommonService.addLog("出库任务分配:" + "\n" + cacheKey, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_1);
|
||||
if (CollectionUtils.isNotEmpty(resultMsg)) {
|
||||
// 生成缓存键
|
||||
String cacheKey = generateCacheKey(resultMsg);
|
||||
|
||||
// 添加到缓存
|
||||
processedCache.put(cacheKey, true);
|
||||
// 检查是否已经处理过相同的内容
|
||||
if (!processedCache.containsKey(cacheKey)) {
|
||||
// 新内容,记录日志
|
||||
baseCommonService.addLog("出库任务分配:" + "\n" + cacheKey, CommonConstant.LOG_TYPE_2, CommonConstant.OPERATE_TYPE_1);
|
||||
|
||||
// 控制缓存大小
|
||||
if (processedCache.size() > MAX_CACHE_SIZE) {
|
||||
// 移除一部分旧缓存(简单实现,可以按需优化)
|
||||
processedCache.clear();
|
||||
// 添加到缓存
|
||||
processedCache.put(cacheKey, true);
|
||||
|
||||
// 控制缓存大小
|
||||
if (processedCache.size() > MAX_CACHE_SIZE) {
|
||||
processedCache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新索引,循环使用
|
||||
currentIndex = (currentIndex + 1) % pickList.size();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//生成出库AGV出库任务
|
||||
long startTime2 = System.currentTimeMillis();
|
||||
iTaskService.generateAgvTask();
|
||||
|
|
|
|||
|
|
@ -64,6 +64,13 @@ public interface IAsnService extends IService<Asn> {
|
|||
*/
|
||||
void receiveAsn(Long asnId);
|
||||
|
||||
/**
|
||||
* 取消操作
|
||||
*
|
||||
* @param asn 入库单
|
||||
*/
|
||||
void cancelAsn(Asn asn);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,9 +108,9 @@ public class AsnDetailServiceImpl extends ServiceImpl<AsnDetailMapper, AsnDetail
|
|||
stockService.bindStock(stock);
|
||||
|
||||
//4.成品入库,生成AGV任务
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType()) && station != null) {
|
||||
/*if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType()) && station != null) {
|
||||
agvTaskService.createAgvTask(asn.getId(), stock.getStockCode(), srcPoint.getPointCode(), station.getPointCode(), null, BusinessTypeEnum.INBOUND.getValue(), 0, AgvVendorEnum.HIK.getValue());
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1,12 +1,15 @@
|
|||
package org.cpte.modules.receive.service.impl;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.agvTask.entity.AgvTask;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.mapper.StockMapper;
|
||||
import org.cpte.modules.constant.enums.AsnStatusEnum;
|
||||
import org.cpte.modules.constant.enums.CommonStatusEnum;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
||||
|
|
@ -36,6 +39,8 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||
@Slf4j
|
||||
public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnService {
|
||||
|
||||
@Autowired
|
||||
private StockMapper stockMapper;
|
||||
@Autowired
|
||||
private AsnDetailMapper asnDetailMapper;
|
||||
@Autowired
|
||||
|
|
@ -54,7 +59,7 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("入库单创建中,请稍后重试");
|
||||
}
|
||||
asnDetailService.processorSaveMain(asn, asnDetailList);
|
||||
asnDetailService.processorSaveMain(asn, asnDetailList);
|
||||
} catch (Exception e) {
|
||||
log.error("入库单创建异常", e);
|
||||
throw e;
|
||||
|
|
@ -119,6 +124,7 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
throw new RuntimeException("操作失败:【" + orderNoList + "】入库单,非创建状态不允许删除");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void receiveAsn(Long asnId) {
|
||||
String lockKey = "asn:" + asnId;
|
||||
|
|
@ -138,4 +144,28 @@ public class AsnServiceImpl extends ServiceImpl<AsnMapper, Asn> implements IAsnS
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void cancelAsn(Asn asn) {
|
||||
List<AsnDetail> details = asnDetailMapper.selectByMainId(asn.getId());
|
||||
List<AsnDetail> updateToDetails = new ArrayList<>();
|
||||
for (AsnDetail detail : details) {
|
||||
detail.setStatus(AsnStatusEnum.CANCELED.getValue());
|
||||
updateToDetails.add(detail);
|
||||
}
|
||||
if (CollectionUtils.isNotEmpty(updateToDetails)) {
|
||||
asnDetailMapper.updateById(updateToDetails);
|
||||
}
|
||||
asn.setStatus(AsnStatusEnum.CANCELED.getValue());
|
||||
this.baseMapper.updateById(asn);
|
||||
|
||||
if (CollectionUtils.isNotEmpty(details)) {
|
||||
Stock stock = stockMapper.selectById(details.get(0).getStockId());
|
||||
if (stock != null) {
|
||||
stock.setStatus(CommonStatusEnum.FREE.getValue());
|
||||
stockMapper.updateById(stock);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,6 +78,10 @@ public class ReceiveProcessor {
|
|||
// 1.数据准备
|
||||
ReceiveData data = prepareReceiveData(asnId);
|
||||
|
||||
if(CollectionUtils.isEmpty(data.getAsnDetails())){
|
||||
return;
|
||||
}
|
||||
|
||||
//3.创建数据结构
|
||||
List<AsnDetail> updateToAsnDetail = new ArrayList<>();
|
||||
List<ReceiveRecord> createRecords = new ArrayList<>();
|
||||
|
|
|
|||
|
|
@ -5,10 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||
import jakarta.validation.Valid;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.cpte.modules.receive.service.IAsnService;
|
||||
import org.cpte.modules.saiWms.request.CallAgvRequest;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.saiWms.request.SyncStockRequest;
|
||||
import org.cpte.modules.saiWms.request.*;
|
||||
import org.cpte.modules.saiWms.service.ISMOMService;
|
||||
import org.jeecg.common.api.vo.Result;
|
||||
import org.jeecg.common.aspect.annotation.AutoLog;
|
||||
|
|
@ -73,8 +70,21 @@ public class SaiWmsController {
|
|||
@AutoLog(value = "出库任务下发")
|
||||
@Operation(summary = "赛意WMS-出库任务下发")
|
||||
@PostMapping(value = "/outBoundTask")
|
||||
public Result<String> outBoundTask(@RequestBody @Valid OutboundRequest outboundRequest) {
|
||||
public Result<String> outBoundTask(@RequestBody OutboundRequest outboundRequest) {
|
||||
iSaiWmsService.outBoundTask(outboundRequest);
|
||||
return Result.OK("操作成功!");
|
||||
}
|
||||
|
||||
/**
|
||||
* 入库取消
|
||||
*
|
||||
* @param inBoundCancel 请求参数
|
||||
*/
|
||||
@AutoLog(value = "入库任务取消")
|
||||
@Operation(summary = "入库任务取消")
|
||||
@PostMapping(value = "/inBoundCancel")
|
||||
public Result<String> inBoundCancel(@RequestBody InBoundCancelRequest inBoundCancel) {
|
||||
iSaiWmsService.inBoundCancel(inBoundCancel);
|
||||
return Result.OK("操作成功!");
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,11 @@
|
|||
package org.cpte.modules.saiWms.request;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class InBoundCancelRequest {
|
||||
// 任务号
|
||||
@JsonProperty("No")
|
||||
private String no;
|
||||
}
|
||||
|
|
@ -15,17 +15,14 @@ import java.util.List;
|
|||
@Data
|
||||
public class OutboundRequest {
|
||||
// 任务号
|
||||
@NotBlank(message = "任务号不能为空")
|
||||
@JsonProperty("No")
|
||||
private String no;
|
||||
|
||||
// 单号
|
||||
@NotBlank(message = "单号不能为空")
|
||||
@JsonProperty("OrderNo")
|
||||
private String orderNo;
|
||||
|
||||
// 仓库
|
||||
@NotBlank(message = "仓库不能为空")
|
||||
@JsonProperty("WhCode")
|
||||
private String whCode;
|
||||
|
||||
|
|
@ -34,7 +31,6 @@ public class OutboundRequest {
|
|||
private String customerCode;
|
||||
|
||||
// 单据类型:0.成品入库;1.配件入库;2.成品拆托入库;3.配件拆托入库;4.成品出库;5.配件出库;6.返工出库;7.检验出库;8.其他出库
|
||||
@NotNull(message = "单据类型不能为空")
|
||||
@JsonProperty("Type")
|
||||
private Integer type;
|
||||
|
||||
|
|
@ -43,20 +39,16 @@ public class OutboundRequest {
|
|||
private String enterprise;
|
||||
|
||||
// 出库明细列表
|
||||
@NotNull(message = "入库明细不能为空")
|
||||
@JsonProperty("details")
|
||||
@Valid
|
||||
private List<OutboundDetail> details;
|
||||
|
||||
@Data
|
||||
public static class OutboundDetail {
|
||||
// 行号
|
||||
@NotBlank(message = "行号不能为空")
|
||||
@JsonProperty("LineNo")
|
||||
private String lineNo;
|
||||
|
||||
// 物料
|
||||
@NotBlank(message = "物料不能为空")
|
||||
@JsonProperty("Item")
|
||||
private String item;
|
||||
|
||||
|
|
@ -66,10 +58,13 @@ public class OutboundRequest {
|
|||
private String unit;
|
||||
|
||||
// 数量
|
||||
@NotNull(message = "数量不能为空")
|
||||
@JsonProperty("Qty")
|
||||
private Double qty;
|
||||
|
||||
// 托盘号
|
||||
@JsonProperty("Lpn")
|
||||
private String lpn;
|
||||
|
||||
// 项目号
|
||||
@JsonProperty("Project")
|
||||
private String project;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,7 @@
|
|||
package org.cpte.modules.saiWms.service;
|
||||
|
||||
import org.cpte.modules.saiWms.request.CallAgvRequest;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.saiWms.request.SyncStockRequest;
|
||||
import jakarta.validation.Valid;
|
||||
import org.cpte.modules.saiWms.request.*;
|
||||
|
||||
public interface ISMOMService {
|
||||
|
||||
|
|
@ -30,4 +28,9 @@ public interface ISMOMService {
|
|||
* 呼叫AGV
|
||||
*/
|
||||
void callAgv(CallAgvRequest callAgvRequest);
|
||||
|
||||
/**
|
||||
* 入库取消
|
||||
*/
|
||||
void inBoundCancel(InBoundCancelRequest inBoundCancel);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,15 +2,9 @@ package org.cpte.modules.saiWms.service.impl;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.saiWms.request.CallAgvRequest;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.saiWms.request.SyncStockRequest;
|
||||
import org.cpte.modules.saiWms.request.*;
|
||||
import org.cpte.modules.saiWms.service.ISMOMService;
|
||||
import org.cpte.modules.saiWms.service.processor.CallAgvProcessor;
|
||||
import org.cpte.modules.saiWms.service.processor.InBoundTaskProcessor;
|
||||
import org.cpte.modules.saiWms.service.processor.OutBoundTaskProcessor;
|
||||
import org.cpte.modules.saiWms.service.processor.SyncStockProcessor;
|
||||
import org.cpte.modules.saiWms.service.processor.*;
|
||||
import org.cpte.modules.utils.RedisDistributedLockUtil;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
|
@ -31,6 +25,9 @@ public class ISMOMServiceImpl implements ISMOMService {
|
|||
@Autowired
|
||||
private CallAgvProcessor callAgvProcessor;
|
||||
|
||||
@Autowired
|
||||
private InBoundCancelProcessor inBoundCancelProcessor;
|
||||
|
||||
@Autowired
|
||||
private RedisDistributedLockUtil redissonLock;
|
||||
|
||||
|
|
@ -100,6 +97,26 @@ public class ISMOMServiceImpl implements ISMOMService {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void inBoundCancel(InBoundCancelRequest inBoundCancel) {
|
||||
String lockKey = "cancel:" + inBoundCancel.getNo();
|
||||
String lockValue = null;
|
||||
try {
|
||||
lockValue = redissonLock.tryLock(lockKey, 10);
|
||||
if (StringUtils.isEmpty(lockValue)) {
|
||||
throw new RuntimeException("入库单取消中,请稍后重试");
|
||||
}
|
||||
inBoundCancelProcessor.inBoundCancel(inBoundCancel);
|
||||
} catch (Exception e) {
|
||||
log.error("入库单取消异常", e);
|
||||
throw e;
|
||||
} finally {
|
||||
if (StringUtils.isNotEmpty(lockValue)) {
|
||||
redissonLock.unlock(lockKey, lockValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,93 @@
|
|||
package org.cpte.modules.saiWms.service.processor;
|
||||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.service.IItemService;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.enums.AsnOrderTypeEnum;
|
||||
import org.cpte.modules.constant.enums.AsnStatusEnum;
|
||||
import org.cpte.modules.inventory.mapper.InventoryMapper;
|
||||
import org.cpte.modules.receive.entity.Asn;
|
||||
import org.cpte.modules.receive.entity.AsnDetail;
|
||||
import org.cpte.modules.receive.mapper.AsnDetailMapper;
|
||||
import org.cpte.modules.receive.mapper.AsnMapper;
|
||||
import org.cpte.modules.receive.service.IAsnDetailService;
|
||||
import org.cpte.modules.receive.service.IAsnService;
|
||||
import org.cpte.modules.saiWms.request.InBoundCancelRequest;
|
||||
import org.cpte.modules.saiWms.request.InboundRequest;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* 接收入库任务处理
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class InBoundCancelProcessor {
|
||||
|
||||
@Autowired
|
||||
private AsnMapper asnMapper;
|
||||
|
||||
@Autowired
|
||||
private IAsnService asnService;
|
||||
|
||||
/**
|
||||
* 入库取消
|
||||
*
|
||||
* @param inBoundCancel 入库取消参数
|
||||
*/
|
||||
public void inBoundCancel(InBoundCancelRequest inBoundCancel) {
|
||||
// 1.参数校验
|
||||
validateParams(inBoundCancel);
|
||||
|
||||
// 2.验证任务号
|
||||
Asn asn = validateAsn(inBoundCancel.getNo());
|
||||
|
||||
if (AsnStatusEnum.CANCELED.getValue().equals(asn.getStatus())) {
|
||||
throw new RuntimeException("【" + inBoundCancel.getNo() + "】任务号已取消,请勿重复操作");
|
||||
}
|
||||
|
||||
if (AsnStatusEnum.CREATED.getValue().equals(asn.getStatus())) {
|
||||
asnService.cancelAsn(asn);
|
||||
} else {
|
||||
throw new RuntimeException("【" + inBoundCancel.getNo() + "】任务号已入库,无法取消");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 入库参数校验
|
||||
*
|
||||
* @param inboundRequest 入库参数
|
||||
*/
|
||||
private void validateParams(InBoundCancelRequest inboundRequest) {
|
||||
if (StringUtils.isBlank(inboundRequest.getNo())) {
|
||||
throw new RuntimeException("任务号(No)必填");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证任务号
|
||||
*
|
||||
* @param no 任务号
|
||||
*/
|
||||
private Asn validateAsn(String no) {
|
||||
Asn asn = asnMapper.queryByNo(no);
|
||||
if (asn == null) {
|
||||
throw new RuntimeException("【" + no + "】任务号不存在");
|
||||
}
|
||||
return asn;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -100,6 +100,11 @@ public class InBoundTaskProcessor {
|
|||
if (inboundRequest.getType() == null) {
|
||||
throw new RuntimeException("任务类型(Type)必填");
|
||||
}
|
||||
|
||||
if (!Set.of(0, 1, 2, 3, 8).contains(inboundRequest.getType())) {
|
||||
throw new RuntimeException("【" + inboundRequest.getType() + "】任务类型错误");
|
||||
}
|
||||
|
||||
if (AsnOrderTypeEnum.PRODUCT.getValue().equals(inboundRequest.getType())) {
|
||||
if (StringUtils.isBlank(inboundRequest.getLocationFrom())) {
|
||||
throw new RuntimeException("起点(LocationFrom)必填");
|
||||
|
|
|
|||
|
|
@ -5,8 +5,10 @@ import org.apache.commons.collections4.CollectionUtils;
|
|||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.base.service.IItemService;
|
||||
import org.cpte.modules.base.service.IPointService;
|
||||
import org.cpte.modules.base.service.IStockService;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.constant.enums.AreaTypeEnum;
|
||||
import org.cpte.modules.constant.enums.AsnOrderTypeEnum;
|
||||
|
|
@ -22,6 +24,7 @@ import org.springframework.transaction.annotation.Transactional;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* 接收出库任务处理
|
||||
|
|
@ -36,6 +39,9 @@ public class OutBoundTaskProcessor {
|
|||
@Autowired
|
||||
private IItemService itemService;
|
||||
|
||||
@Autowired
|
||||
private IStockService stockService;
|
||||
|
||||
@Autowired
|
||||
private IPointService pointService;
|
||||
|
||||
|
|
@ -58,8 +64,11 @@ public class OutBoundTaskProcessor {
|
|||
//3.验证物料
|
||||
Map<String, Item> itemMap = validateItem(outboundRequest.getDetails());
|
||||
|
||||
//4.验证容器
|
||||
Map<String, Stock> stockMap = validateStock(outboundRequest.getDetails());
|
||||
|
||||
//5.出库处理
|
||||
pickDetailService.processOutBoundTask(outboundRequest, itemMap);
|
||||
pickDetailService.processOutBoundTask(outboundRequest, itemMap,stockMap);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -81,6 +90,9 @@ public class OutBoundTaskProcessor {
|
|||
throw new RuntimeException("任务类型(Type)必填");
|
||||
}
|
||||
|
||||
if (!Set.of(4, 5, 6, 7).contains(outboundRequest.getType())) {
|
||||
throw new RuntimeException("【" + outboundRequest.getType() + "】任务类型错误");
|
||||
}
|
||||
|
||||
if (CollectionUtils.isEmpty(outboundRequest.getDetails())) {
|
||||
throw new RuntimeException("出库信息不能为空");
|
||||
|
|
@ -140,6 +152,30 @@ public class OutBoundTaskProcessor {
|
|||
return exitItemMap;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证容器
|
||||
*
|
||||
* @param detail 明细
|
||||
*/
|
||||
private Map<String, Stock> validateStock(List<OutboundRequest.OutboundDetail> detail) {
|
||||
//获取明细中所有的容器
|
||||
List<String> stockCodes = detail.stream().map(OutboundRequest.OutboundDetail::getLpn).toList();
|
||||
if (CollectionUtils.isNotEmpty(stockCodes)) {
|
||||
//获取数据库已存在容器
|
||||
Map<String, Stock> exitStockMap = stockService.queryByStockCodesToMap(stockCodes);
|
||||
|
||||
//获取不存在的容器
|
||||
List<String> notExitStockCodes = stockCodes.stream().filter(stockCode -> !exitStockMap.containsKey(stockCode)).toList();
|
||||
if (CollectionUtils.isNotEmpty(notExitStockCodes)) {
|
||||
throw new RuntimeException("系统无" + notExitStockCodes + "托盘,请维护");
|
||||
}
|
||||
return exitStockMap;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 验证起点
|
||||
*
|
||||
|
|
|
|||
|
|
@ -61,6 +61,15 @@ public class PickDetail implements Serializable {
|
|||
@Schema(description = "物料ID")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long itemId;
|
||||
|
||||
/**
|
||||
* 容器
|
||||
*/
|
||||
@Excel(name = "容器", width = 15)
|
||||
@Schema(description = "容器")
|
||||
@JsonSerialize(using = ToStringSerializer.class)
|
||||
private java.lang.Long stockId;
|
||||
|
||||
/**
|
||||
* 行号
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1,14 +1,11 @@
|
|||
package org.cpte.modules.shipping.service;
|
||||
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Point;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.inventory.entity.Inventory;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
import org.cpte.modules.shipping.entity.Pick;
|
||||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
|
@ -36,7 +33,7 @@ public interface IPickDetailService extends IService<PickDetail> {
|
|||
* @param exitItemMap 物料
|
||||
* @return 出库单明细
|
||||
*/
|
||||
List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap);
|
||||
List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap, Map<String, Stock> stockMap);
|
||||
|
||||
|
||||
/**
|
||||
|
|
@ -77,7 +74,7 @@ public interface IPickDetailService extends IService<PickDetail> {
|
|||
* @param outboundRequest 出库参数
|
||||
* @param itemMap 物料
|
||||
*/
|
||||
void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap);
|
||||
void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap, Map<String, Stock> stockMap);
|
||||
|
||||
/**
|
||||
* 刷新出库单
|
||||
|
|
|
|||
|
|
@ -3,6 +3,7 @@ package org.cpte.modules.shipping.service.impl;
|
|||
import org.apache.commons.collections4.CollectionUtils;
|
||||
import org.apache.shiro.SecurityUtils;
|
||||
import org.cpte.modules.base.entity.Item;
|
||||
import org.cpte.modules.base.entity.Stock;
|
||||
import org.cpte.modules.constant.GeneralConstant;
|
||||
import org.cpte.modules.constant.enums.PickStatusEnum;
|
||||
import org.cpte.modules.saiWms.request.OutboundRequest;
|
||||
|
|
@ -56,12 +57,13 @@ public class PickDetailServiceImpl extends ServiceImpl<PickDetailMapper, PickDet
|
|||
}
|
||||
|
||||
@Override
|
||||
public List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap) {
|
||||
public List<PickDetail> buildPickDetail(List<OutboundRequest.OutboundDetail> details, Map<String, Item> exitItemMap, Map<String, Stock> stockMap) {
|
||||
List<PickDetail> newDetailList = new ArrayList<>();
|
||||
for (OutboundRequest.OutboundDetail detail : details) {
|
||||
PickDetail pickDetail = PickDetail.builder()
|
||||
.lineNo(Integer.parseInt(detail.getLineNo()))
|
||||
.itemId(exitItemMap.get(detail.getItem()).getId())
|
||||
.stockId(stockMap == null ? null : stockMap.get(detail.getLpn()).getId())
|
||||
.unit(detail.getUnit())
|
||||
.orderQty(BigDecimal.valueOf(detail.getQty()))
|
||||
.allocatedQty(BigDecimal.ZERO)
|
||||
|
|
@ -77,23 +79,23 @@ public class PickDetailServiceImpl extends ServiceImpl<PickDetailMapper, PickDet
|
|||
return newDetailList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取出库单Map
|
||||
*
|
||||
* @param pickIds 出库单id
|
||||
* @return 出库单Map
|
||||
*/
|
||||
public Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds) {
|
||||
if (CollectionUtils.isEmpty(pickIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, Pick> pickMap = new HashMap<>();
|
||||
List<Pick> pickList = pickMapper.selectByIds(pickIds);
|
||||
for (Pick pick : pickList) {
|
||||
pickMap.put(pick.getId(), pick);
|
||||
}
|
||||
return pickMap;
|
||||
}
|
||||
/**
|
||||
* 获取出库单Map
|
||||
*
|
||||
* @param pickIds 出库单id
|
||||
* @return 出库单Map
|
||||
*/
|
||||
public Map<Long, Pick> queryByPickIdsToMap(List<Long> pickIds) {
|
||||
if (CollectionUtils.isEmpty(pickIds)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
Map<Long, Pick> pickMap = new HashMap<>();
|
||||
List<Pick> pickList = pickMapper.selectByIds(pickIds);
|
||||
for (Pick pick : pickList) {
|
||||
pickMap.put(pick.getId(), pick);
|
||||
}
|
||||
return pickMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取出库单明细Map
|
||||
|
|
@ -146,10 +148,10 @@ public class PickDetailServiceImpl extends ServiceImpl<PickDetailMapper, PickDet
|
|||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap) {
|
||||
public void processOutBoundTask(OutboundRequest outboundRequest, Map<String, Item> itemMap, Map<String, Stock> stockMap) {
|
||||
// 创建出库单和明细
|
||||
Pick createPick = buildPick(outboundRequest);
|
||||
List<PickDetail> pickDetails = buildPickDetail(outboundRequest.getDetails(), itemMap);
|
||||
List<PickDetail> pickDetails = buildPickDetail(outboundRequest.getDetails(), itemMap, stockMap);
|
||||
processorSaveMain(createPick, pickDetails);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -23,7 +23,6 @@ import org.cpte.modules.shipping.entity.Pick;
|
|||
import org.cpte.modules.shipping.entity.PickDetail;
|
||||
import org.cpte.modules.shipping.entity.Task;
|
||||
import org.cpte.modules.shipping.mapper.PickDetailMapper;
|
||||
import org.cpte.modules.shipping.mapper.TaskMapper;
|
||||
import org.cpte.modules.shipping.service.IPickDetailService;
|
||||
import org.cpte.modules.shipping.service.ITaskService;
|
||||
import org.cpte.modules.shipping.vo.AllocationData;
|
||||
|
|
@ -57,8 +56,6 @@ public class AllocateProcessor {
|
|||
@Autowired
|
||||
private ItemKeyMapper itemKeyMapper;
|
||||
|
||||
|
||||
|
||||
@Autowired
|
||||
private InventoryMapper inventoryMapper;
|
||||
|
||||
|
|
@ -347,6 +344,21 @@ public class AllocateProcessor {
|
|||
|
||||
// 智能排序库存
|
||||
List<InventoryScore> scoredInventories = scoreInventories(matchedInventories);
|
||||
|
||||
//指定容器出库
|
||||
if (pickDetail.getStockId() != null) {
|
||||
//根据容器分组
|
||||
Map<Long, List<InventoryScore>> inventoryScoreMap = scoredInventories.stream().collect(Collectors.groupingBy(InventoryScore::getStockId));
|
||||
scoredInventories = inventoryScoreMap.get(pickDetail.getStockId());
|
||||
|
||||
}
|
||||
if (CollectionUtils.isEmpty(scoredInventories)) {
|
||||
Stock stock = stockService.getById(pickDetail.getStockId());
|
||||
String message = String.format("任务号【%s】,容器【%s】无库存", pick.getNo(), stock.getStockCode());
|
||||
errorMsgSet.add(message);
|
||||
return;
|
||||
}
|
||||
|
||||
//未分配数量
|
||||
BigDecimal remainingQty = totalUnAllocatedQty;
|
||||
for (InventoryScore inventoryScore : scoredInventories) {
|
||||
|
|
@ -354,6 +366,7 @@ public class AllocateProcessor {
|
|||
if (remainingQty.compareTo(BigDecimal.ZERO) <= 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
Inventory inventory = inventoryScore.getInventory();
|
||||
|
||||
// 库存可用数量
|
||||
|
|
@ -432,7 +445,7 @@ public class AllocateProcessor {
|
|||
double distanceScore = calculateClusterDistanceCost(currPoint, bestPoint) * 0.3;
|
||||
|
||||
//当前巷道的库位数
|
||||
List<Point> points= pointMapper.findByColAndLayer(currPoint.getColNum(), currPoint.getLayerNum());
|
||||
List<Point> points = pointMapper.findByColAndLayer(currPoint.getColNum(), currPoint.getLayerNum());
|
||||
|
||||
// 目标库位的深度位转换为索引
|
||||
int targetIndex = Integer.parseInt(currPoint.getRowNum()) - 1;
|
||||
|
|
@ -459,7 +472,7 @@ public class AllocateProcessor {
|
|||
log.info("【{}】库位距离评分: {}-移位评分: {}-总得分: {}-移位次数: {}",
|
||||
currPoint.getPointCode(), distanceScore, moveScore, totalScore, movePoints.size());
|
||||
|
||||
return new InventoryScore(inventory, totalScore, bestPoint, movePoints);
|
||||
return new InventoryScore(inventory, inventory.getStockId(), totalScore, bestPoint, movePoints);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -716,16 +729,20 @@ public class AllocateProcessor {
|
|||
Map<Long, Stock> stockMap = stockService.queryByStockIdsToMap(stockIds);
|
||||
|
||||
for (Inventory inv : moveInventoryList) {
|
||||
Item moveItem = moveItemMap.get(inv.getItemId());
|
||||
Point fromPoint = fromPointMap.get(inv.getPointId());
|
||||
Stock stock = stockMap.get(inv.getStockId());
|
||||
String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO);
|
||||
//根据算法找到最优的目标库位
|
||||
Point toPoint = allocatePoint(fromPoint, itemKeyMap.get(inv.getItemKeyId()));
|
||||
Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0);
|
||||
moveList.add(moveTask);
|
||||
pointService.bindPoint(toPoint);
|
||||
log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity());
|
||||
try {
|
||||
Item moveItem = moveItemMap.get(inv.getItemId());
|
||||
Point fromPoint = fromPointMap.get(inv.getPointId());
|
||||
Stock stock = stockMap.get(inv.getStockId());
|
||||
String taskNo = moveSerialNumberRule.generateSerialNumber(GeneralConstant.MOVE_ORDER_NO);
|
||||
//根据算法找到最优的目标库位
|
||||
Point toPoint = allocatePoint(fromPoint, itemKeyMap.get(inv.getItemKeyId()));
|
||||
Task moveTask = taskService.bulidTask(taskNo, TaskTypeEnum.MOVE.getValue(), moveItem, fromPoint, toPoint, stock, null, null, inv.getItemKeyId(), inv.getId(), inv.getQuantity(), 0);
|
||||
moveList.add(moveTask);
|
||||
pointService.bindPoint(toPoint);
|
||||
log.info("生成移位任务:{}- 容器:{} - 库位:{} - 库存数量:{}", taskNo, stock.getStockCode(), fromPoint.getPointCode(), inv.getQuantity());
|
||||
} catch (Exception e) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
return moveList;
|
||||
}
|
||||
|
|
@ -740,7 +757,7 @@ public class AllocateProcessor {
|
|||
Area area = areaMapper.selectById(currentPoint.getAreaId());
|
||||
String areaCode = area.getAreaCode();
|
||||
List<ItemKey> itemKeyIds = Collections.singletonList(itemKey);
|
||||
return scanTrayProcessor.allocatePoint(itemKeyIds, currentPoint, areaCode,BusinessTypeEnum.MOVE.getValue());
|
||||
return scanTrayProcessor.allocatePoint(itemKeyIds, currentPoint, areaCode, BusinessTypeEnum.MOVE.getValue());
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -12,6 +12,8 @@ import java.util.List;
|
|||
public class InventoryScore {
|
||||
// 库存
|
||||
private Inventory inventory;
|
||||
//容器
|
||||
private Long stockId;
|
||||
// 分数
|
||||
private double score;
|
||||
//最佳出库口
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@ spring:
|
|||
jdbc:
|
||||
initialize-schema: embedded
|
||||
#定时任务启动开关,true-开 false-关
|
||||
auto-startup: true
|
||||
auto-startup: false
|
||||
#延迟1秒启动定时任务
|
||||
startup-delay: 1s
|
||||
#启动时更新己存在的Job
|
||||
|
|
@ -145,7 +145,7 @@ spring:
|
|||
selectWhereAlwayTrueCheck: false
|
||||
# 打开mergeSql功能;慢SQL记录
|
||||
stat:
|
||||
log-slow-sql: true
|
||||
#log-slow-sql: false
|
||||
slow-sql-millis: 5000
|
||||
merge-sql: true
|
||||
datasource:
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue