diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/dataobject/dailyplan/DailyPlanClaimDO.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/dataobject/dailyplan/DailyPlanClaimDO.java index 810e8571..54ec9b1f 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/dataobject/dailyplan/DailyPlanClaimDO.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/dataobject/dailyplan/DailyPlanClaimDO.java @@ -23,6 +23,7 @@ public class DailyPlanClaimDO extends TenantBaseDO { private Integer version; private Integer claimStatus; private Integer activeFlag; + private Boolean taskCreated; private LocalDateTime expireTime; private LocalDateTime confirmedTime; private String operator; diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/coretube/CoreTubeMapper.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/coretube/CoreTubeMapper.java index 0a1bcacd..43f0d0d6 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/coretube/CoreTubeMapper.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/coretube/CoreTubeMapper.java @@ -21,4 +21,42 @@ public interface CoreTubeMapper extends BaseMapperX { /** 插入管芯实例。 */ int insertCoreTube(@Param("tube") CoreTubeDO tube); + + /** 查询对接位上一根可用的目标管芯。 */ + CoreTubeDO selectAvailableDockTube(@Param("materialId") Long materialId); + + /** 查询管芯库中一根可用的目标管芯。 */ + CoreTubeDO selectAvailableWarehouseTube(@Param("materialId") Long materialId); + + /** 原子预占一根管芯。 */ + int reserveTube(@Param("coreTubeId") Long coreTubeId, @Param("expectedStage") Integer expectedStage, + @Param("newStage") Integer newStage, @Param("dailyPlanId") Long dailyPlanId, + @Param("claimToken") String claimToken, @Param("expireTime") java.time.LocalDateTime expireTime, + @Param("updater") String updater); + + /** 绑定现场任务。 */ + int bindTask(@Param("coreTubeId") Long coreTubeId, @Param("taskId") Long taskId, + @Param("updater") String updater); + + /** 释放尚未落任务的管芯预占。 */ + int releaseReservation(@Param("coreTubeId") Long coreTubeId, @Param("claimToken") String claimToken, + @Param("stage") Integer stage, @Param("updater") String updater); + + /** 完成管芯位置转换。 */ + int completeTubeTask(@Param("coreTubeId") Long coreTubeId, @Param("taskId") Long taskId, + @Param("stage") Integer stage, @Param("status") Integer status, + @Param("locationType") Integer locationType, + @Param("locationId") Long locationId, @Param("locationCode") String locationCode, + @Param("clearVehicle") Boolean clearVehicle, @Param("updater") String updater); + + /** 取消管芯任务并恢复可用。 */ + int cancelTubeTask(@Param("coreTubeId") Long coreTubeId, @Param("taskId") Long taskId, + @Param("stage") Integer stage, @Param("updater") String updater); + + /** 按托盘更新全部管芯当前位置。 */ + int updateVehicleLocation(@Param("vehicleCode") String vehicleCode, + @Param("locationType") Integer locationType, + @Param("locationId") Long locationId, + @Param("locationCode") String locationCode, + @Param("updater") String updater); } diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/dailyplan/DailyPlanClaimMapper.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/dailyplan/DailyPlanClaimMapper.java index 79244ea0..2f34b391 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/dailyplan/DailyPlanClaimMapper.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/dailyplan/DailyPlanClaimMapper.java @@ -22,6 +22,8 @@ public interface DailyPlanClaimMapper extends BaseMapperX { int releaseClaim(@Param("claimToken") String claimToken, @Param("updater") String updater); + int markTaskCreated(@Param("claimToken") String claimToken, @Param("updater") String updater); + int renewClaim(@Param("claimToken") String claimToken, @Param("version") Integer version, @Param("expireTime") LocalDateTime expireTime, @Param("updater") String updater); diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/stockingivt/StockingIvtMapper.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/stockingivt/StockingIvtMapper.java index aa204788..c06a5295 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/stockingivt/StockingIvtMapper.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/dal/mysql/stockingivt/StockingIvtMapper.java @@ -78,4 +78,26 @@ public interface StockingIvtMapper extends BaseMapperX { * 新增管芯托盘格位。 */ int insertPaperVehicleCoreTube(@Param("tube") cn.code.nl.module.lms.dal.dataobject.coretube.CoreTubeDO tube); + + /** 管芯离开托盘后清理格位绑定。 */ + int clearPaperVehicleCoreTube(@Param("coreTubeId") Long coreTubeId, @Param("updater") String updater); + + /** 查询当前有托盘的对接位。 */ + StockingIvtDO selectOccupiedDockPoint(); + + /** 查询当前空闲的对接位。 */ + StockingIvtDO selectEmptyDockPoint(); + + /** 查询当前空闲的缓存位。 */ + StockingIvtDO selectEmptyCachePoint(); + + /** 为目标物料选择最合适的缓存位托盘。 */ + StockingIvtDO selectBestCacheVehicle(@Param("materialId") Long materialId, + @Param("requiredQty") Integer requiredQty); + + /** 完成托盘点位转移。 */ + int completeVehicleMove(@Param("sourcePointId") Long sourcePointId, + @Param("targetPointId") Long targetPointId, + @Param("vehicleCode") String vehicleCode, + @Param("updater") String updater); } diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeHandleCodeConstants.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeHandleCodeConstants.java new file mode 100644 index 00000000..6a040b19 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeHandleCodeConstants.java @@ -0,0 +1,7 @@ +package cn.code.nl.module.lms.enums; + +/** 管芯任务回调处理器编码。 */ +public interface CoreTubeHandleCodeConstants { + String CORE_TUBE_STOCKING_TASK = "CORE_TUBE_STOCKING_TASK"; + String CORE_TUBE_SLEEVING_TASK = "CORE_TUBE_SLEEVING_TASK"; +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeTaskBizTypeEnum.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeTaskBizTypeEnum.java new file mode 100644 index 00000000..c76845c4 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/enums/CoreTubeTaskBizTypeEnum.java @@ -0,0 +1,9 @@ +package cn.code.nl.module.lms.enums; + +/** 管芯现场任务业务类型。 */ +public enum CoreTubeTaskBizTypeEnum { + CORE_TUBE_PALLET_IN, + CORE_TUBE_PALLET_OUT, + CORE_TUBE_STOCKING_PICK, + CORE_TUBE_SLEEVING_OUT +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/job/DailyPlanCoreTubeJob.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/job/DailyPlanCoreTubeJob.java new file mode 100644 index 00000000..0cd7dfac --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/job/DailyPlanCoreTubeJob.java @@ -0,0 +1,38 @@ +package cn.code.nl.module.lms.job; + +import cn.code.nl.framework.tenant.core.job.TenantJob; +import cn.code.nl.module.lms.service.coretube.CoreTubeTaskDispatchService; +import com.xxl.job.core.context.XxlJobHelper; +import com.xxl.job.core.handler.annotation.XxlJob; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.stereotype.Component; + +/** 日计划管芯备货与套管定时调度。 */ +@Slf4j +@Component +public class DailyPlanCoreTubeJob { + + @Resource + private CoreTubeTaskDispatchService dispatchService; + + /** 每次每租户最多创建一条备货现场任务。 */ + @XxlJob("dailyPlanStockingJob") + @TenantJob + public void dailyPlanStockingJob() { + String result = dispatchService.dispatchStockingOnce(); + log.info("日计划备货调度完成:{}", result); + XxlJobHelper.log(result); + XxlJobHelper.handleSuccess(result); + } + + /** 每次每租户最多创建一条单根管芯出库任务。 */ + @XxlJob("dailyPlanSleevingJob") + @TenantJob + public void dailyPlanSleevingJob() { + String result = dispatchService.dispatchSleevingOnce(); + log.info("日计划套管调度完成:{}", result); + XxlJobHelper.log(result); + XxlJobHelper.handleSuccess(result); + } +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskContext.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskContext.java new file mode 100644 index 00000000..0faf976f --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskContext.java @@ -0,0 +1,18 @@ +package cn.code.nl.module.lms.service.coretube; + +import lombok.Data; + +/** 管芯现场任务回调上下文。 */ +@Data +public class CoreTubeTaskContext { + private String bizType; + private Long dailyPlanId; + private String claimToken; + private Long coreTubeId; + private String coreTubeCode; + private String vehicleCode; + private Long sourcePointId; + private String sourcePointCode; + private Long targetPointId; + private String targetPointCode; +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchService.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchService.java new file mode 100644 index 00000000..9fda9a9d --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchService.java @@ -0,0 +1,17 @@ +package cn.code.nl.module.lms.service.coretube; + +/** 管芯日计划现场任务调度服务。 */ +public interface CoreTubeTaskDispatchService { + + /** 执行一轮备货调度。 */ + String dispatchStockingOnce(); + + /** 执行一轮套管调度。 */ + String dispatchSleevingOnce(); + + /** 处理任务完成。 */ + void handleFinished(Long taskId, boolean sleeving); + + /** 处理任务取消。 */ + void handleCancelled(Long taskId, boolean sleeving); +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchServiceImpl.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchServiceImpl.java new file mode 100644 index 00000000..bc96b59e --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/coretube/CoreTubeTaskDispatchServiceImpl.java @@ -0,0 +1,330 @@ +package cn.code.nl.module.lms.service.coretube; + +import cn.code.nl.framework.common.pojo.CommonResult; +import cn.code.nl.framework.common.util.json.JsonUtils; +import cn.code.nl.module.lms.dal.dataobject.coretube.CoreTubeDO; +import cn.code.nl.module.lms.dal.dataobject.stockingivt.StockingIvtDO; +import cn.code.nl.module.lms.dal.mysql.coretube.CoreTubeMapper; +import cn.code.nl.module.lms.dal.mysql.stockingivt.StockingIvtMapper; +import cn.code.nl.module.lms.enums.CoreTubeHandleCodeConstants; +import cn.code.nl.module.lms.enums.CoreTubeLocationTypeEnum; +import cn.code.nl.module.lms.enums.CoreTubeStageEnum; +import cn.code.nl.module.lms.enums.CoreTubeStatusEnum; +import cn.code.nl.module.lms.enums.CoreTubeTaskBizTypeEnum; +import cn.code.nl.module.lms.service.dailyplan.DailyPlanScheduleCandidate; +import cn.code.nl.module.lms.service.dailyplan.DailyPlanScheduleService; +import cn.code.nl.module.task.api.TransportTaskApi; +import cn.code.nl.module.task.dto.TaskInfoDTO; +import cn.code.nl.module.task.dto.TransportTaskCreateReqDTO; +import jakarta.annotation.Resource; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.time.LocalDateTime; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** 管芯日计划现场任务调度服务实现。 */ +@Slf4j +@Service +public class CoreTubeTaskDispatchServiceImpl implements CoreTubeTaskDispatchService { + + private static final String OPERATOR = "SCHEDULER"; + private static final String OWNER_SERVICE = "LMS"; + + @Resource + private DailyPlanScheduleService dailyPlanScheduleService; + @Resource + private CoreTubeMapper coreTubeMapper; + @Resource + private StockingIvtMapper stockingIvtMapper; + @Resource + private TransportTaskApi transportTaskApi; + + @Value("${lms.core-tube.agv-system-type:AGV}") + private String agvSystemType; + @Value("${lms.core-tube.pallet-in-acs-type:CORE_PALLET_IN}") + private String palletInAcsType; + @Value("${lms.core-tube.pallet-out-acs-type:CORE_PALLET_OUT}") + private String palletOutAcsType; + @Value("${lms.core-tube.stocking-pick-acs-type:CORE_STOCKING_PICK}") + private String stockingPickAcsType; + @Value("${lms.core-tube.sleeving-out-acs-type:CORE_SLEEVING_OUT}") + private String sleevingOutAcsType; + @Value("${lms.core-tube.stocking-target-point:CORE_WAREHOUSE_IN}") + private String stockingTargetPoint; + @Value("${lms.core-tube.sleeving-target-point:SLEEVING_IN}") + private String sleevingTargetPoint; + + /** 执行一轮备货调度。 */ + @Override + @Transactional(rollbackFor = Exception.class) + public String dispatchStockingOnce() { + List candidates = dailyPlanScheduleService.previewStockingCandidates(); + if (candidates.isEmpty()) { + return "没有待备货日计划"; + } + Set checkedMaterials = new HashSet<>(); + for (DailyPlanScheduleCandidate candidate : candidates) { + if (!checkedMaterials.add(candidate.getMaterialId())) { + continue; + } + CoreTubeDO tube = coreTubeMapper.selectAvailableDockTube(candidate.getMaterialId()); + if (tube != null) { + Long taskId = createSingleTubeTask(candidate, tube, false); + return "已创建管芯抓取任务,taskId=" + taskId + ",管芯=" + tube.getCoreTubeCode(); + } + } + return createPalletTask(candidates, checkedMaterials); + } + + /** 执行一轮套管调度。 */ + @Override + @Transactional(rollbackFor = Exception.class) + public String dispatchSleevingOnce() { + List candidates = dailyPlanScheduleService.previewSleevingCandidates(); + if (candidates.isEmpty()) { + return "没有待套管日计划"; + } + Set checkedMaterials = new HashSet<>(); + for (DailyPlanScheduleCandidate candidate : candidates) { + if (!checkedMaterials.add(candidate.getMaterialId())) { + continue; + } + CoreTubeDO tube = coreTubeMapper.selectAvailableWarehouseTube(candidate.getMaterialId()); + if (tube != null) { + Long taskId = createSingleTubeTask(candidate, tube, true); + return "已创建管芯出库任务,taskId=" + taskId + ",管芯=" + tube.getCoreTubeCode(); + } + if (hasStockingTask(candidate.getMaterialId())) { + log.info("{}管芯正在备货,跳过日计划{}", candidate.getMaterialSpec(), candidate.getPlanCode()); + } else { + log.info("备货区{}管芯库存不足,跳过日计划{}", candidate.getMaterialSpec(), candidate.getPlanCode()); + } + } + return "全部待套管规格当前均无可出库管芯"; + } + + /** 创建单根抓取或出库任务。 */ + protected Long createSingleTubeTask(DailyPlanScheduleCandidate preview, CoreTubeDO tube, boolean sleeving) { + DailyPlanScheduleCandidate claim = sleeving + ? dailyPlanScheduleService.claimSleevingCandidate(preview.getDailyPlanId(), OPERATOR) + : dailyPlanScheduleService.claimStockingCandidate(preview.getDailyPlanId(), OPERATOR); + int oldStage = sleeving ? CoreTubeStageEnum.CORE_WAREHOUSE.getCode() : CoreTubeStageEnum.STOCKING_AREA.getCode(); + int newStage = sleeving ? CoreTubeStageEnum.CORE_OUTBOUND.getCode() : CoreTubeStageEnum.STOCKING_PICKING.getCode(); + if (coreTubeMapper.reserveTube(tube.getCoreTubeId(), oldStage, newStage, claim.getDailyPlanId(), + claim.getClaimToken(), claim.getClaimExpireTime(), OPERATOR) != 1) { + dailyPlanScheduleService.releaseClaim(claim.getClaimToken(), OPERATOR); + throw new IllegalStateException("管芯已被其他任务占用"); + } + CoreTubeTaskContext context = new CoreTubeTaskContext(); + context.setBizType((sleeving ? CoreTubeTaskBizTypeEnum.CORE_TUBE_SLEEVING_OUT + : CoreTubeTaskBizTypeEnum.CORE_TUBE_STOCKING_PICK).name()); + context.setDailyPlanId(claim.getDailyPlanId()); + context.setClaimToken(claim.getClaimToken()); + context.setCoreTubeId(tube.getCoreTubeId()); + context.setCoreTubeCode(tube.getCoreTubeCode()); + context.setVehicleCode(tube.getVehicleCode()); + context.setSourcePointId(tube.getCurrentLocationId()); + context.setSourcePointCode(tube.getCurrentLocationCode()); + context.setTargetPointCode(sleeving ? sleevingTargetPoint : stockingTargetPoint); + String bizType = context.getBizType(); + String bizId = tube.getCoreTubeCode(); + Long taskId = createTask(buildTubeTask(claim, tube, context, sleeving), bizType, bizId); + if (coreTubeMapper.bindTask(tube.getCoreTubeId(), taskId, OPERATOR) != 1) { + throw new IllegalStateException("管芯任务绑定失败"); + } + dailyPlanScheduleService.confirmTaskCreated(claim.getClaimToken(), OPERATOR); + return taskId; + } + + /** 所有规格不能直接抓取时创建一条托盘任务。 */ + private String createPalletTask(List candidates, Set checkedMaterials) { + StockingIvtDO occupiedDock = stockingIvtMapper.selectOccupiedDockPoint(); + if (occupiedDock != null) { + StockingIvtDO target = stockingIvtMapper.selectEmptyCachePoint(); + if (target == null) { + return "对接位存在非目标托盘,但没有空缓存位可移出"; + } + Long taskId = createPalletMoveTask(occupiedDock, target, occupiedDock.getVehicleCode(), true, null); + return "已创建托盘移出任务,taskId=" + taskId; + } + StockingIvtDO dock = stockingIvtMapper.selectEmptyDockPoint(); + if (dock == null) { + return "没有可用的备货对接位"; + } + for (DailyPlanScheduleCandidate candidate : candidates) { + if (!checkedMaterials.contains(candidate.getMaterialId())) { + continue; + } + String materialBizId = "MATERIAL:" + candidate.getMaterialId(); + if (getUnfinished(CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN.name(), materialBizId) != null) { + continue; + } + StockingIvtDO source = stockingIvtMapper.selectBestCacheVehicle(candidate.getMaterialId(), + candidate.getRemainingQuantity()); + if (source != null) { + Long taskId = createPalletMoveTask(source, dock, source.getVehicleCode(), false, candidate); + return "已创建托盘移入任务,taskId=" + taskId; + } + log.info("备货区没有可用的{}管芯,跳过日计划{}", candidate.getMaterialSpec(), candidate.getPlanCode()); + } + return "备货区没有任何候选规格的可用管芯托盘"; + } + + /** 创建托盘点位转移任务。 */ + private Long createPalletMoveTask(StockingIvtDO source, StockingIvtDO target, String vehicleCode, + boolean moveOut, DailyPlanScheduleCandidate candidate) { + CoreTubeTaskContext context = new CoreTubeTaskContext(); + context.setBizType((moveOut ? CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_OUT + : CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN).name()); + context.setDailyPlanId(candidate == null ? null : candidate.getDailyPlanId()); + context.setVehicleCode(vehicleCode); + context.setSourcePointId(source.getIvtId()); + context.setSourcePointCode(source.getPointCode()); + context.setTargetPointId(target.getIvtId()); + context.setTargetPointCode(target.getPointCode()); + TransportTaskCreateReqDTO request = baseTask(context, moveOut ? "管芯托盘移出" : "管芯托盘移入", + moveOut ? palletOutAcsType : palletInAcsType, CoreTubeHandleCodeConstants.CORE_TUBE_STOCKING_TASK); + request.setVehicleCode(vehicleCode); + request.setPointCode1(source.getPointCode()); + request.setPointCode2(target.getPointCode()); + request.setMaterialId(candidate == null ? null : candidate.getMaterialId()); + request.setMaterialCode(candidate == null ? null : candidate.getMaterialCode()); + String bizId = moveOut ? "DOCK:" + source.getPointCode() : "MATERIAL:" + candidate.getMaterialId(); + return createTask(request, context.getBizType(), bizId); + } + + /** 构造单根管芯任务。 */ + private TransportTaskCreateReqDTO buildTubeTask(DailyPlanScheduleCandidate candidate, CoreTubeDO tube, + CoreTubeTaskContext context, boolean sleeving) { + TransportTaskCreateReqDTO request = baseTask(context, sleeving ? "日计划管芯出库" : "日计划管芯抓取", + sleeving ? sleevingOutAcsType : stockingPickAcsType, + sleeving ? CoreTubeHandleCodeConstants.CORE_TUBE_SLEEVING_TASK + : CoreTubeHandleCodeConstants.CORE_TUBE_STOCKING_TASK); + request.setPointCode1(tube.getCurrentLocationCode()); + request.setPointCode2(context.getTargetPointCode()); + request.setVehicleCode(tube.getCoreTubeCode()); + request.setMaterialId(candidate.getMaterialId()); + request.setMaterialCode(candidate.getMaterialCode()); + return request; + } + + /** 构造任务公共字段。 */ + private TransportTaskCreateReqDTO baseTask(CoreTubeTaskContext context, String taskName, String acsType, + String handleCode) { + TransportTaskCreateReqDTO request = new TransportTaskCreateReqDTO(); + request.setTaskName(taskName); + request.setOwnerService(OWNER_SERVICE); + request.setBizType(context.getBizType()); + request.setHandleCode(handleCode); + request.setAcsTaskType(acsType); + request.setAgvSystemType(agvSystemType); + request.setIsAutoIssue("1"); + request.setIsCreateFinish(true); + request.setRequestParam(JsonUtils.toJsonString(context)); + return request; + } + + /** 创建任务并处理响应不确定场景。 */ + private Long createTask(TransportTaskCreateReqDTO request, String bizType, String bizId) { + request.setBizType(bizType); + request.setBizId(bizId); + CommonResult result = transportTaskApi.createTransportTask(request); + if (result != null && result.isSuccess() && result.getData() != null) { + return result.getData(); + } + TaskInfoDTO existing = getUnfinished(bizType, bizId); + if (existing != null) { + return existing.getTaskId(); + } + throw new IllegalStateException("创建现场任务失败:" + (result == null ? "无响应" : result.getMsg())); + } + + /** 查询未完成业务任务。 */ + private TaskInfoDTO getUnfinished(String bizType, String bizId) { + CommonResult result = transportTaskApi.getUnfinishedTaskByBiz(OWNER_SERVICE, bizType, bizId); + return result != null && result.isSuccess() ? result.getData() : null; + } + + /** 判断目标物料是否正在备货。 */ + private boolean hasStockingTask(Long materialId) { + if (getUnfinished(CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN.name(), "MATERIAL:" + materialId) != null) { + return true; + } + CommonResult> result = transportTaskApi.getRunningTaskByMaterialId(materialId, OWNER_SERVICE); + return result != null && result.isSuccess() && result.getData() != null + && result.getData().stream().anyMatch(task -> + CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN.name().equals(task.getBizType()) + || CoreTubeTaskBizTypeEnum.CORE_TUBE_STOCKING_PICK.name().equals(task.getBizType())); + } + + /** 处理任务完成。 */ + @Override + @Transactional(rollbackFor = Exception.class) + public void handleFinished(Long taskId, boolean sleeving) { + TaskInfoDTO task = getTask(taskId); + CoreTubeTaskContext context = JsonUtils.parseObject(task.getRequestParam(), CoreTubeTaskContext.class); + if (CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN.name().equals(context.getBizType()) + || CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_OUT.name().equals(context.getBizType())) { + int affected = stockingIvtMapper.completeVehicleMove(context.getSourcePointId(), + context.getTargetPointId(), context.getVehicleCode(), OPERATOR); + if (affected == 0) { + return; + } + if (affected != 2) { + throw new IllegalStateException("托盘点位转移状态不完整,taskId=" + taskId); + } + int locationType = CoreTubeTaskBizTypeEnum.CORE_TUBE_PALLET_IN.name().equals(context.getBizType()) + ? CoreTubeLocationTypeEnum.STOCKING_DOCK.getCode() + : CoreTubeLocationTypeEnum.STOCKING_CACHE.getCode(); + coreTubeMapper.updateVehicleLocation(context.getVehicleCode(), locationType, + context.getTargetPointId(), context.getTargetPointCode(), OPERATOR); + return; + } + int stage = sleeving ? CoreTubeStageEnum.SLEEVING.getCode() : CoreTubeStageEnum.CORE_WAREHOUSE.getCode(); + int locationType = sleeving ? CoreTubeLocationTypeEnum.EQUIPMENT.getCode() + : CoreTubeLocationTypeEnum.CORE_WAREHOUSE.getCode(); + if (coreTubeMapper.completeTubeTask(context.getCoreTubeId(), taskId, stage, + sleeving ? CoreTubeStatusEnum.PROCESSING.getCode() : CoreTubeStatusEnum.AVAILABLE.getCode(), + locationType, context.getTargetPointId(), context.getTargetPointCode(), true, OPERATOR) == 1) { + if (sleeving) { + dailyPlanScheduleService.increaseSleevedQuantity(context.getClaimToken(), + context.getDailyPlanId(), 1, OPERATOR); + } else { + stockingIvtMapper.clearPaperVehicleCoreTube(context.getCoreTubeId(), OPERATOR); + dailyPlanScheduleService.increaseStockedQuantity(context.getClaimToken(), + context.getDailyPlanId(), 1, OPERATOR); + } + } + } + + /** 处理任务取消。 */ + @Override + @Transactional(rollbackFor = Exception.class) + public void handleCancelled(Long taskId, boolean sleeving) { + TaskInfoDTO task = getTask(taskId); + CoreTubeTaskContext context = JsonUtils.parseObject(task.getRequestParam(), CoreTubeTaskContext.class); + if (context.getCoreTubeId() == null) { + return; + } + int affected = coreTubeMapper.cancelTubeTask(context.getCoreTubeId(), taskId, + sleeving ? CoreTubeStageEnum.CORE_WAREHOUSE.getCode() : CoreTubeStageEnum.STOCKING_AREA.getCode(), + OPERATOR); + if (affected == 1) { + dailyPlanScheduleService.releaseClaim(context.getClaimToken(), OPERATOR); + } + } + + /** 查询任务详情。 */ + private TaskInfoDTO getTask(Long taskId) { + CommonResult result = transportTaskApi.getTaskById(taskId); + if (result == null || !result.isSuccess() || result.getData() == null) { + throw new IllegalStateException("管芯任务不存在,taskId=" + taskId); + } + return result.getData(); + } +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleCandidate.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleCandidate.java index 395e4c66..1733a405 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleCandidate.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleCandidate.java @@ -22,6 +22,8 @@ public class DailyPlanScheduleCandidate { private String materialSpec; /** 本轮建议处理数量。 */ private Integer suggestedQuantity; + /** 当前作业尚需处理数量,用于整托盘择优。 */ + private Integer remainingQuantity; /** 日计划乐观锁版本号。 */ private Integer version; /** 本轮使用的策略模式。 */ diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleServiceImpl.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleServiceImpl.java index ab52d4fb..96ce945d 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleServiceImpl.java +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/service/dailyplan/DailyPlanScheduleServiceImpl.java @@ -107,7 +107,7 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { } List result = new ArrayList<>(ordered.size()); for (DailyPlanDO plan : ordered) { - result.add(convertCandidate(plan, mode.getCode())); + result.add(convertCandidate(plan, mode.getCode(), type)); } return result; } @@ -176,7 +176,7 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { } catch (DuplicateKeyException ex) { throw exception(DAILY_PLAN_CLAIM_CONFLICT); } - DailyPlanScheduleCandidate candidate = convertCandidate(plan, strategyMode); + DailyPlanScheduleCandidate candidate = convertCandidate(plan, strategyMode, type); candidate.setSuggestedQuantity(quantity); candidate.setClaimToken(claim.getClaimToken()); candidate.setClaimExpireTime(expireTime); @@ -184,7 +184,8 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { } /** 将日计划转换为调度候选。 */ - private DailyPlanScheduleCandidate convertCandidate(DailyPlanDO plan, Integer strategyMode) { + private DailyPlanScheduleCandidate convertCandidate(DailyPlanDO plan, Integer strategyMode, + DailyPlanStrategyTypeEnum type) { DailyPlanScheduleCandidate candidate = new DailyPlanScheduleCandidate(); candidate.setDailyPlanId(plan.getDailyPlanId()); candidate.setPlanCode(plan.getPlanCode()); @@ -193,6 +194,9 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { candidate.setMaterialName(plan.getMaterialName()); candidate.setMaterialSpec(plan.getMaterialSpec()); candidate.setSuggestedQuantity(1); + int total = Math.addExact(plan.getPlanQty(), plan.getAppendQty()); + int progress = type == DailyPlanStrategyTypeEnum.STOCKING ? plan.getStockedQty() : plan.getSleevedQty(); + candidate.setRemainingQuantity(total - progress); candidate.setVersion(plan.getVersion()); candidate.setStrategyMode(strategyMode); return candidate; @@ -204,6 +208,10 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { public void confirmTaskCreated(String claimToken, String operator) { DailyPlanClaimDO claim = getClaimForUpdate(claimToken); validateActiveClaim(claim); + if (!claim.getTaskCreated() + && dailyPlanClaimMapper.markTaskCreated(claimToken, normalizedOperator(operator)) != 1) { + throw exception(DAILY_PLAN_CLAIM_INVALID); + } DailyPlanStrategyTypeEnum type = DailyPlanStrategyTypeEnum.getByCode(claim.getStrategyType()); if (type == null) { throw exception(DAILY_PLAN_STRATEGY_NOT_EXISTS); @@ -353,7 +361,7 @@ public class DailyPlanScheduleServiceImpl implements DailyPlanScheduleService { private void validateActiveClaim(DailyPlanClaimDO claim) { if (!Integer.valueOf(CLAIM_ACTIVE).equals(claim.getClaimStatus()) || claim.getActiveFlag() == null - || !claim.getExpireTime().isAfter(LocalDateTime.now())) { + || !claim.getTaskCreated() && !claim.getExpireTime().isAfter(LocalDateTime.now())) { throw exception(DAILY_PLAN_CLAIM_INVALID); } } diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeSleevingTask.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeSleevingTask.java new file mode 100644 index 00000000..2101d2fc --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeSleevingTask.java @@ -0,0 +1,26 @@ +package cn.code.nl.module.lms.task; + +import cn.code.nl.framework.execute.core.AbstractTask; +import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO; +import cn.code.nl.module.lms.enums.CoreTubeHandleCodeConstants; +import cn.code.nl.module.lms.service.coretube.CoreTubeTaskDispatchService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +/** 管芯库单根出库任务回调。 */ +@Component(CoreTubeHandleCodeConstants.CORE_TUBE_SLEEVING_TASK) +public class CoreTubeSleevingTask extends AbstractTask { + + @Resource + private CoreTubeTaskDispatchService dispatchService; + + @Override + public void doHandleFinish(TaskExecuteDTO taskExecuteDTO) { + dispatchService.handleFinished(taskExecuteDTO.getTaskId(), true); + } + + @Override + public void doHandleCancel(TaskExecuteDTO taskExecuteDTO) { + dispatchService.handleCancelled(taskExecuteDTO.getTaskId(), true); + } +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeStockingTask.java b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeStockingTask.java new file mode 100644 index 00000000..14710d87 --- /dev/null +++ b/nl-module-lms/nl-module-lms-server/src/main/java/cn/code/nl/module/lms/task/CoreTubeStockingTask.java @@ -0,0 +1,26 @@ +package cn.code.nl.module.lms.task; + +import cn.code.nl.framework.execute.core.AbstractTask; +import cn.code.nl.framework.execute.core.dto.TaskExecuteDTO; +import cn.code.nl.module.lms.enums.CoreTubeHandleCodeConstants; +import cn.code.nl.module.lms.service.coretube.CoreTubeTaskDispatchService; +import jakarta.annotation.Resource; +import org.springframework.stereotype.Component; + +/** 备货区托盘搬运及管芯抓取任务回调。 */ +@Component(CoreTubeHandleCodeConstants.CORE_TUBE_STOCKING_TASK) +public class CoreTubeStockingTask extends AbstractTask { + + @Resource + private CoreTubeTaskDispatchService dispatchService; + + @Override + public void doHandleFinish(TaskExecuteDTO taskExecuteDTO) { + dispatchService.handleFinished(taskExecuteDTO.getTaskId(), false); + } + + @Override + public void doHandleCancel(TaskExecuteDTO taskExecuteDTO) { + dispatchService.handleCancelled(taskExecuteDTO.getTaskId(), false); + } +} diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/coretube/CoreTubeMapper.xml b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/coretube/CoreTubeMapper.xml index 6fb46fb0..8b5c461d 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/coretube/CoreTubeMapper.xml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/coretube/CoreTubeMapper.xml @@ -48,4 +48,88 @@ #{tube.currentLocationType}, #{tube.currentLocationId}, #{tube.currentLocationCode}, 0, #{tube.creator}, #{tube.updater}) + + + + + + + UPDATE lms_core_tube + SET stage = #{newStage}, status = 2, + reserved_daily_plan_id = #{dailyPlanId}, reserved_claim_token = #{claimToken}, + reserve_expire_time = #{expireTime}, updater = #{updater}, version = version + 1 + WHERE core_tube_id = #{coreTubeId} + AND stage = #{expectedStage} AND status = 1 + AND reserved_task_id IS NULL AND deleted = b'0' + + + + UPDATE lms_core_tube + SET reserved_task_id = #{taskId}, status = 3, updater = #{updater}, version = version + 1 + WHERE core_tube_id = #{coreTubeId} + AND status = 2 AND reserved_task_id IS NULL AND deleted = b'0' + + + + UPDATE lms_core_tube + SET stage = #{stage}, status = 1, + reserved_daily_plan_id = NULL, reserved_claim_token = NULL, + reserve_expire_time = NULL, updater = #{updater}, version = version + 1 + WHERE core_tube_id = #{coreTubeId} + AND reserved_claim_token = #{claimToken} + AND reserved_task_id IS NULL AND deleted = b'0' + + + + UPDATE lms_core_tube + SET stage = #{stage}, status = #{status}, + current_location_type = #{locationType}, current_location_id = #{locationId}, + current_location_code = #{locationCode}, + vehicle_code = CASE WHEN #{clearVehicle} THEN NULL ELSE vehicle_code END, + row_num = CASE WHEN #{clearVehicle} THEN NULL ELSE row_num END, + col_num = CASE WHEN #{clearVehicle} THEN NULL ELSE col_num END, + active_slot = CASE WHEN #{clearVehicle} THEN NULL ELSE active_slot END, + reserved_daily_plan_id = NULL, reserved_claim_token = NULL, + reserved_task_id = NULL, reserve_expire_time = NULL, + updater = #{updater}, version = version + 1 + WHERE core_tube_id = #{coreTubeId} + AND reserved_task_id = #{taskId} AND deleted = b'0' + + + + UPDATE lms_core_tube + SET stage = #{stage}, status = 1, + reserved_daily_plan_id = NULL, reserved_claim_token = NULL, + reserved_task_id = NULL, reserve_expire_time = NULL, + updater = #{updater}, version = version + 1 + WHERE core_tube_id = #{coreTubeId} + AND reserved_task_id = #{taskId} AND deleted = b'0' + + + + UPDATE lms_core_tube + SET current_location_type = #{locationType}, current_location_id = #{locationId}, + current_location_code = #{locationCode}, updater = #{updater}, version = version + 1 + WHERE vehicle_code = #{vehicleCode} AND active_slot = 1 AND deleted = b'0' + diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanClaimMapper.xml b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanClaimMapper.xml index f5ee6d01..3998a2d5 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanClaimMapper.xml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanClaimMapper.xml @@ -4,17 +4,17 @@ claim_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version, progress_qty, version, - claim_status, active_flag, expire_time, confirmed_time, operator, + claim_status, active_flag, task_created, expire_time, confirmed_time, operator, creator, create_time, updater, update_time, deleted, tenant_id INSERT INTO lms_daily_plan_claim (claim_id, claim_token, daily_plan_id, strategy_type, claimed_qty, plan_version, progress_qty, version, - claim_status, active_flag, expire_time, operator, creator, updater) + claim_status, active_flag, task_created, expire_time, operator, creator, updater) VALUES (#{claim.claimId}, #{claim.claimToken}, #{claim.dailyPlanId}, #{claim.strategyType}, - #{claim.claimedQty}, #{claim.planVersion}, #{claim.progressQty}, 0, 0, 1, #{claim.expireTime}, + #{claim.claimedQty}, #{claim.planVersion}, #{claim.progressQty}, 0, 0, 1, b'0', #{claim.expireTime}, #{claim.operator}, #{claim.operator}, #{claim.operator}) @@ -35,6 +35,13 @@ UPDATE lms_daily_plan_claim SET claim_status = 1, active_flag = NULL, confirmed_time = NOW(), updater = #{updater}, version = version + 1 WHERE claim_id = #{claimId} AND version = #{version} AND claim_status = 0 AND active_flag = 1 + AND (task_created = b'1' OR expire_time > NOW(6)) AND deleted = b'0' + + + + UPDATE lms_daily_plan_claim + SET task_created = b'1', updater = #{updater}, version = version + 1 + WHERE claim_token = #{claimToken} AND claim_status = 0 AND active_flag = 1 AND expire_time > NOW(6) AND deleted = b'0' @@ -54,7 +61,8 @@ UPDATE lms_daily_plan_claim SET claim_status = 3, active_flag = NULL, updater = #{updater} - WHERE claim_status = 0 AND active_flag = 1 AND expire_time <= #{now} AND deleted = b'0' + WHERE claim_status = 0 AND active_flag = 1 AND task_created = b'0' + AND expire_time <= #{now} AND deleted = b'0' diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanMapper.xml b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanMapper.xml index a7ebc8a7..5c2ffb23 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanMapper.xml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/dailyplan/DailyPlanMapper.xml @@ -68,7 +68,7 @@ AND claim.tenant_id = lms_daily_plan.tenant_id AND claim.strategy_type = #{strategyType} AND claim.claim_status = 0 AND claim.active_flag = 1 - AND claim.expire_time > NOW(6) AND claim.deleted = b'0' + AND (claim.task_created = b'1' OR claim.expire_time > NOW(6)) AND claim.deleted = b'0' ) FOR UPDATE @@ -124,7 +124,8 @@ WHERE claim.daily_plan_id = lms_daily_plan.daily_plan_id AND claim.tenant_id = lms_daily_plan.tenant_id AND claim.strategy_type = 1 AND claim.claim_status = 0 - AND claim.active_flag = 1 AND claim.expire_time > NOW(6) AND claim.deleted = b'0' + AND claim.active_flag = 1 + AND (claim.task_created = b'1' OR claim.expire_time > NOW(6)) AND claim.deleted = b'0' ) ORDER BY sort_seq ASC, daily_plan_id ASC @@ -142,7 +143,8 @@ WHERE claim.daily_plan_id = lms_daily_plan.daily_plan_id AND claim.tenant_id = lms_daily_plan.tenant_id AND claim.strategy_type = 2 AND claim.claim_status = 0 - AND claim.active_flag = 1 AND claim.expire_time > NOW(6) AND claim.deleted = b'0' + AND claim.active_flag = 1 + AND (claim.task_created = b'1' OR claim.expire_time > NOW(6)) AND claim.deleted = b'0' ) ORDER BY sort_seq ASC, daily_plan_id ASC diff --git a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/stockingivt/StockingIvtMapper.xml b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/stockingivt/StockingIvtMapper.xml index 43fe0648..af702ded 100644 --- a/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/stockingivt/StockingIvtMapper.xml +++ b/nl-module-lms/nl-module-lms-server/src/main/resources/mapper/stockingivt/StockingIvtMapper.xml @@ -120,4 +120,73 @@ #{tube.materialCode}, #{tube.materialName}, 1, #{tube.creator}, #{tube.updater}) + + UPDATE lms_base_papervehicle + SET core_tube_id = NULL, + core_tube_code = NULL, + material_code = NULL, + material_name = NULL, + qty = 0, + updater = #{updater} + WHERE core_tube_id = #{coreTubeId} + + + + + + + + + + + + UPDATE lms_ivt_stockingivt + SET vehicle_code = CASE WHEN ivt_id = #{sourcePointId} THEN NULL ELSE #{vehicleCode} END, + ivt_status = CASE WHEN ivt_id = #{sourcePointId} THEN '1' ELSE '2' END, + updater = #{updater} + WHERE (ivt_id = #{sourcePointId} AND vehicle_code = #{vehicleCode}) + OR (ivt_id = #{targetPointId} AND ivt_status = '1') + + diff --git a/sql/mysql/lms_core_tube.sql b/sql/mysql/lms_core_tube.sql index c9f0732d..f8bc88d2 100644 --- a/sql/mysql/lms_core_tube.sql +++ b/sql/mysql/lms_core_tube.sql @@ -48,6 +48,15 @@ PREPARE lms_core_tube_stmt FROM @lms_core_tube_ddl; EXECUTE lms_core_tube_stmt; DEALLOCATE PREPARE lms_core_tube_stmt; +SET @lms_core_tube_ddl = IF( + EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() + AND table_name = 'lms_daily_plan_claim' AND column_name = 'task_created'), + 'SELECT 1', + 'ALTER TABLE lms_daily_plan_claim ADD COLUMN task_created BIT(1) NOT NULL DEFAULT b''0'' COMMENT ''是否已创建现场任务'' AFTER active_flag'); +PREPARE lms_core_tube_stmt FROM @lms_core_tube_ddl; +EXECUTE lms_core_tube_stmt; +DEALLOCATE PREPARE lms_core_tube_stmt; + SET @lms_core_tube_ddl = IF( EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'lms_base_papervehicle' AND column_name = 'core_tube_code'), diff --git a/sql/mysql/lms_daily_plan.sql b/sql/mysql/lms_daily_plan.sql index ff71a9f2..082229c7 100644 --- a/sql/mysql/lms_daily_plan.sql +++ b/sql/mysql/lms_daily_plan.sql @@ -81,6 +81,7 @@ CREATE TABLE IF NOT EXISTS `lms_daily_plan_claim` ( `version` int NOT NULL DEFAULT 0 COMMENT '领取乐观锁版本号', `claim_status` tinyint NOT NULL DEFAULT 0 COMMENT '领取状态:0执行中,1已确认,2已释放,3已过期', `active_flag` tinyint DEFAULT 1 COMMENT '有效领取唯一标记,终态置空', + `task_created` bit(1) NOT NULL DEFAULT b'0' COMMENT '是否已创建现场任务', `expire_time` datetime(6) NOT NULL COMMENT '租约过期时间', `confirmed_time` datetime DEFAULT NULL COMMENT '确认时间', `operator` varchar(64) NOT NULL COMMENT '领取人/执行器', @@ -125,6 +126,14 @@ SET @lms_daily_plan_ddl = IF( PREPARE lms_daily_plan_stmt FROM @lms_daily_plan_ddl; EXECUTE lms_daily_plan_stmt; DEALLOCATE PREPARE lms_daily_plan_stmt; +SET @lms_daily_plan_ddl = IF( + EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() + AND table_name = 'lms_daily_plan_claim' AND column_name = 'task_created'), + 'SELECT 1', + 'ALTER TABLE lms_daily_plan_claim ADD COLUMN task_created BIT(1) NOT NULL DEFAULT b''0'' COMMENT ''是否已创建现场任务'' AFTER active_flag'); +PREPARE lms_daily_plan_stmt FROM @lms_daily_plan_ddl; +EXECUTE lms_daily_plan_stmt; +DEALLOCATE PREPARE lms_daily_plan_stmt; SET @lms_daily_plan_ddl = IF( EXISTS (SELECT 1 FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = 'lms_daily_plan_claim' AND column_name = 'expire_time'