From 02432faa174d181633f98d2e454fbcfb0a9753df Mon Sep 17 00:00:00 2001 From: gongbaoxiong <751575283@qq.com> Date: Wed, 10 Jun 2026 17:56:14 +0800 Subject: [PATCH] =?UTF-8?q?opt:=E4=B8=80=E6=9C=9F=E5=86=85=E5=AE=B9?= =?UTF-8?q?=E4=BC=98=E5=8C=96=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- acs/nladmin-system/nlsso-server/pom.xml | 14 + .../src/main/java/org/nl/acs/AcsConfig.java | 16 + .../run/OneNDCSocketConnectionAutoRun.java | 6 +- .../agv/ndcone/AgvNdcOneDeviceDriver.java | 213 ++++++++-- .../java/org/nl/acs/history/ErrorUtil.java | 57 +-- .../service/impl/InstructionServiceImpl.java | 73 +++- .../org/nl/acs/task/service/TaskService.java | 7 +- .../task/service/impl/TaskServiceImpl.java | 355 ++++++++++++++--- .../controller/dict/SysDictController.java | 14 + .../controller/param/SysParamController.java | 8 + .../system/service/dict/ISysDictService.java | 9 + .../dict/dao/mapper/SysDictMapper.java | 6 + .../service/dict/impl/SysDictServiceImpl.java | 25 +- .../service/param/ISysParamService.java | 2 + .../param/impl/SysParamServiceImpl.java | 44 +++ .../service/quartz/task/AutoCreateInst.java | 371 ++++-------------- acs/nladmin-ui/src/router/routers.js | 13 + .../views/acs/history/taskRecord/index.vue | 31 ++ .../src/views/acs/history/taskSheet/index.vue | 330 ++++++++++++---- .../src/views/system/param/index.vue | 36 +- .../src/views/system/param/param.js | 40 +- .../src/views/system/param/stationDialog.vue | 150 +++++++ .../src/views/system/param/tubeDialog2.vue | 136 +++++++ .../service/dto/StrategyStructParam.java | 5 + .../service/impl/StructattrServiceImpl.java | 14 +- .../service/impl/InBillServiceImpl.java | 2 + .../service/impl/WmsToIWmsServiceImpl.java | 3 +- 27 files changed, 1500 insertions(+), 480 deletions(-) create mode 100644 acs/nladmin-ui/src/views/system/param/stationDialog.vue create mode 100644 acs/nladmin-ui/src/views/system/param/tubeDialog2.vue diff --git a/acs/nladmin-system/nlsso-server/pom.xml b/acs/nladmin-system/nlsso-server/pom.xml index 4f4c653..281e758 100644 --- a/acs/nladmin-system/nlsso-server/pom.xml +++ b/acs/nladmin-system/nlsso-server/pom.xml @@ -131,6 +131,20 @@ test + + + org.powermock + powermock-module-junit4 + 2.0.9 + test + + + org.powermock + powermock-api-mockito2 + 2.0.9 + test + + org.reflections reflections diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/AcsConfig.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/AcsConfig.java index 79dce40..d24fbcf 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/AcsConfig.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/AcsConfig.java @@ -8,6 +8,12 @@ public interface AcsConfig { String ONEFORKAGV = "oneforkagv"; //同一站点运行最大任务数 String ONEPOINTMAXTASK = "onePointMaxTask"; + //工作时长 + String WORKINGTIME = "workingTime"; + //飞书发送时间8:00-22:00 + String FEISHUSENDTIME = "feiShuSendTime"; + //飞书发送频次(分钟) + String FEISHUSENDFRE = "feiShuSendFre"; //同一任务创建最大指令数 String MAXINSTNUMBER = "maxInstNumber"; //同一任务创建最大RT车指令数 @@ -65,4 +71,14 @@ public interface AcsConfig { String LOGLEVEL = "log_level"; String ELECTRIC ="electric"; + + + + String ELECTRIC2 ="electric2"; + + String ELECTRIC_BEGIN ="electric_begin"; + + String ELECTRIC_END ="electric_end"; + + String IS_ATUO_ELECTRIC ="is_atuo_electric"; } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/auto/run/OneNDCSocketConnectionAutoRun.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/auto/run/OneNDCSocketConnectionAutoRun.java index b530d63..fe522de 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/auto/run/OneNDCSocketConnectionAutoRun.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/auto/run/OneNDCSocketConnectionAutoRun.java @@ -119,7 +119,7 @@ public class OneNDCSocketConnectionAutoRun extends AbstractAutoRunnable { StringBuffer bs1 = new StringBuffer("0"); bs.append(temp < 16 ? bs1.append(Integer.toHexString(temp)) : Integer.toHexString(temp)); } - + //87cd000800140001007300100001020300730001000000000000004a boolean flag = false; if (arr[8] * 256 + arr[9] == 0x73) { byte[] data = null; @@ -288,11 +288,11 @@ public class OneNDCSocketConnectionAutoRun extends AbstractAutoRunnable { data = NDCAgvService.sendAgvOneModeInst(phase, index, 0); } } - } else { + }else { //上报异常信息 //(不需要WCS反馈) if (phase == 0x67) { - device = deviceAppService.findDeviceByCode(Integer.toString(arr[27])); + device = deviceAppService.findDeviceByCode(Integer.toString(agvaddr)); } else { device = deviceAppService.findDeviceByCode(Integer.toString(arr[20])); } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/device_driver/basedriver/agv/ndcone/AgvNdcOneDeviceDriver.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/device_driver/basedriver/agv/ndcone/AgvNdcOneDeviceDriver.java index 57ae399..8ce5672 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/device_driver/basedriver/agv/ndcone/AgvNdcOneDeviceDriver.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/device_driver/basedriver/agv/ndcone/AgvNdcOneDeviceDriver.java @@ -1,22 +1,26 @@ package org.nl.acs.device_driver.basedriver.agv.ndcone; +import cn.hutool.core.date.DateTime; import cn.hutool.core.date.DateUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import lombok.Data; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; +import org.apache.commons.lang3.StringUtils; +import org.nl.acs.AcsConfig; import org.nl.acs.agv.server.NDCAgvService; import org.nl.acs.auto.run.OneNDCSocketConnectionAutoRun; import org.nl.acs.device.domain.Device; import org.nl.acs.device.service.DeviceService; import org.nl.acs.device_driver.DeviceDriver; import org.nl.acs.device_driver.driver.AbstractDeviceDriver; -import org.nl.acs.ext.wms.data.one.feedBackTaskStatus.FeedBackTaskStatusRequest; import org.nl.acs.ext.wms.service.AcsToWmsService; import org.nl.acs.ext.wms.service.impl.AcsToWmsServiceImpl; +import org.nl.acs.history.ErrorUtil; import org.nl.acs.instruction.domain.Instruction; import org.nl.acs.instruction.service.InstructionService; import org.nl.acs.instruction.service.impl.InstructionServiceImpl; @@ -34,8 +38,11 @@ import org.nl.system.service.lucene.LuceneExecuteLogService; import org.nl.system.service.param.ISysParamService; import org.nl.system.service.param.impl.SysParamServiceImpl; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ThreadPoolExecutor; /** @@ -74,6 +81,16 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic int is_have = 0; //是否有货 int error = 0; //车辆故障 + // 飞书消息去重缓存:key为设备代码+错误类型,value为最后发送时间戳 + private final ConcurrentHashMap feiShuErrorCache = new ConcurrentHashMap<>(); + /** + * 缓存的参数值,避免频繁查询数据库 + */ + private volatile String feiShuSendTime = "8:00-22:00"; + private volatile String feiShuSendFre = "2"; + private volatile long lastParamLoadTime = 0; + private static final long PARAM_CACHE_TIMEOUT = 600000; // 参数缓存超时时间:120秒 + String transportOrder = ""; boolean isCharge = false; String message = null; @@ -83,6 +100,7 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic public synchronized void processSocket(int[] arr) throws Exception { device_code = this.getDeviceCode(); byte[] data = null; + //阶段值 phase = arr[16] * 256 + arr[17]; // agv任务号 int index = arr[12] * 256 + arr[13]; @@ -116,20 +134,29 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic String old_device_code = null; String emptyNum = null; String device_code = null; - + //设备故障 if (phase == 0x67) { - //todo 故障信息 - if (arr[18] * 256 + arr[19] == 0) { - + try { + if (ikey != 0) { + data = ndcAgvService.sendAgvOneModeInst(phase, index, 0, 0, 0, 0, 0); + Map error = ErrorUtil.getAgvErrorMsg(ikey); + String code = error.get("code"); + String info = error.get("info"); + log.error("车辆" + agvaddr + "故障:故障码:" + error + ",ikey为:" + ikey + ",已解析报警信息:code:" + code + ",info" + info); + //通过ikey + if (StringUtils.isNotBlank(info)) { + sendFeiShuAlert(info); + } + // FeedBackTaskStatusRequest request = new FeedBackTaskStatusRequest(); + // request.setDevice_code(this.device_code); + // request.setState("故障"); + // acsToWmsService.notify(request); + } + } catch (Exception e) { + log.error("发送飞书报警消息失败", e); } - FeedBackTaskStatusRequest request = new FeedBackTaskStatusRequest(); - request.setDevice_code(this.device_code); - request.setState("故障"); - acsToWmsService.notify(request); - data = ndcAgvService.sendAgvOneModeInst(phase, index, 0, 0, 0, 0, 0); } TaskDto task = new TaskDto(); - if (ObjectUtil.isNotEmpty(inst)) { task = taskService.findById(inst.getTask_id()); } @@ -141,12 +168,8 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic transportOrder = inst.getTask_code(); //车辆分配任务时 状态为1 执行中 task.setTask_status("1"); - //车辆执行任务开始计时字段 - if (StrUtil.isEmpty(task.getTo_x())) { - task.setTo_x(DateUtil.now()); - } //添加车号 - if (StrUtil.isEmpty(task.getCar_no())) { + if (StringUtils.isBlank(task.getCar_no())) { task.setCar_no(String.valueOf(carno)); } taskserver.update(task); @@ -156,22 +179,23 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic //到达取货点 //(需要WCS反馈) } else if (phase == 0x03) { - inst.setExecute_status("1"); instructionService.update(inst); data = ndcAgvService.sendAgvOneModeInst(phase, index, 0); flag = true; - } else if (phase == 0x04) { data = getData(data, index, inst, task); //取货完毕 //(需要WCS反馈) } else if (phase == 0x05) { - task.setTask_status("8"); - taskserver.update(task); - data = ndcAgvService.sendAgvOneModeInst(phase, index, 0); - log.info("agv进入" + device_code + "取货完成"); - flag = true; + data = ndcAgvService.sendAgvOneModeInst(phase, index, 0); + task.setTask_status("8"); + //车辆执行任务开始计时字段 + if (StringUtils.isBlank(task.getTo_x())) { + task.setTo_x(DateUtil.now()); + } + taskserver.updateEntity(task); + flag = true; } else if (phase == 0x06) { JSONObject feed_jo = new JSONObject(); feed_jo.put("task_id", task.getExt_task_id()); @@ -183,7 +207,7 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic acsToWmsService.feedTaskStatus(ja); Instruction inst1 = instructionService.findBytaskCode(inst.getTask_id()); log.info("二次分配指令终点是{}",inst1.getNext_point_code()); - if(inst1.getNext_point_code().equals("CKFPW")){ + if ("CKFPW".equals(inst1.getNext_point_code())) { throw new BadRequestException("没有出库点位了请释放"); } data=ndcAgvService.sendAgvTwoModeInst(phase,index,0,inst1); @@ -194,9 +218,9 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic data = ndcAgvService.sendAgvOneModeInst(phase, index, 0); flag = true; } else if (phase == 0x09) { + log.info("agv进入" + this.device_code + "放货完成" + task.getTo_x()); data = ndcAgvService.sendAgvOneModeInst(phase, index, 0); flag = true; - } //到达位置点 //(需要WCS反馈) @@ -254,4 +278,143 @@ public class AgvNdcOneDeviceDriver extends AbstractDeviceDriver implements Devic return data; } + /** + * 发送飞书报警消息 + * + * @param errorMessage 错误消息 + */ + private void sendFeiShuAlert(String errorMessage) { + try { + loadTaskCountParamsIfNeeded(); + // 1. 检查是否在允许的工作时间范围内 + if (StrUtil.isNotBlank(feiShuSendTime) && feiShuSendTime.contains("-")) { + // 解析时间格式:"8:00-22:00" + String[] timeRange = feiShuSendTime.split("-"); + if (timeRange.length == 2) { + DateTime now = DateUtil.date(); + // 将当前时间转换为分钟数进行比较 + int nowMinutes = DateUtil.hour(now, true) * 60 + DateUtil.minute(now); + // 解析开始时间 + String[] startTime = timeRange[0].trim().split(":"); + int startHour = Integer.parseInt(startTime[0]); + int startMinute = startTime.length > 1 ? Integer.parseInt(startTime[1]) : 0; + int startMinutes = startHour * 60 + startMinute; + // 解析结束时间 + String[] endTime = timeRange[1].trim().split(":"); + int endHour = Integer.parseInt(endTime[0]); + int endMinute = endTime.length > 1 ? Integer.parseInt(endTime[1]) : 0; + int endMinutes = endHour * 60 + endMinute; + // 判断当前时间是否在工作时间内 + if (nowMinutes < startMinutes || nowMinutes >= endMinutes) { +// log.info("当前时间{}不在工作时间范围内({}),跳过发送飞书消息", +// DateUtil.formatTime(now), feiShuSendTime); + return; + } + } + } + // 2. 重复消息筛选:5分钟内相同设备的相同错误不重复发送 + String cacheKey = this.getDeviceCode() + errorMessage; + long currentTime = System.currentTimeMillis(); + Long lastSendTime = feiShuErrorCache.get(cacheKey); + if (lastSendTime != null) { + long diffTime = currentTime - lastSendTime; + // 距离上次发送不足2分钟,过滤掉该消息 + int feiShuSendFreMin = Integer.parseInt(feiShuSendFre); + if (diffTime < feiShuSendFreMin * 60000L) { + log.debug("设备{}的{}在5分钟内已有过提醒,过滤掉本次重复提醒(距今{}ms)", + this.getDeviceCode(), errorMessage, diffTime); + return; + } + } + //构建飞书 webhook 请求参数(使用 Post 富文本格式) + JSONObject requestBody = new JSONObject(); + requestBody.put("msg_type", "post"); + // 构建 Post 内容 + JSONObject content = new JSONObject(); + JSONObject post = new JSONObject(); + JSONObject zh_cn = new JSONObject(); + // 设置标题 + zh_cn.put("title", "AMR报警"); + // 设置内容 + JSONArray contentArray = new JSONArray(); + JSONArray contentRow1 = new JSONArray(); + // 第一行:报警信息: 【AMR故障报警】 + JSONObject tagText1 = new JSONObject(); + tagText1.put("tag", "text"); + tagText1.put("text", "报警信息: 【AMR故障报警】"); + // 第二行:设备编码 + JSONObject tagText2 = new JSONObject(); + tagText2.put("tag", "text"); + tagText2.put("text", "\n设备编码:" + this.getDeviceCode() + "号车"); + // 第三行:故障信息 + JSONObject tagText3 = new JSONObject(); + tagText3.put("tag", "text"); + tagText3.put("text", "\n故障信息:" + errorMessage); + // 第四行:报警时间 + JSONObject tagText4 = new JSONObject(); + tagText4.put("tag", "text"); + tagText4.put("text", "\n报警时间:" + DateUtil.now()); + // 第五行:请及时处理! + JSONObject tagText5 = new JSONObject(); + tagText5.put("tag", "text"); + tagText5.put("text", "\n请及时处理!"); + // 将所有内容行添加到内容数组 + contentArray.add(contentRow1); + contentRow1.add(tagText1); + contentRow1.add(tagText2); + contentRow1.add(tagText3); + contentRow1.add(tagText4); + contentRow1.add(tagText5); + zh_cn.put("content", contentArray); + post.put("zh_cn", zh_cn); + content.put("post", post); + requestBody.put("content", content); + String feiShuUrl = "https://open.feishu.cn/open-apis/bot/v2/hook/c3fcb100-72e0-48e6-bdf6-e266e67858a1"; + // 5. 发送 HTTP 请求到飞书机器人 + String response = HttpRequest.post(feiShuUrl) + .header("Content-Type", "application/json") + .body(requestBody.toJSONString()) + .timeout(15000) // 5秒超时 + .execute() + .body(); + // 6. 检查响应结果并记录日志 + JSONObject jsonResponse = JSONObject.parseObject(response); + if (jsonResponse != null && jsonResponse.getIntValue("code") == 0) { + //log.info("设备{}的故障消息发送成功:{}", this.getDeviceCode(), errorMessage); + // 更新缓存:记录最后发送时间 + feiShuErrorCache.put(cacheKey, currentTime); + } else { + log.error("设备{}的故障消息发送失败:{}", this.getDeviceCode(), response); + } + + } catch (Exception e) { + log.error("发送飞书报警消息时发生异常,设备编码:{},错误信息:{}", this.getDeviceCode(), errorMessage, e); + } + } + + /** + * 如果缓存未过期则直接使用缓存值,否则从数据库重新加载 + */ + private void loadTaskCountParamsIfNeeded() { + long currentTime = System.currentTimeMillis(); + try { + if (currentTime - lastParamLoadTime < PARAM_CACHE_TIMEOUT) { + return; + } + String feiShuSendTimeResult = paramService.findByCode(AcsConfig.FEISHUSENDTIME).getValue(); + String feiShuSendFreResult = paramService.findByCode(AcsConfig.FEISHUSENDFRE).getValue(); + // 更新缓存值 + if (StringUtils.isNotBlank(feiShuSendTimeResult)) { + this.feiShuSendTime = feiShuSendTimeResult; + } + if (StringUtils.isNotBlank(feiShuSendFreResult)) { + this.feiShuSendFre = feiShuSendFreResult; + } + this.lastParamLoadTime = System.currentTimeMillis(); + } catch (Exception e) { + log.error("加载任务数量参数失败,使用缓存值", e); + } + } + + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/history/ErrorUtil.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/history/ErrorUtil.java index 6a4bffc..749d1b5 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/history/ErrorUtil.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/history/ErrorUtil.java @@ -7,10 +7,7 @@ import org.nl.system.service.dict.ISysDictService; import org.nl.system.service.dict.dao.Dict; import org.nl.system.service.dict.impl.SysDictServiceImpl; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; -import java.util.Map; +import java.util.*; import java.util.concurrent.ConcurrentHashMap; import java.util.function.Function; import java.util.stream.Collectors; @@ -64,7 +61,7 @@ public class ErrorUtil { List dictDtos = dictDetailService.queryAll(); for (int i = 0; i < dictDtos.size(); i++) { Dict dictDto = dictDtos.get(i); - dictMap.put(dictDto.getName(), getDict(dictDto.getName(), dictDetailService::getDictByName)); + dictMap.put(dictDto.getCode(), getDict(dictDto.getDict_id(), dictDetailService::getDictDetail)); } } } @@ -76,7 +73,6 @@ public class ErrorUtil { public static Map getAgvErrorMsg(Integer agvErrorNum) { String code; String message; - if (agvErrorNum == 0) { code = "0"; message = "正常"; @@ -90,7 +86,6 @@ public class ErrorUtil { message = "字典表未配置 [agv_error_type]"; } else { List> errors = agvMap.entrySet().stream().filter(e -> e.getKey() > 0).sorted(Comparator.comparingInt(Map.Entry::getKey)).collect(Collectors.toList()); - if (errors.isEmpty()) { code = "-1"; message = "字典表 [agv_error_type] 配置有误"; @@ -98,27 +93,37 @@ public class ErrorUtil { code = "-1"; message = "AGV上报报警代码有误"; } else { - int index = 0; - StringBuilder errorCode = new StringBuilder(); - StringBuilder errorMessage = new StringBuilder(); - for (int i = agvErrorNum; i != 0; i = i >> 1) { - if (index == errors.size()) { - errorCode.setLength(0); - errorCode.append("-1"); - errorMessage.setLength(0); - errorMessage.append("字典表 [agv_error_type] 配置有误"); - break; + // 尝试直接匹配错误码 + Optional> matchedEntry = agvMap.entrySet().stream() + .filter(e -> e.getKey().equals(agvErrorNum)) + .findFirst(); + if (matchedEntry.isPresent()) { + code = matchedEntry.get().getKey().toString(); + message = matchedEntry.get().getValue(); + } else { + // 如果没有直接匹配,使用位运算解析多个错误 + int index = 0; + StringBuilder errorCode = new StringBuilder(); + StringBuilder errorMessage = new StringBuilder(); + for (int i = agvErrorNum; i != 0; i = i >> 1) { + if (index == errors.size()) { + errorCode.setLength(0); + errorCode.append("-1"); + errorMessage.setLength(0); + errorMessage.append("字典表 [agv_error_type] 配置有误"); + break; + } + if (i % 2 == 1) { + errorCode.append(errors.get(index).getKey()).append(","); + errorMessage.append(errors.get(index).getValue()).append(","); + } + index++; } - if (i % 2 == 1) { - errorCode.append(errors.get(index).getKey()).append(","); - errorMessage.append(errors.get(index).getValue()).append(","); - } - index++; + code = errorCode.toString(); + message = errorMessage.toString(); } - code = errorCode.toString(); - message = errorMessage.toString(); - } - } + } + } } Map map = new HashMap<>(2); diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java index 193fd82..434db20 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/instruction/service/impl/InstructionServiceImpl.java @@ -346,7 +346,10 @@ public class InstructionServiceImpl extends CommonServiceImpl taskList = new LambdaQueryChainWrapper<>(taskMapper) .eq(Task::getTask_status, "0") .eq(Task::getIs_delete, "0") - .eq(Task::getCar_type, task.getCar_type()) .eq(Task::getTask_type, "1".equals(task.getTask_type()) ? "2" : "1") .orderByDesc(Task::getPriority) .orderByAsc(Task::getTask_code) @@ -797,13 +811,14 @@ public class InstructionServiceImpl extends CommonServiceImpl instructionList = new LambdaQueryChainWrapper<>(instructionMapper) .lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex()) + .eq(InstructionMybatis::getIs_delete, "0") .list(); if (ObjectUtil.isNotEmpty(taskList)) { - TaskDto acsTask = null; List priorityTaskList = ConvertUtil.convertList(taskList, TaskDto.class); - if (task.getTask_type().equals("2")) { + if ("2".equals(task.getTask_type())) { //包含"BCPRK"或"CPRK"的任务 List collection1 = new ArrayList<>(); + //不需要二次分配的任务 List collection2 = new ArrayList<>(); // 分组任务 for (TaskDto taskDto : priorityTaskList) { @@ -839,8 +854,45 @@ public class InstructionServiceImpl extends CommonServiceImpl> group = collection1.stream() + .filter(r -> r.getStart_device_code() != null && r.getStart_device_code().contains("-")) + .collect(Collectors.groupingBy( + r -> r.getStart_device_code().split("-")[0] + )); + + // 对每个组内的元素按task_code升序排序 + for (String key : group.keySet()) { + List sortedList = group.get(key).stream() + .sorted(Comparator.comparing(TaskDto::getTask_code)) + .collect(Collectors.toList()); + group.put(key, sortedList); + } + // 将分组按组内第1个元素的task_code升序排序 + Map> sortedGroup = group.entrySet().stream() + .sorted((entry1, entry2) -> { + List list1 = entry1.getValue(); + List list2 = entry2.getValue(); + if (!list1.isEmpty() && !list2.isEmpty()) { + return list1.get(0).getTask_code().compareTo(list2.get(0).getTask_code()); + } + return 0; + }).collect(Collectors.toMap( + Map.Entry::getKey, + Map.Entry::getValue, + (e1, e2) -> e1, + LinkedHashMap::new + )); + // 按car_type查找任务(从排序后的第1个组开始找) + for (Map.Entry> entry : sortedGroup.entrySet()) { + List groupList = entry.getValue(); + if (!groupList.isEmpty() && task.getCar_type().equals(groupList.get(0).getCar_type())) { + acsTask = groupList.get(0); + break; + } + } } else { if (ObjectUtil.isNotEmpty(collection2)) { acsTask = collection2.get(0); @@ -852,12 +904,11 @@ public class InstructionServiceImpl extends CommonServiceImpl { * @param task_status task_status * @return AcsTask */ - List queryAllByInStatus(Set task_status); + List queryAllByInStatus(List task_status); @@ -281,6 +281,11 @@ public interface TaskService extends CommonService { */ void update(TaskDto dto); + + + void updateEntity(TaskDto dto); + + /** * 多选删除 * diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java index bdd2db3..fb48ef1 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/acs/task/service/impl/TaskServiceImpl.java @@ -7,6 +7,7 @@ import cn.hutool.core.map.MapUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; +import cn.hutool.http.HttpRequest; import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; @@ -14,8 +15,9 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import lombok.extern.slf4j.Slf4j; -import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; import org.jetbrains.annotations.NotNull; import org.nl.acs.AcsConfig; import org.nl.acs.agv.server.XianGongAgvService; @@ -31,6 +33,7 @@ import org.nl.acs.device.service.DeviceService; import org.nl.acs.device.service.dto.DeviceAssignedDto; import org.nl.acs.device.service.impl.DeviceServiceImpl; import org.nl.acs.ext.wms.service.AcsToWmsService; +import org.nl.acs.history.ErrorUtil; import org.nl.acs.instruction.domain.Instruction; import org.nl.acs.instruction.domain.InstructionMybatis; import org.nl.acs.instruction.enums.InstructionStatusEnum; @@ -60,7 +63,9 @@ import org.nl.config.SpringContextHolder; import org.nl.config.language.LangProcess; import org.nl.system.service.param.ISysParamService; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; +import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Propagation; @@ -70,6 +75,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.*; import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CopyOnWriteArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -84,7 +90,6 @@ import java.util.stream.Collectors; @Lazy @Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class) public class TaskServiceImpl extends CommonServiceImpl implements TaskService, ApplicationAutoInitial { - @Autowired private TaskMapper taskMapper; @Autowired @@ -200,7 +205,7 @@ public class TaskServiceImpl extends CommonServiceImpl impleme return ConvertUtil.convertList(taskList, TaskDto.class); } - public List queryAllByInStatus(Set task_status) { + public List queryAllByInStatus(List task_status) { List taskList = new LambdaQueryChainWrapper<>(taskMapper) .in(Task::getTask_status, task_status) .eq(Task::getIs_delete, "0") @@ -212,7 +217,6 @@ public class TaskServiceImpl extends CommonServiceImpl impleme @Override public Map queryAll(Map whereJson, Pageable page) { - String task_code = (String) whereJson.get("task_code"); String vehicle_code = (String) whereJson.get("vehicle_code"); String material_type = (String) whereJson.get("material_type"); @@ -220,12 +224,15 @@ public class TaskServiceImpl extends CommonServiceImpl impleme String point_code = (String) whereJson.get("point_code"); String is_over = (String) whereJson.get("is_over"); String priority = (String) whereJson.get("priority"); - + String task_type = (String) whereJson.get("task_type"); IPage queryPage = PageUtil.toMybatisPage(page); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (!StrUtil.isEmpty(task_code)) { wrapper.eq(Task::getTask_code, task_code); } + if (!StrUtil.isEmpty(task_type)) { + wrapper.eq(Task::getTask_type, task_type); + } if (!StrUtil.isEmpty(vehicle_code)) { wrapper.eq(Task::getVehicle_code, vehicle_code); } @@ -328,7 +335,10 @@ public class TaskServiceImpl extends CommonServiceImpl impleme String point_code = (String) whereJson.get("point_code"); String create_time = (String) whereJson.get("createTime"); String end_time = (String) whereJson.get("end_time"); - + String task_type = (String) whereJson.get("task_type"); + String start_point_code = (String) whereJson.get("start_point_code"); + String next_point_code = (String) whereJson.get("next_point_code"); + String timeIndex = (String) whereJson.get("timeIndex"); IPage queryPage = PageUtil.toMybatisPage(page); LambdaQueryWrapper wrapper = new LambdaQueryWrapper<>(); if (!StrUtil.isEmpty(car_no)) { @@ -337,6 +347,9 @@ public class TaskServiceImpl extends CommonServiceImpl impleme if (!StrUtil.isEmpty(task_code)) { wrapper.eq(Task::getTask_code, task_code); } + if (!StrUtil.isEmpty(task_type)) { + wrapper.eq(Task::getTask_type, task_type); + } if (!StrUtil.isEmpty(vehicle_code)) { wrapper.like(Task::getVehicle_code, vehicle_code); } @@ -348,11 +361,62 @@ public class TaskServiceImpl extends CommonServiceImpl impleme } if (!StrUtil.isEmpty(point_code)) { wrapper.and(task -> task.like(Task::getStart_point_code, point_code).or().like(Task::getNext_point_code, point_code)); + }else{ + if ("AA".equals(start_point_code)) { + wrapper.like(Task::getNext_point_code, next_point_code); + }else if ("AA".equals(next_point_code)) { + wrapper.like(Task::getStart_point_code, start_point_code); + } } if (!StrUtil.isEmpty(create_time) && !StrUtil.isEmpty(end_time)) { wrapper.between(Task::getCreate_time, create_time, end_time); } wrapper.orderByDesc(Task::getCreate_time); + if (StrUtil.isNotEmpty(timeIndex)) { + // 先查询出所有符合条件的任务,然后在内存中根据时间间隔过滤 + List allTasks = taskMapper.selectList(wrapper); + // 计算每个任务的时间间隔(分钟) + List filteredTasks = allTasks.stream() + .filter(task -> { + Double duration = calculateDuration(task.getTo_x(), task.getTo_y()); + if (duration == null) { + return false; + } + switch (timeIndex) { + case "1": // 1-3分钟(包含1和3) + return duration >= 1 && duration <= 3; + case "2": // 3-5分钟(大于3,小于等于5) + return duration > 3 && duration <= 5; + case "3": // 5-8分钟(大于5,小于等于8) + return duration > 5 && duration <= 8; + case "4": // 大于8分钟 + return duration > 8; + default: + return true; + } + }).collect(Collectors.toList()); + // 手动分页 + int total = filteredTasks.size(); + int start = (int) page.getOffset(); + int end = Math.min(start + page.getPageSize(), total); + List pageData = start < total ? filteredTasks.subList(start, end) : new ArrayList<>(); + // 构建分页结果 + Page resultPage = new Page<>(page.getPageNumber() + 1, page.getPageSize(), total); + resultPage.setRecords(pageData); + final JSONObject json = (JSONObject) JSON.toJSON(ConvertUtil.convertPage(resultPage, TaskDto.class)); + JSONArray array = json.getJSONArray("content"); + int totalElements = (int) json.getLongValue("totalElements"); + JSONArray arr = new JSONArray(); + for (int i = 0; i < array.size(); i++) { + JSONObject jsonObject = (JSONObject) array.get(i); + jsonObject.put("hasChildren", true); + arr.add(jsonObject); + } + JSONObject jo = new JSONObject(); + jo.put("content", arr); + jo.put("totalElements", totalElements); + return jo; + } IPage taskPage = taskMapper.selectPage(queryPage, wrapper); final JSONObject json = (JSONObject) JSON.toJSON(ConvertUtil.convertPage(taskPage, TaskDto.class)); JSONArray array = json.getJSONArray("content"); @@ -768,6 +832,22 @@ public class TaskServiceImpl extends CommonServiceImpl impleme } } + + //仅更新数据库 + @Override + public void updateEntity(TaskDto dto) { + TaskDto entity = this.findById(dto.getTask_id()); + if (entity == null) { + throw new BadRequestException(LangProcess.msg("error_sysAuth")); + } + String currentUsername = SecurityUtils.getCurrentUsername(); + String now = DateUtil.now(); + dto.setUpdate_time(now); + dto.setUpdate_by(currentUsername); + Task task = ConvertUtil.convert(dto, Task.class); + taskMapper.updateById(task); + } + @Override @Transactional(rollbackFor = Exception.class) public void deleteAll(String[] ids) throws Exception { @@ -797,7 +877,7 @@ public class TaskServiceImpl extends CommonServiceImpl impleme //车辆执行任务完成计时字段 entity.setTo_y(now); Task task = ConvertUtil.convert(entity, Task.class); - if (StrUtil.isNotBlank(entity.getTo_x())) { + if (StringUtils.isNotBlank(entity.getTo_x())) { DateTime toXTime = DateUtil.parse(entity.getTo_x()); DateTime nowTime = DateUtil.parse(now); long diffMs = nowTime.getTime() - toXTime.getTime(); @@ -818,7 +898,10 @@ public class TaskServiceImpl extends CommonServiceImpl impleme if (!StrUtil.startWith(entity.getTask_code(), "-") && StrUtil.equals(hasWms, "1")) { this.feedWmsTaskStatus(entity); } + } + + @Override @Transactional(rollbackFor = Exception.class) public void finishmove(String id) { @@ -867,23 +950,52 @@ public class TaskServiceImpl extends CommonServiceImpl impleme if (acsTask == null) { throw new BadRequestException(LangProcess.msg("error_sysAuth")); } - DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class); InstructionService instructionservice = SpringContextHolder.getBean("instructionServiceImpl"); InstructionDto inst = instructionservice.findByTaskid(ids, "instruction_status < 2 "); if (inst != null) { throw new BadRequestException(LangProcess.msg("task_insRun")); } - int unfinishedInstructionCount = new LambdaQueryChainWrapper<>(instructionMapper) + String maxInstNumber = "0"; + long unfinishedInstructionCount = 0L; + List unfinishedList = new LambdaQueryChainWrapper<>(instructionMapper) .lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex()) - .count(); - String maxInstNumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue(); - int maxInst = Integer.parseInt(maxInstNumber); + .eq(InstructionMybatis::getIs_delete, "0").list(); + if ("2".equals(acsTask.getCar_type())) { + maxInstNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue(); + unfinishedInstructionCount = unfinishedList.stream().filter(r -> "2".equals(r.getCar_type())).count(); + } else { + maxInstNumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue(); + unfinishedInstructionCount = unfinishedList.stream().filter(r -> !"2".equals(r.getCar_type())).count(); + } + long maxInst = Long.parseLong(maxInstNumber); if (unfinishedInstructionCount >= maxInst) { - throw new BadRequestException("超过最大指令数:"+maxInstNumber+"个,请等待指令列表完成后再创建!"); + throw new BadRequestException("超过最大指令数:" + maxInstNumber + "个,请等待指令列表完成后再创建!"); + } + String startDeviceCode = acsTask.getStart_device_code(); + if ("1".equals(acsTask.getTask_type()) && (startDeviceCode.contains("BCPRK") || startDeviceCode.contains("CPRK"))) { + // 包含"BCPRK"或"CPRK"的指令 + List collection = new ArrayList<>(); + // 分组指令 + for (InstructionMybatis instruction : unfinishedList) { + String deviceCode = instruction.getStart_device_code(); + if (deviceCode != null && (deviceCode.contains("BCPRK") || deviceCode.contains("CPRK"))) { + collection.add(instruction); + } + } + boolean flag = collection.stream().anyMatch(ins -> { + String code = ins.getStart_device_code(); + if (code == null) return false; + String[] parts = code.split("-", 2); + String[] parts1 = startDeviceCode.split("-", 2); + return parts1[0].equals(parts[0]); + }); + if (flag) { + throw new BadRequestException("当前任务的起点:" + startDeviceCode + "存在相同入库口的指令,请等待执行完成再创建!"); + } } String taskid = acsTask.getTask_id(); String taskcode = acsTask.getTask_code(); - String car_type=acsTask.getCar_type(); + String car_type = acsTask.getCar_type(); String vehiclecode = acsTask.getVehicle_code(); String priority = acsTask.getPriority(); String start_point_code = acsTask.getStart_point_code(); @@ -931,7 +1043,7 @@ public class TaskServiceImpl extends CommonServiceImpl impleme instdto.setInstruction_type(task_type); instdto.setInstruction_id(IdUtil.simpleUUID()); instdto.setRoute_plan_code(route_plan_code); - instdto.setRemark(acsTask.getRemark()); + instdto.setRemark(acsTask.getRemark() != null ? acsTask.getRemark() + "该指令由人工创建" : "该指令由人工创建"); instdto.setMaterial(acsTask.getMaterial()); instdto.setQuantity(acsTask.getQuantity()); instdto.setCar_type(car_type); @@ -959,7 +1071,6 @@ public class TaskServiceImpl extends CommonServiceImpl impleme instdto.setAgv_system_type(agv_system_type); instdto.setAgv_inst_type(CommonFinalParam.ONE); instructionservice.create(instdto); - acsTask.setTask_status(CommonFinalParam.ONE); this.update(acsTask); return instdto; @@ -1354,32 +1465,35 @@ public class TaskServiceImpl extends CommonServiceImpl impleme @Override public List getTaskList(Map whereJson) { - whereJson.put("status", "2"); - LambdaQueryWrapper wrapper = getTaskLambdaQueryWrapper(whereJson); - List taskList = taskMapper.selectList(wrapper); - return Optional - .ofNullable(taskList) - .orElse(new ArrayList<>()) - .stream().sorted(Comparator.comparing(Task::getTo_x, Comparator.nullsLast(Comparator.naturalOrder()))) + Pageable page = PageRequest.of(0, 999999); + JSONObject result = (JSONObject) getAll(whereJson, page); + // 从结果中获取content数组 + JSONArray contentArray = result.getJSONArray("content"); + if (contentArray == null || contentArray.isEmpty()) { + return new ArrayList<>(); + } + return contentArray.stream() + .map(obj -> (JSONObject) obj) + .sorted(Comparator.comparing(task -> task.getString("to_x"), Comparator.nullsLast(Comparator.naturalOrder()))) .map(task -> { JSONObject ins = new JSONObject(); - ins.put("task_code", task.getTask_code()); - ins.put("task_type", "1".equals(task.getTask_type()) ? "入库" : "出库"); - ins.put("vehicle_code", task.getVehicle_code()); + ins.put("task_code", task.getString("task_code")); + ins.put("task_type", "1".equals(task.getString("task_type")) ? "入库" : "出库"); + ins.put("vehicle_code", task.getString("vehicle_code")); ins.put("task_status", "完成"); - ins.put("priority", task.getPriority()); - ins.put("start_point_code", task.getStart_point_code()); - ins.put("next_point_code", task.getNext_point_code()); - ins.put("matarial", task.getMaterial()); - ins.put("quantity", task.getQuantity()); - ins.put("remark", task.getRemark()); - ins.put("create_by", task.getCreate_by()); - ins.put("create_time", task.getCreate_time()); - ins.put("car_no", task.getCar_no()); - ins.put("to_x", task.getTo_x()); - ins.put("to_y", task.getTo_y()); - ins.put("to_z", task.getTo_z()); - ins.put("update_time", task.getUpdate_time()); + ins.put("priority", task.getString("priority")); + ins.put("start_point_code", task.getString("start_point_code")); + ins.put("next_point_code", task.getString("next_point_code")); + ins.put("matarial", task.getString("material")); + ins.put("quantity", task.getString("quantity")); + ins.put("remark", task.getString("remark")); + ins.put("create_by", task.getString("create_by")); + ins.put("create_time", task.getString("create_time")); + ins.put("car_no", task.getString("car_no")); + ins.put("to_x", task.getString("to_x")); + ins.put("to_y", task.getString("to_y")); + ins.put("to_z", task.getString("to_z")); + ins.put("update_time", task.getString("update_time")); return ins; }) .collect(Collectors.toList()); @@ -1589,7 +1703,6 @@ public class TaskServiceImpl extends CommonServiceImpl impleme Collectors.mapping(durationCalculator, Collectors.toList()) )); long inTotal = inTaskMap.values().stream().mapToLong(List::size).sum(); - // 出库任务 (type 2), 按start_point_code分组 Map> outTaskMap = taskList.stream() .filter(t -> "2".equals(t.getTask_type())) @@ -1618,10 +1731,10 @@ public class TaskServiceImpl extends CommonServiceImpl impleme long c2 = durations.stream().filter(d -> d >= 3 && d < 5).count(); long c3 = durations.stream().filter(d -> d >= 5 && d < 8).count(); long c4 = durations.stream().filter(d -> d >= 8).count(); - result.put("item" + itemIndex, String.valueOf(c1 * 100 / total)); - result.put("item" + (itemIndex + 1), String.valueOf(c2 * 100 / total)); - result.put("item" + (itemIndex + 2), String.valueOf(c3 * 100 / total)); - result.put("item" + (itemIndex + 3), String.valueOf(c4 * 100 / total)); + result.put("AA-"+group+"-1-"+ (itemIndex), String.valueOf(c1 * 100 / total)); + result.put("AA-"+group+"-2-"+ (itemIndex + 1), String.valueOf(c2 * 100 / total)); + result.put("AA-"+group+"-3-"+ (itemIndex + 2), String.valueOf(c3 * 100 / total)); + result.put("AA-"+group+"-4-"+ (itemIndex + 3), String.valueOf(c4 * 100 / total)); itemIndex += 4; } for (String group : groups) { @@ -1631,13 +1744,159 @@ public class TaskServiceImpl extends CommonServiceImpl impleme long c2 = durations.stream().filter(d -> d >= 3 && d < 5).count(); long c3 = durations.stream().filter(d -> d >= 5 && d < 8).count(); long c4 = durations.stream().filter(d -> d >= 8).count(); - result.put("item" + itemIndex, String.valueOf(c1 * 100 / total)); - result.put("item" + (itemIndex + 1), String.valueOf(c2 * 100 / total)); - result.put("item" + (itemIndex + 2), String.valueOf(c3 * 100 / total)); - result.put("item" + (itemIndex + 3), String.valueOf(c4 * 100 / total)); + result.put(group+"-AA"+"-1-"+ (itemIndex), String.valueOf(c1 * 100 / total)); + result.put(group+"-AA"+"-2-"+ (itemIndex + 1), String.valueOf(c2 * 100 / total)); + result.put(group+"-AA"+"-3-"+ (itemIndex + 2), String.valueOf(c3 * 100 / total)); + result.put(group+"-AA"+"-4-"+ (itemIndex + 3), String.valueOf(c4 * 100 / total)); itemIndex += 4; } + // 稼动率统计 + // 1. getCar_no + Map> carTaskMap = taskList.stream() + .filter(t -> StrUtil.isNotEmpty(t.getCar_no())) + .collect(Collectors.groupingBy(Task::getCar_no)); + // 2. 获取标准工作时间(分钟) + long standardWorkingMinutes = getStandardWorkingMinutes(whereJson); + // 3. 计算每辆车的统计数据 + int carIndex = 1; + for (Map.Entry> entry : carTaskMap.entrySet()) { + String carType = entry.getKey(); + List carTasks = entry.getValue(); + // 计算实际运行总时长(to_z累加,单位:分钟) + // to_z格式为 "5.19" 表示 5分钟19秒,需要正确解析 + long totalRunningSeconds = carTasks.stream() + .filter(t -> StrUtil.isNotEmpty(t.getTo_z())) + .mapToLong(t -> { + try { + String[] parts = t.getTo_z().split("\\."); + int minutes = Integer.parseInt(parts[0]); + int seconds = parts.length > 1 ? Integer.parseInt(parts[1]) : 0; + return minutes * 60 + seconds; // 转换为秒 + } catch (Exception e) { + return 0L; + } + }) + .sum(); + long totalRunningMinutes = totalRunningSeconds / 60; // 转换为分钟 + // 任务数 + int taskCount = carTasks.size(); + // 计算稼动率(总时长/工作时间) + int utilizationRate = standardWorkingMinutes > 0 + ? (int) (totalRunningMinutes * 100 / standardWorkingMinutes) + : 0; + // 计算平均耗时(总秒数/任务数,单位:分钟) + long avgSeconds = taskCount > 0 ? totalRunningSeconds / taskCount : 0; + String avgTime = formatMinutes(avgSeconds / 60); + // 格式化实际运行总时长 + String actualTimeStr = formatMinutes(totalRunningMinutes); + String standardTimeStr = formatMinutes(standardWorkingMinutes); + // 放入result + result.put("car-" + carType + "-1", carType); // 车辆编号 + result.put("car-" + carType + "-2", actualTimeStr); // 实际运行总时长 + result.put("car-" + carType + "-3", standardTimeStr); // 标准工作时间 + result.put("car-" + carType + "-4", taskCount); // 总任务数 + result.put("car-" + carType + "-5", String.valueOf(utilizationRate)); // 稼动率 + result.put("car-" + carType + "-6", avgTime); // 平均耗时 + //carIndex += 5; + } return Collections.singletonList(result); } + /** + * 获取标准工作时间(分钟) + * @param whereJson 查询参数,包含startDate和endDate + * @return 标准工作总分钟数 = 每日标准工作时间 × 天数 + */ + private long getStandardWorkingMinutes(Map whereJson) { + try { + // 获取每日标准工作时间(分钟) + String workingTime = paramService.findByCode(AcsConfig.WORKINGTIME).getValue(); + if (StrUtil.isEmpty(workingTime)) { + return 8 * 60; // 默认8小时 + } + // 计算每日标准工作分钟数 + long dailyWorkingMinutes; + if (workingTime.contains(".")) { + // 格式如 8.30 表示 8小时30分钟 + String[] parts = workingTime.split("\\."); + int hours = Integer.parseInt(parts[0]); + int minutes = Integer.parseInt(parts[1]); + dailyWorkingMinutes = hours * 60 + minutes; + } else { + // 纯小时数 + dailyWorkingMinutes = Long.parseLong(workingTime) * 60; + } + + // 计算时间范围的天数 + String create_time = (String) whereJson.get("startDate"); + String end_time = (String) whereJson.get("endDate"); + if (StrUtil.isEmpty(create_time) || StrUtil.isEmpty(end_time)) { + // 默认当天,天数为1 + return dailyWorkingMinutes * 1; + } + + // 处理日期格式 + if (create_time.length() == 10) { + create_time += " 00:00:00"; + } + if (end_time.length() == 10) { + end_time += " 23:59:59"; + } + + // 计算天数差 + try { + Date start = DateUtil.parse(create_time); + Date end = DateUtil.parse(end_time); + long days = (end.getTime() - start.getTime()) / (1000L * 60 * 60 * 24) + 1; // +1 包含当天 + if (days <= 0) { + days = 1; + } + return dailyWorkingMinutes * days; + } catch (Exception e) { + return dailyWorkingMinutes * 1; + } + } catch (Exception e) { + return 8 * 60; // 默认8小时 + } + } + + /** + * 将分钟格式化为 小时h分钟m 的字符串 + */ + private String formatMinutes(long minutes) { + if (minutes <= 0) { + return "0m"; + } + long hours = minutes / 60; + long mins = minutes % 60; + if (hours > 0 && mins > 0) { + return hours + "h" + mins + "m"; + } else if (hours > 0) { + return hours + "h"; + } else { + return mins + "m"; + } + } + + + /** + * 计算任务持续时间(分钟) + * @param startTime 开始时间字符串 + * @param endTime 结束时间字符串 + * @return 分钟数,计算失败返回null + */ + private Double calculateDuration(String startTime, String endTime) { + if (StrUtil.isEmpty(startTime) || StrUtil.isEmpty(endTime)) { + return null; + } + try { + Date start = DateUtil.parse(startTime); + Date end = DateUtil.parse(endTime); + long diffMillis = end.getTime() - start.getTime(); + return diffMillis / (1000.0 * 60); + } catch (Exception e) { + return null; + } + } + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/dict/SysDictController.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/dict/SysDictController.java index a3e0432..3d3952b 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/dict/SysDictController.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/dict/SysDictController.java @@ -106,5 +106,19 @@ public class SysDictController { return new ResponseEntity<>(HttpStatus.OK); } + @GetMapping("/showDetail2") + @Log("查询字典明细") + public ResponseEntity showDetail2(@RequestParam String name){ + return new ResponseEntity<>(dictService.getDictByName(name), HttpStatus.OK); + } + + @PostMapping("/initDict") + @Log("初始化字典") + public ResponseEntity initDict(@Validated @RequestBody Dict dto){ + dictService.initDict(dto); + return new ResponseEntity<>(HttpStatus.NO_CONTENT); + } + + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/param/SysParamController.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/param/SysParamController.java index 56fdb61..6743437 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/param/SysParamController.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/controller/param/SysParamController.java @@ -69,6 +69,14 @@ class SysParamController { return new ResponseEntity<>(paramService.findByCode(code), HttpStatus.CREATED); } + @PostMapping("/setParam") + @Log("保存参数") + @SaIgnore + public ResponseEntity setParam(@RequestBody Map whereJson) { + paramService.setParam(whereJson); + return new ResponseEntity<>(HttpStatus.OK); + } + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/ISysDictService.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/ISysDictService.java index f56a0ba..8e9367b 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/ISysDictService.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/ISysDictService.java @@ -62,6 +62,15 @@ public interface ISysDictService extends IService { */ List getDictByName(String name); + void initDict(Dict dto); + + /** + * 获取字典明细 + * @param code + * @return + */ + List getDictDetail(String code); + /** * 添加字典明细 * @param resources diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/dao/mapper/SysDictMapper.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/dao/mapper/SysDictMapper.java index d83ff61..9231f22 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/dao/mapper/SysDictMapper.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/dao/mapper/SysDictMapper.java @@ -1,8 +1,11 @@ package org.nl.system.service.dict.dao.mapper; +import org.apache.ibatis.annotations.Select; import org.nl.system.service.dict.dao.Dict; import com.baomidou.mybatisplus.core.mapper.BaseMapper; +import java.util.List; + /** *

* 字典表 Mapper 接口 @@ -13,4 +16,7 @@ import com.baomidou.mybatisplus.core.mapper.BaseMapper; */ public interface SysDictMapper extends BaseMapper { + @Select("select dict_id,label,value from sys_dict_detail where dict_id = #{code}") + List getDictDetail(String code); + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/impl/SysDictServiceImpl.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/impl/SysDictServiceImpl.java index 5bd1845..b2605cf 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/impl/SysDictServiceImpl.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/dict/impl/SysDictServiceImpl.java @@ -124,6 +124,10 @@ public class SysDictServiceImpl extends ServiceImpl impleme .ne(Dict::getLabel, "")); return dictList; } + @Override + public List getDictDetail(String code){ + return sysDictMapper.getDictDetail(code); + } @Override @Transactional(rollbackFor = Exception.class) @@ -189,9 +193,28 @@ public class SysDictServiceImpl extends ServiceImpl impleme @Override public List queryAll() { return sysDictMapper.selectList(new QueryWrapper() - .select("MAX(dict_id) AS dictId, code, name") + .select("MAX(dict_id) AS dict_id, code, name") .lambda() .groupBy(Dict::getCode, Dict::getName)); } + @Override + @Transactional(rollbackFor = Exception.class) + public void initDict(Dict dto) { + Dict dict = sysDictMapper.selectById(dto.getDict_id()); + if (ObjectUtil.isEmpty(dict)) { + throw new BadRequestException("字典不存在"); + } + String currentUserId = SecurityUtils.getCurrentUserId(); + String currentNickName = SecurityUtils.getCurrentNickName(); + dict.setValue("0"); + dict.setPara2(""); + dict.setPara3("充电桩空闲"); + dict.setUpdate_id(currentUserId); + dict.setUpdate_name(currentNickName); + dict.setUpdate_time(DateUtil.now()); + sysDictMapper.updateById(dict); + } + + } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/ISysParamService.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/ISysParamService.java index a10d971..6bbcd19 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/ISysParamService.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/ISysParamService.java @@ -60,4 +60,6 @@ public interface ISysParamService extends IService { */ /*@Cached(name = "paramDataCode.", key = "#code", expire = 3600, cacheType = CacheType.REMOTE)*/ Param findByCode(String code); + + void setParam(Map whereJson); } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/impl/SysParamServiceImpl.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/impl/SysParamServiceImpl.java index 274e2d1..7f35c5c 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/impl/SysParamServiceImpl.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/param/impl/SysParamServiceImpl.java @@ -9,6 +9,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage; import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import lombok.extern.slf4j.Slf4j; +import org.nl.acs.AcsConfig; import org.nl.common.domain.query.PageQuery; import org.nl.common.exception.BadRequestException; import org.nl.common.utils.SecurityUtils; @@ -98,4 +99,47 @@ public class SysParamServiceImpl extends ServiceImpl impl Param param = paramMapper.selectOne(queryWrapper); return param; } + @Override + @Transactional(rollbackFor = Exception.class) + public void setParam(Map whereJson){ + Integer electric = (Integer) whereJson.get("electric"); + Integer electric2 = (Integer) whereJson.get("electric2"); + String electric_begin = (String) whereJson.get("electric_begin"); + String electric_end = (String) whereJson.get("electric_end"); + + String now_time = DateUtil.now(); + //白班充电阈值 + Param param_electric = this.findByCode(AcsConfig.ELECTRIC); + if (ObjectUtil.isEmpty(param_electric)) throw new BadRequestException("白班充电阈值参数异常"); + param_electric.setValue(electric.toString()); + param_electric.setUpdate_id(SecurityUtils.getCurrentUserId()); + param_electric.setUpdate_name(SecurityUtils.getCurrentNickName()); + param_electric.setUpdate_time(now_time); + paramMapper.updateById(param_electric); + //晚班充电阈值 + Param param_electric2 = this.findByCode(AcsConfig.ELECTRIC2); + if (ObjectUtil.isEmpty(param_electric2)) throw new BadRequestException("晚班充电阈值参数异常"); + param_electric2.setValue(electric2.toString()); + param_electric2.setUpdate_id(SecurityUtils.getCurrentUserId()); + param_electric2.setUpdate_name(SecurityUtils.getCurrentNickName()); + param_electric2.setUpdate_time(now_time); + paramMapper.updateById(param_electric2); + //白班开始时间 + Param param_electric_begin = this.findByCode(AcsConfig.ELECTRIC_BEGIN); + if (ObjectUtil.isEmpty(param_electric_begin)) throw new BadRequestException("白班开始时间参数异常"); + param_electric_begin.setValue(electric_begin); + param_electric_begin.setUpdate_id(SecurityUtils.getCurrentUserId()); + param_electric_begin.setUpdate_name(SecurityUtils.getCurrentNickName()); + param_electric_begin.setUpdate_time(now_time); + paramMapper.updateById(param_electric_begin); + //白班结束时间 + Param param_electric_end = this.findByCode(AcsConfig.ELECTRIC_END); + if (ObjectUtil.isEmpty(param_electric_end)) throw new BadRequestException("白班开始时间参数异常"); + param_electric_end.setValue(electric_end); + param_electric_end.setUpdate_id(SecurityUtils.getCurrentUserId()); + param_electric_end.setUpdate_name(SecurityUtils.getCurrentNickName()); + param_electric_end.setUpdate_time(now_time); + paramMapper.updateById(param_electric_end); + + } } diff --git a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/quartz/task/AutoCreateInst.java b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/quartz/task/AutoCreateInst.java index 4840af7..6e19f76 100644 --- a/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/quartz/task/AutoCreateInst.java +++ b/acs/nladmin-system/nlsso-server/src/main/java/org/nl/system/service/quartz/task/AutoCreateInst.java @@ -15,24 +15,18 @@ import org.nl.acs.instruction.enums.InstructionStatusEnum; import org.nl.acs.instruction.service.InstructionService; import org.nl.acs.instruction.service.mapper.InstructionMapper; import org.nl.acs.opc.DeviceAppService; -import org.nl.acs.opc.DeviceAppServiceImpl; import org.nl.acs.task.enums.TaskStatusEnum; -import org.nl.acs.task.enums.TaskTypeEnum; import org.nl.acs.task.service.TaskService; import org.nl.acs.task.service.dto.TaskDto; import org.nl.common.utils.SecurityUtils; -import org.nl.config.SpringContextHolder; import org.nl.system.service.lucene.LuceneExecuteLogService; import org.nl.system.service.lucene.dto.LuceneLogDto; -import org.nl.system.service.lucene.impl.LuceneExecuteLogServiceImpl; import org.nl.system.service.param.ISysParamService; import org.redisson.api.RLock; import org.redisson.api.RedissonClient; import org.springframework.stereotype.Component; -import java.util.List; -import java.util.Objects; -import java.util.Set; +import java.util.*; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; @@ -60,14 +54,7 @@ public class AutoCreateInst { RLock lock = redissonClient.getLock("autoGenInstructionLock"); boolean locked = false; try { - String maxPsnumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue(); - String maxRtNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue(); - int maxPsInst = Integer.parseInt(maxPsnumber); - int maxRtnst = Integer.parseInt(maxRtNumber); - int rtInstNum = 0; - int psInstNum = 0; - long estimatedTime = (maxPsInst + maxRtnst) * 5L + 10; - locked = lock.tryLock(0, estimatedTime, TimeUnit.SECONDS); + locked = lock.tryLock(0, TimeUnit.SECONDS); if (!locked) { //log.debug("未获取到分布式锁,跳过本次执行"); return; @@ -77,24 +64,24 @@ public class AutoCreateInst { if (CollectionUtils.isEmpty(list)) { return; } - List pslist = list.stream().filter(r -> !"2".equals(r.getCar_type())).collect(Collectors.toList()); - List rtlist = list.stream().filter(r -> "2".equals(r.getCar_type())).collect(Collectors.toList()); + String maxPsnumber = paramService.findByCode(AcsConfig.MAXINSTNUMBER).getValue(); + String maxRtNumber = paramService.findByCode(AcsConfig.MAXRTINSTNUMBER).getValue(); + int maxPsInst = Integer.parseInt(maxPsnumber); + int maxRtnst = Integer.parseInt(maxRtNumber); + int rtInstNum = 0; + int psInstNum = 0; //已创建 List instructionList = new LambdaQueryChainWrapper<>(instructionMapper) .lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex()) .list(); + //2个车型各创建的任务数 if (ObjectUtil.isNotEmpty(instructionList)) { rtInstNum = Math.toIntExact(instructionList.stream().filter(r -> "2".equals(r.getCar_type())).count()); psInstNum = instructionList.size() - rtInstNum; } - if (ObjectUtil.isNotEmpty(pslist)) { - maxPsInst = Math.max(0, maxPsInst - psInstNum); - createInstruction(pslist, maxPsInst); - } - if (ObjectUtil.isNotEmpty(rtlist)) { - maxRtnst = Math.max(0, maxRtnst - rtInstNum); - createInstruction(rtlist, maxRtnst); - } + maxRtnst = Math.max(0, maxRtnst - rtInstNum); + maxPsInst = Math.max(0, maxPsInst - psInstNum); + createInstruction(list, maxPsInst, maxRtnst); } catch (Exception e) { log.error("自动生成指令异常", e); } finally { @@ -109,136 +96,64 @@ public class AutoCreateInst { } - private void createInstruction(List list, int maxNum) throws InterruptedException { - int createdCount = 0; - for (int i = 0; i < list.size(); i++) { - //每次循环前检查本次已创建指令数是否达到上限 - if (createdCount >= maxNum) { - break; - } - TaskDto acsTask = list.get(i); - Boolean flag = false; - String taskid = acsTask.getTask_id(); - String taskcode = acsTask.getTask_code(); - String task_type = acsTask.getTask_type(); - String vehiclecode = acsTask.getVehicle_code(); - String priority = acsTask.getPriority(); - String is_send = acsTask.getIs_send(); + private void createInstruction(List list, int maxPsNum, int maxRtNum) throws InterruptedException { + int psCreatedCount = 0; + int rtCreatedCount = 0; + // 记录被阻断的起点,该起点上的后续任务一律不创建防止插 + Set blockedPoints = new HashSet<>(); + Iterator iterator = list.iterator(); + while (iterator.hasNext()) { + TaskDto acsTask = iterator.next(); + String car_type = acsTask.getCar_type(); + // 判断是否为起点任务,NPE String start_device_code = acsTask.getStart_device_code(); + boolean isStartTask = start_device_code != null && + (start_device_code.contains("BCPRK") || start_device_code.contains("CPRK")); String start_point = null; - if (start_device_code.contains("BCPRK")) { - String[] parts = start_device_code.split("-", 2); - start_point = parts[0]; - } else if (start_device_code.contains("CPRK")) { - String[] parts = start_device_code.split("-", 2); - start_point = parts[0]; + if (isStartTask) { + start_point = start_device_code.split("-", 2)[0]; } - if (start_point != null) { - if (start_point.equals("CPRK1")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("CPRK1")) { - flag = true; - } - } - } else if (start_point.equals("CPRK2")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("CPRK2")) { - flag = true; - } - } - } else if (start_point.equals("CPRK3")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("CPRK3")) { - flag = true; - } - } - } else if (start_point.equals("CPRK4")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("CPRK4")) { - flag = true; - } - } - } else if (start_point.equals("CPRK5")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("CPRK5")) { - flag = true; - } - } - } else if (start_point.equals("BCPRK1")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("BCPRK1")) { - flag = true; - } - } - } else if (start_point.equals("BCPRK2")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("BCPRK2")) { - flag = true; - } - } - } else if (start_point.equals("BCPRK3")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("BCPRK3")) { - flag = true; - } - } - } else if (start_point.equals("BCPRK4")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("BCPRK4")) { - flag = true; - } - } - } else if (start_point.equals("BCPRK5")) { - List list1 = taskserver.queryAllByStatus("1"); - for (int j = 0; j < list1.size(); j++) { - String start_device_code1 = list1.get(j).getStart_device_code(); - String[] parts = start_device_code1.split("-", 2); - start_point = parts[0]; - if (start_point.equals("BCPRK5")) { - flag = true; - } - } - } - } - if (flag) { + //如果当前起点已被阻断,直接移除任务并跳过 + if (isStartTask && blockedPoints.contains(start_point)) { + iterator.remove(); continue; } + //型上限检查 + boolean reachLimit = false; + if ("2".equals(car_type) && rtCreatedCount >= maxRtNum) { + reachLimit = true; + } else if (!"2".equals(car_type) && psCreatedCount >= maxPsNum) { + reachLimit = true; + } + if (reachLimit) { + iterator.remove(); + if (isStartTask) { + blockedPoints.add(start_point); + } + continue; + } + if (StrUtil.equals(acsTask.getIs_send(), "0")) { + iterator.remove(); + if (isStartTask) { + blockedPoints.add(start_point); + } + continue; + } + List activeInstructions = new LambdaQueryChainWrapper<>(instructionMapper) + .lt(InstructionMybatis::getInstruction_status, InstructionStatusEnum.FINISHED.getIndex()) + .eq(InstructionMybatis::getIs_delete, "0") + .list(); + //起点重复检查 + if (isStartTask && checkinsList(activeInstructions, start_point)) { + blockedPoints.add(start_point); + iterator.remove(); + continue; + } + String taskid = acsTask.getTask_id(); + String taskcode = acsTask.getTask_code(); + String vehiclecode = acsTask.getVehicle_code(); + String priority = acsTask.getPriority(); + String task_type = acsTask.getTask_type(); String start_point_code = acsTask.getStart_point_code(); String put_device_code = acsTask.getPut_device_code(); String put_point_code = acsTask.getPut_point_code(); @@ -249,11 +164,7 @@ public class AutoCreateInst { String agv_system_type = acsTask.getAgv_system_type(); String start_height = acsTask.getStart_height(); String next_height = acsTask.getNext_height(); - String car_type = acsTask.getCar_type(); String car_width = acsTask.getCar_width(); - if (StrUtil.equals(is_send, "0")) { - continue; - } if (StrUtil.equals(appService.findDeviceTypeByCode(next_device_code), "storage")) { next_point_code = next_device_code + "-" + acsTask.getTo_y() + "-" + acsTask.getTo_z(); } else { @@ -287,6 +198,7 @@ public class AutoCreateInst { instdto.setAgv_system_type(agv_system_type); instdto.setStart_height(start_height); instdto.setNext_height(next_height); + instdto.setRemark(acsTask.getRemark()); try { instructionService.create(instdto); } catch (Exception e) { @@ -300,152 +212,31 @@ public class AutoCreateInst { luceneExecuteLogService.deviceExecuteLog(logDto); continue; } - TimeUnit.SECONDS.sleep(5); //创建指令后修改任务状态 acsTask.setTask_status(TaskStatusEnum.BUSY.getIndex()); acsTask.setUpdate_time(DateUtil.now()); taskserver.update(acsTask); log.info("自动生成指令成功: {},{}", DateUtil.now(), acsTask.getTask_code()); - createdCount++; - } - } - - - /** - * 根据任务状态创建指令、生成下一条指令 - */ - public void run1() throws Exception { - //log.info("自动生成指令开始: {}", DateUtil.now()); - RLock lock = redissonClient.getLock("autoGenInstructionLock"); - boolean locked = false; - try { - locked = lock.tryLock(0, 5, TimeUnit.SECONDS); // 不等待,锁持有5秒自动释放 - if (!locked) { - //log.debug("未获取到分布式锁,跳过本次执行"); - return; - } - TaskService taskserver = SpringContextHolder.getBean(TaskService.class); - InstructionService instructionService = SpringContextHolder.getBean(InstructionService.class); - DeviceAppService appService = SpringContextHolder.getBean(DeviceAppServiceImpl.class); - LuceneExecuteLogService luceneExecuteLogService = SpringContextHolder.getBean(LuceneExecuteLogServiceImpl.class); - //按优先级降序task_code升序 - List list = taskserver.queryAllByStatus("0"); - if (CollectionUtils.isEmpty(list)) { - return; - } - Set busyStartPoints = taskserver.queryAllByStatus("1").stream() - .map(t -> extractStartPoint(t.getStart_device_code())) - .filter(Objects::nonNull) - .collect(Collectors.toSet()); - for (TaskDto acsTask : list) { - if (isNonBlockingTaskType(acsTask)) { - continue; // AGV/Truss且不以"-"开头,跳过,继续看下一个 - } - if (StrUtil.equals(acsTask.getIs_send(), "0")) { - break; - } - //起始点冲突(同一起点已有执行中任务) - String startPoint = extractStartPoint(acsTask.getStart_device_code()); - if (startPoint != null && busyStartPoints.contains(startPoint)) { - break; - } - try { - createInstruction(acsTask, appService, instructionService, taskserver); - } catch (Exception e) { - acsTask.setRemark(e.getMessage()); - taskserver.updateByCodeFromCache(acsTask); - LuceneLogDto logDto = LuceneLogDto.builder() - .device_code("定时创建指令失败") - .content(e.getMessage()) - .build(); - logDto.setLog_level(2); - luceneExecuteLogService.deviceExecuteLog(logDto); - break; - } - break; - } - } catch (Exception e) { - log.error("自动生成指令异常", e); - } finally { - if (locked && lock.isHeldByCurrentThread()) { - try { - lock.unlock(); - } catch (Exception e) { - log.error("释放分布式锁异常", e); - } + if ("2".equals(car_type)) { + rtCreatedCount++; + } else { + psCreatedCount++; } + TimeUnit.SECONDS.sleep(1); } } - /** - * 判断是否属于无需生成指令的任务类型 - */ - private boolean isNonBlockingTaskType(TaskDto acsTask) { - String taskType = acsTask.getTask_type(); - String taskCode = acsTask.getTask_code(); - boolean isAgv = StrUtil.equals(taskType, TaskTypeEnum.AGV_Task.getIndex()) - && !StrUtil.startWith(taskCode, "-"); - boolean isTruss = StrUtil.equals(taskType, TaskTypeEnum.Truss_Task.getIndex()) - && !StrUtil.startWith(taskCode, "-"); - return isAgv || isTruss; + private boolean checkinsList(List instructList, String targetPoint) { + if (instructList == null || targetPoint == null) { + return false; + } + return instructList.stream().anyMatch(r -> { + String code = r.getStart_device_code(); + if (code == null) return false; + String[] parts = code.split("-", 2); + return targetPoint.equals(parts[0]); + }); } - /** - * 从设备编码中提取起点区域CPRK1, BCPRK2 - */ - private String extractStartPoint(String startDeviceCode) { - if (startDeviceCode == null) { - return null; - } - if (startDeviceCode.contains("BCPRK") || startDeviceCode.contains("CPRK")) { - return startDeviceCode.split("-")[0]; - } - return null; - } - /** - * 封装指令创建与任务状态更新 - */ - private void createInstruction(TaskDto acsTask, DeviceAppService appService, - InstructionService instructionService, TaskService taskserver) throws Exception { - String next_device_code = acsTask.getNext_device_code(); - String next_point_code; - if (StrUtil.equals(appService.findDeviceTypeByCode(next_device_code), "storage")) { - next_point_code = next_device_code + "-" + acsTask.getTo_y() + "-" + acsTask.getTo_z(); - } else { - next_point_code = next_device_code; - } - Instruction instdto = new Instruction(); - instdto.setInstruction_type(acsTask.getTask_type()); - instdto.setInstruction_id(IdUtil.simpleUUID()); - instdto.setRoute_plan_code(acsTask.getRoute_plan_code()); - instdto.setRemark(acsTask.getRemark()); - instdto.setMaterial(acsTask.getMaterial()); - instdto.setQuantity(acsTask.getQuantity()); - instdto.setTask_id(acsTask.getTask_id()); - instdto.setTask_code(acsTask.getTask_code()); - instdto.setVehicle_code(acsTask.getVehicle_code()); - instdto.setCreate_time(DateUtil.now()); - instdto.setCreate_by(SecurityUtils.getCurrentNickName()); - instdto.setStart_device_code(acsTask.getStart_point_code()); - instdto.setStart_point_code(acsTask.getStart_point_code()); - instdto.setPut_device_code(acsTask.getPut_device_code()); - instdto.setPut_point_code(acsTask.getPut_point_code()); - instdto.setNext_device_code(next_device_code); - instdto.setNext_point_code(next_point_code); - instdto.setCar_type(acsTask.getCar_type()); - instdto.setCar_width(acsTask.getCar_width()); - instdto.setPriority(acsTask.getPriority()); - instdto.setInstruction_status(InstructionStatusEnum.READY.getIndex()); - instdto.setExecute_device_code(acsTask.getStart_point_code()); - instdto.setVehicle_type(acsTask.getVehicle_type()); - instdto.setAgv_system_type(acsTask.getAgv_system_type()); - instdto.setStart_height(acsTask.getStart_height()); - instdto.setNext_height(acsTask.getNext_height()); - instructionService.create(instdto); - // 更新任务状态为执行中 - acsTask.setTask_status(TaskStatusEnum.BUSY.getIndex()); - acsTask.setUpdate_time(DateUtil.now()); - taskserver.update(acsTask); - } } diff --git a/acs/nladmin-ui/src/router/routers.js b/acs/nladmin-ui/src/router/routers.js index d516b9c..627f253 100644 --- a/acs/nladmin-ui/src/router/routers.js +++ b/acs/nladmin-ui/src/router/routers.js @@ -71,6 +71,19 @@ export const constantRouterMap = [ meta: { title: i18n.t('auto.common.Personal_center') } } ] + }, + { + path: '/acs/history/taskRecord', + component: Layout, + hidden: true, + children: [ + { + path: '', + component: (resolve) => require(['@/views/acs/history/taskRecord/index'], resolve), + name: 'TaskRecord', + meta: { title: '任务历史记录' } + } + ] } ] diff --git a/acs/nladmin-ui/src/views/acs/history/taskRecord/index.vue b/acs/nladmin-ui/src/views/acs/history/taskRecord/index.vue index 64796a3..8ea2652 100644 --- a/acs/nladmin-ui/src/views/acs/history/taskRecord/index.vue +++ b/acs/nladmin-ui/src/views/acs/history/taskRecord/index.vue @@ -475,6 +475,27 @@ export default { } }, created() { + // 处理从任务统计页面跳转过来的查询参数 + const { startPoint, endPoint, timeIndex, car_no, createTime, end_time, ...rest } = this.$route.query + if (startPoint) { + this.$set(this.crud.query, 'start_point_code', startPoint) + } + if (endPoint) { + this.$set(this.crud.query, 'next_point_code', endPoint) + } + if (timeIndex) { + this.$set(this.crud.query, 'timeIndex', timeIndex) + } + if (car_no) { + this.$set(this.crud.query, 'car_no', car_no) + } + // 处理日期范围参数 - 使用数组格式 [开始时间, 结束时间] + if (createTime && end_time) { + this.$set(this.crud.query, 'createTime', [createTime, end_time]) + } + // 合并其他查询参数 + Object.assign(this.crud.query, rest) + deviceCrud.selectDeviceList().then(data => { this.deviceList = data }) @@ -484,6 +505,12 @@ export default { getDicts().then(data => { this.dicts = data }) + // 如果有从任务统计页面跳转过来的查询参数,自动刷新查询 + if (startPoint || endPoint || timeIndex || car_no || createTime) { + this.$nextTick(() => { + this.crud.toQuery() + }) + } }, methods: { // 钩子:在获取表格数据之前执行,false 则代表不获取数据 @@ -526,6 +553,10 @@ export default { material_type: this.crud.query.material_type, status: this.crud.query.status, point_code: this.crud.query.point_code, + start_point_code: this.crud.query.start_point_code, + next_point_code: this.crud.query.next_point_code, + car_no: this.crud.query.car_no, + timeIndex: this.crud.query.timeIndex, createTime: formatDateTime(timeRange[0]), end_time: formatDateTime(timeRange[1]) } diff --git a/acs/nladmin-ui/src/views/acs/history/taskSheet/index.vue b/acs/nladmin-ui/src/views/acs/history/taskSheet/index.vue index 257364b..1aeae17 100644 --- a/acs/nladmin-ui/src/views/acs/history/taskSheet/index.vue +++ b/acs/nladmin-ui/src/views/acs/history/taskSheet/index.vue @@ -35,10 +35,26 @@ > - - - - + + + + + + + + + + + + @@ -55,10 +71,48 @@ > - - - - + + + + + + + + + + + + + + + + +

+
稼动率统计
+ + + + + + + + +
@@ -75,18 +129,20 @@ export default { query: { dateRange: [] }, - // 入库数据 + // 入库数据 (AA->AB/AD/AC) inboundData: [ - { startPoint: 'AA/缓存区', endPoint: 'AB', item1: '', item2: '', item3: '', item4: '' }, - { startPoint: 'AA/缓存区', endPoint: 'AD', item1: '', item2: '', item3: '', item4: '' }, - { startPoint: 'AA/缓存区', endPoint: 'AC', item1: '', item2: '', item3: '', item4: '' } + { startPoint: 'AA', endPoint: 'AB', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' }, + { startPoint: 'AA', endPoint: 'AD', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' }, + { startPoint: 'AA', endPoint: 'AC', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' } ], - // 出库数据 + // 出库数据 (AB/AD/AC->AA) outboundData: [ - { startPoint: 'AB', endPoint: 'AA/缓存区', item1: '', item2: '', item3: '', item4: '' }, - { startPoint: 'AD', endPoint: 'AA/缓存区', item1: '', item2: '', item3: '', item4: '' }, - { startPoint: 'AC', endPoint: 'AA/缓存区', item1: '', item2: '', item3: '', item4: '' } - ] + { startPoint: 'AB', endPoint: 'AA', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' }, + { startPoint: 'AD', endPoint: 'AA', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' }, + { startPoint: 'AC', endPoint: 'AA', item1: '', item2: '', item3: '', item4: '', item1Key: '', item2Key: '', item3Key: '', item4Key: '' } + ], + // 稼动率数据 (动态从后端获取) + carData: [] } }, mounted() { @@ -101,27 +157,173 @@ export default { } queryTaskSheet(params).then(res => { if (res) { - this.fillData(res) + this.fillData(res[0]) } }) }, fillData(data) { - // 入库数据填充 (item1-item12) + // 入库数据填充 (AA-AB-X-Y, AA-AD-X-Y, AA-AC-X-Y) for (let i = 0; i < 3; i++) { - const baseIndex = i * 4 - this.inboundData[i].item1 = data[0][`item${baseIndex + 1}`] ? data[0][`item${baseIndex + 1}`] + '%' : '0%' - this.inboundData[i].item2 = data[0][`item${baseIndex + 2}`] ? data[0][`item${baseIndex + 2}`] + '%' : '0%' - this.inboundData[i].item3 = data[0][`item${baseIndex + 3}`] ? data[0][`item${baseIndex + 3}`] + '%' : '0%' - this.inboundData[i].item4 = data[0][`item${baseIndex + 4}`] ? data[0][`item${baseIndex + 4}`] + '%' : '0%' + const start = this.inboundData[i].startPoint + const end = this.inboundData[i].endPoint + + // 时间段1-3分钟 (timeIndex=1) + this.inboundData[i].item1Key = `${start}-${end}-1` + this.inboundData[i].item1 = this.getValue(data, start, end, 1) + + // 时间段3-5分钟 (timeIndex=2) + this.inboundData[i].item2Key = `${start}-${end}-2` + this.inboundData[i].item2 = this.getValue(data, start, end, 2) + + // 时间段5-8分钟 (timeIndex=3) + this.inboundData[i].item3Key = `${start}-${end}-3` + this.inboundData[i].item3 = this.getValue(data, start, end, 3) + + // 时间段8分钟以上 (timeIndex=4) + this.inboundData[i].item4Key = `${start}-${end}-4` + this.inboundData[i].item4 = this.getValue(data, start, end, 4) } - // 出库数据填充 (item13-item24) + + // 出库数据填充 (AB-AA-X-Y, AD-AA-X-Y, AC-AA-X-Y) for (let i = 0; i < 3; i++) { - const baseIndex = 12 + i * 4 - this.outboundData[i].item1 = data[0][`item${baseIndex + 1}`] ? data[0][`item${baseIndex + 1}`] + '%' : '0%' - this.outboundData[i].item2 = data[0][`item${baseIndex + 2}`] ? data[0][`item${baseIndex + 2}`] + '%' : '0%' - this.outboundData[i].item3 = data[0][`item${baseIndex + 3}`] ? data[0][`item${baseIndex + 3}`] + '%' : '0%' - this.outboundData[i].item4 = data[0][`item${baseIndex + 4}`] ? data[0][`item${baseIndex + 4}`] + '%' : '0%' + const start = this.outboundData[i].startPoint + const end = this.outboundData[i].endPoint + + this.outboundData[i].item1Key = `${start}-${end}-1` + this.outboundData[i].item1 = this.getValue(data, start, end, 1) + + this.outboundData[i].item2Key = `${start}-${end}-2` + this.outboundData[i].item2 = this.getValue(data, start, end, 2) + + this.outboundData[i].item3Key = `${start}-${end}-3` + this.outboundData[i].item3 = this.getValue(data, start, end, 3) + + this.outboundData[i].item4Key = `${start}-${end}-4` + this.outboundData[i].item4 = this.getValue(data, start, end, 4) } + + // 稼动率数据填充 (car-X-Y) + this.fillCarData(data) + }, + // 填充稼动率数据 + fillCarData(data) { + const carData = [] + // 后端格式: car-{车辆号}-{列号},如 car-2-1 表示车辆2的第1列(车辆编号) + const carMap = new Map() + + Object.keys(data).forEach(key => { + if (key.startsWith('car-')) { + const parts = key.split('-') + if (parts.length >= 3) { + const carNo = parts[1] + const colIndex = parseInt(parts[2]) + if (!carMap.has(carNo)) { + carMap.set(carNo, {}) + } + carMap.get(carNo)[colIndex] = data[key] + } + } + }) + + // 按车辆编号排序并构建数据 + const sortedCarNos = Array.from(carMap.keys()).sort((a, b) => parseInt(a) - parseInt(b)) + + sortedCarNos.forEach(carNo => { + const carInfo = carMap.get(carNo) + // 列1: 车辆编号, 列2: 实际运行总时长, 列3: 标准工作时间, 列4: 总任务数, 列5: 稼动率, 列6: 平均耗时 + carData.push({ + carNo: carInfo[1] || carNo, // 车辆编号 + actualTime: carInfo[2] || '0', // 实际运行总时长 + standardTime: carInfo[3] || '0', // 标准工作时间 + totalTasks: carInfo[4] || '0', // 总任务数 + utilizationRate: carInfo[5] ? carInfo[5] + '%' : '0%', // 稼动率 + avgTime: carInfo[6] || '0' // 平均耗时 + }) + }) + + this.carData = carData + }, + // 获取百分比值 + getValue(data, start, end, timeIndex) { + // 查找匹配的key,格式: start-end-timeIndex-index + for (let index = 1; index <= 30; index++) { + const key = `${start}-${end}-${timeIndex}-${index}` + if (data[key] !== undefined) { + return data[key] + '%' + } + } + return '0%' + }, + // 获取日期范围参数 + getDateRangeParams() { + let startDate, endDate + if (this.query.dateRange && this.query.dateRange.length === 2) { + startDate = this.query.dateRange[0] + endDate = this.query.dateRange[1] + } else { + // 如果没有选择日期范围,使用今天日期 + const today = new Date() + const year = today.getFullYear() + const month = String(today.getMonth() + 1).padStart(2, '0') + const day = String(today.getDate()).padStart(2, '0') + startDate = `${year}-${month}-${day}` + endDate = startDate + } + return { + createTime: `${startDate} 00:00:00`, + end_time: `${endDate} 23:59:59` + } + }, + // 点击百分比跳转到任务历史记录页面 + handleClick(key, value) { + if (!key || value === '0%') { + return + } + // 解析key,如 "AA-AB-1" 或 "car-1" + const parts = key.split('-') + const query = {} + + if (parts.length >= 3) { + // 格式: AA-AB-1-X 或 car-1-X + if (parts[0] === 'car') { + // car-1-X 格式 -> car_type=1 + query.car_no = parts[1] + } else { + // AA-AB-1-X 格式 -> startPoint=AA, endPoint=AB, timeIndex=1 + query.startPoint = parts[0] + query.endPoint = parts[1] + query.timeIndex = parts[2] + } + } + + // 添加日期范围参数 + const dateParams = this.getDateRangeParams() + query.createTime = dateParams.createTime + query.end_time = dateParams.end_time + + // 跳转到任务历史记录页面 + this.$router.push({ + path: '/acs/history/taskRecord', + query: query + }) + }, + // 点击车辆跳转到任务历史记录页面 + handleCarClick(carNo) { + if (!carNo) { + return + } + // 构建查询参数 + const query = { car_no: carNo } + // 添加日期范围参数 + const dateParams = this.getDateRangeParams() + query.createTime = dateParams.createTime + query.end_time = dateParams.end_time + + // 跳转到任务历史记录页面 + this.$router.push({ + path: '/acs/history/taskRecord', + query: query + }) }, // 导出所有表格 exportAll() { @@ -132,44 +334,33 @@ export default { const data = [] // 添加入库统计数据 - data.push(['入库统计']) // 添加入库统计标题 - data.push(header) // 添加表头 + data.push(['入库统计']) + data.push(header) this.inboundData.forEach(item => { - data.push([ - item.startPoint, - item.endPoint, - item.item1, - item.item2, - item.item3, - item.item4 - ]) + data.push([item.startPoint, item.endPoint, item.item1, item.item2, item.item3, item.item4]) }) - data.push([]) // 空行分隔 + data.push([]) // 添加出库统计数据 - data.push(['出库统计']) // 添加出库统计标题 - data.push(header) // 添加表头 + data.push(['出库统计']) + data.push(header) this.outboundData.forEach(item => { - data.push([ - item.startPoint, - item.endPoint, - item.item1, - item.item2, - item.item3, - item.item4 - ]) + data.push([item.startPoint, item.endPoint, item.item1, item.item2, item.item3, item.item4]) + }) + data.push([]) + + // 添加稼动率统计数据 + data.push(['稼动率统计']) + data.push(['车辆', '实际运行总时长', '标准工作时间', '总任务数', '稼动率', '平均耗时']) + this.carData.forEach(item => { + data.push([item.carNo, item.actualTime, item.standardTime, item.totalTasks, item.utilizationRate, item.avgTime]) }) const worksheet = XLSX.utils.aoa_to_sheet(data) // 设置列宽 worksheet['!cols'] = [ - { wch: 15 }, - { wch: 15 }, - { wch: 12 }, - { wch: 12 }, - { wch: 12 }, - { wch: 15 } + { wch: 15 }, { wch: 15 }, { wch: 12 }, { wch: 12 }, { wch: 12 }, { wch: 15 } ] // 设置样式 @@ -180,16 +371,13 @@ export default { const cellAddress = XLSX.utils.encode_cell({ r: R, c: C }) if (!worksheet[cellAddress]) continue - // 设置"入库统计"和"出库统计"标题样式(第1行和第6行) if (R === 0 || R === 5) { worksheet[cellAddress].s = { fill: { fgColor: { rgb: "FFFFFF" } }, font: { bold: true, sz: 14 }, alignment: { horizontal: "center", vertical: "center" } } - } - // 设置表头样式(第2行和第7行) - else if (R === 1 || R === 6) { + } else if (R === 1 || R === 6) { worksheet[cellAddress].s = { fill: { fgColor: { rgb: "F5F7FA" } }, font: { bold: true }, @@ -200,10 +388,8 @@ export default { } } - // 添加工作表到工作簿 XLSX.utils.book_append_sheet(workbook, worksheet, 'Sheet1') - // 生成文件名 let filename = '任务统计' if (this.query.dateRange && this.query.dateRange.length === 2) { filename = `${filename}_${this.query.dateRange[0]}至${this.query.dateRange[1]}` @@ -215,7 +401,6 @@ export default { // 入库表格合并方法 - 合并起点列 inboundSpanMethod({ rowIndex, columnIndex }) { if (columnIndex === 0) { - // 起点列,第一行合并3行 if (rowIndex === 0) { return { rowspan: 3, colspan: 1 } } else { @@ -226,7 +411,6 @@ export default { // 出库表格合并方法 - 合并终点列 outboundSpanMethod({ rowIndex, columnIndex }) { if (columnIndex === 1) { - // 终点列,第一行合并3行 if (rowIndex === 0) { return { rowspan: 3, colspan: 1 } } else { @@ -241,14 +425,18 @@ export default { return {} }, headerCellStyle({ columnIndex }) { - // 时间列头背景色: 5-8分钟黄色, 8分钟以上红色 if (columnIndex === 4) { return { backgroundColor: '#ffff00', color: '#000' } } else if (columnIndex === 5) { return { backgroundColor: '#f46262', color: '#000' } } return { backgroundColor: '#f5f7fa', color: '#000' } - } + }, + // 稼动率表格表头样式(普通颜色,无黄红标记) + carHeaderCellStyle() { + return { backgroundColor: '#f5f7fa', color: '#000' } + }, + // 点击车辆跳转到任务历史记录页面 } } @@ -263,4 +451,12 @@ export default { text-align: center; margin-bottom: 15px; } +.clickable-link { + color: #409EFF; + cursor: pointer; + text-decoration: underline; +} +.clickable-link:hover { + color: #66b1ff; +} diff --git a/acs/nladmin-ui/src/views/system/param/index.vue b/acs/nladmin-ui/src/views/system/param/index.vue index fb183fe..e5cd28a 100644 --- a/acs/nladmin-ui/src/views/system/param/index.vue +++ b/acs/nladmin-ui/src/views/system/param/index.vue @@ -4,6 +4,26 @@
+ + 配置自动充电 + + + 充电桩管理 +
+ + @@ -67,7 +89,8 @@ import CRUD, { presenter, header, form, crud } from '@crud/crud' import crudOperation from '@crud/CRUD.operation' import udOperation from '@crud/UD.operation' import pagination from '@crud/Pagination' - +import TubeDialog2 from '@/views/system/param/tubeDialog2.vue' +import StationDialog from '@/views/system/param/stationDialog.vue' const defaultForm = { id: null, code: null, @@ -78,7 +101,7 @@ const defaultForm = { } export default { name: 'Param', - components: { pagination, crudOperation, udOperation }, + components: { pagination, crudOperation, udOperation, TubeDialog2, StationDialog }, mixins: [presenter(), header(), form(defaultForm), crud()], cruds() { return CRUD({ title: 'menu.table_title.SystemParam', url: 'api/param', idField: 'id', sort: 'id,desc', crudMethod: { ...crudParam }, @@ -98,7 +121,8 @@ export default { edit: ['admin', 'param:edit'], del: ['admin', 'param:del'] }, - + showView2: false, + showStation: false, rules: { id: [ { required: true, message: this.$t('SysParam.rules.NotNull'), trigger: 'blur' } @@ -130,6 +154,12 @@ export default { [CRUD.HOOK.beforeRefresh]() { return true }, + divOpen() { + this.showView2 = true + }, + divOpenStation() { + this.showStation = true + }, webSocket() { const that = this if (typeof (WebSocket) === 'undefined') { diff --git a/acs/nladmin-ui/src/views/system/param/param.js b/acs/nladmin-ui/src/views/system/param/param.js index 9050af5..af09fc3 100644 --- a/acs/nladmin-ui/src/views/system/param/param.js +++ b/acs/nladmin-ui/src/views/system/param/param.js @@ -30,5 +30,43 @@ export function getValueByCode(code) { method: 'post' }) } +export function queryParam() { + return request({ + url: '/api/param/queryParam', + method: 'get' + }) +} -export default { add, edit, del, getValueByCode } +export function setParam(data) { + return request({ + url: 'api/param/setParam', + method: 'post', + data + }) +} + +export function showDetail2(params) { + return request({ + url: 'api/dict/showDetail2', + method: 'get', + params + }) +} + +export function showDetail3(params) { + return request({ + url: 'api/dict/showDetail3', + method: 'get', + params + }) +} + +export function initDict(data) { + return request({ + url: 'api/dict/initDict', + method: 'post', + data + }) +} + +export default { add, edit, del, getValueByCode, setParam, showDetail2, initDict, showDetail3 } diff --git a/acs/nladmin-ui/src/views/system/param/stationDialog.vue b/acs/nladmin-ui/src/views/system/param/stationDialog.vue new file mode 100644 index 0000000..f0ad362 --- /dev/null +++ b/acs/nladmin-ui/src/views/system/param/stationDialog.vue @@ -0,0 +1,150 @@ + + + + + diff --git a/acs/nladmin-ui/src/views/system/param/tubeDialog2.vue b/acs/nladmin-ui/src/views/system/param/tubeDialog2.vue new file mode 100644 index 0000000..3954ff6 --- /dev/null +++ b/acs/nladmin-ui/src/views/system/param/tubeDialog2.vue @@ -0,0 +1,136 @@ + + + + + diff --git a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dto/StrategyStructParam.java b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dto/StrategyStructParam.java index f05de94..8cfa4ea 100644 --- a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dto/StrategyStructParam.java +++ b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dto/StrategyStructParam.java @@ -33,6 +33,11 @@ public class StrategyStructParam { */ private String ext_type; + /** + * 起点 + */ + private String point_code1; + /** * 出入库类型 */ diff --git a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java index 88b99fc..e433ffa 100644 --- a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java +++ b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java @@ -434,7 +434,7 @@ public class StructattrServiceImpl extends ServiceImpl strategy = one.getStrategy(); Map decisionerMap = SpringContextHolder.getBeansOfType(Decisioner.class); @@ -478,16 +478,24 @@ public class StructattrServiceImpl extends ServiceImpl list = this.list(query); + //特殊载具规则 if ("BCPCTZB".equals(param.getStoragevehicle_type()) || "DJQCT".equals(param.getStoragevehicle_type())) { list = structattrMapper.getctnextcode(); - } - if ("2FCP3C".equals(param.getStoragevehicle_type()) && ObjectUtil.isEmpty(list)) { + //只入234层 + } else if ("DJQMZB".equals(param.getStoragevehicle_type())) { + list.removeIf(r -> r.getLayer_num().equals(1)); + } else if ("2FCP3C".equals(param.getStoragevehicle_type()) && ObjectUtil.isEmpty(list)) { query.eq("is_used", true) .eq("lock_type", IOSEnum.LOCK_TYPE.code("未锁定")) .eq("sect_code", param.getSect_code()) .isNull("storagevehicle_code"); list = this.list(query); } + //CNC点位不入4层 + if (param.getPoint_code1().contains("BCPRK6")) { + Integer finalMaxLayerNum = maxLayerNum; + list.removeIf(r -> r.getLayer_num().equals(finalMaxLayerNum)); + } for (String decisionerType : strategy) { Decisioner decisioner = decisionerMap.get(decisionerType); log.info("执行入库规格:" + decisioner.strategyConfig.getStrategy_name()); diff --git a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/warehouse_manage/inAndOut/service/impl/InBillServiceImpl.java b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/warehouse_manage/inAndOut/service/impl/InBillServiceImpl.java index 2f540fe..3559c7e 100644 --- a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/warehouse_manage/inAndOut/service/impl/InBillServiceImpl.java +++ b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/warehouse_manage/inAndOut/service/impl/InBillServiceImpl.java @@ -597,6 +597,7 @@ public class InBillServiceImpl extends ServiceImpl i String iostorinvId = param.getString("iostorinv_id"); String storagevehicleCode = param.getString("storagevehicle_code"); String storagevehicle_stype = param.getString("storagevehicle_type"); + String point_code1 = param.getString("point_code"); MdPbStoragevehicletype mdPbStoragevehicletype = iMdPbStoragevehicletypeService.getByCode(storagevehicle_stype); //处理不同库区,一楼半成品特殊区域待检区 if ("DJQHDL".equals(storagevehicle_stype) || "DJQMZB".equals(storagevehicle_stype) || "DJQCT".equals(storagevehicle_stype)) { @@ -642,6 +643,7 @@ public class InBillServiceImpl extends ServiceImpl i .suitable_car(suitable_car) .strategyMaters(maters) .storagevehicle_type(storagevehicle_stype) + .point_code1(point_code1) .build()); Structattr struct = structattrs.get(0); sect_id = struct.getSect_id(); diff --git a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/wbwms/service/impl/WmsToIWmsServiceImpl.java b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/wbwms/service/impl/WmsToIWmsServiceImpl.java index 0db9181..9ed136b 100644 --- a/nladmin-system/nlsso-server/src/main/java/org/nl/wms/wbwms/service/impl/WmsToIWmsServiceImpl.java +++ b/nladmin-system/nlsso-server/src/main/java/org/nl/wms/wbwms/service/impl/WmsToIWmsServiceImpl.java @@ -354,8 +354,9 @@ public class WmsToIWmsServiceImpl implements WmsToIWmsService { if (CollectionUtils.isNotEmpty(list)) { for (SchBasePoint point : list) { JSONObject pointData = new JSONObject(); + pointData.put("barcode", StringUtils.isBlank(point.getVehicle_code()) ? "" : point.getVehicle_code()); pointData.put("point_code", point.getPoint_code()); - pointData.put("status", point.getPoint_status().equals(PointStatusEnum.EMPTY_POINT.getCode()) && !point.getLock_up() ? "0" : "1"); + pointData.put("status", point.getPoint_status().equals(PointStatusEnum.EMPTY_POINT.getCode()) && StringUtils.isBlank(point.getVehicle_code()) ? "0" : "1"); dataList.add(pointData); } }