| | |
| | | if (!Cools.isEmpty(param.getStatus())) { |
| | | switch (param.getStatus()) { |
| | | case "Assigned": |
| | | // AGV已派车,确认接收命令,记录确认时间 |
| | | if (task.getPlcStrTime() == null) { |
| | | task.setPlcStrTime(new Date()); |
| | | // log.info("AGV已确认接收命令,记录确认时间,taskId:{}", taskId); |
| | | } |
| | | if (Cools.isEmpty(robotGroup)) { |
| | | task.setInvWh(param.getRobotName()); |
| | | } |
| | |
| | | |
| | | /** |
| | | * 检查AGV任务对应的工作档是否已完成或已转历史档并完结 |
| | | * 处理被跳过的AGV任务:如果工作档已完成(wrk_sts=4,5,14,15)或已转历史档并完结,则完结AGV任务 |
| | | * 处理被跳过的AGV任务: |
| | | * 1. 如果工作档已完成(wrk_sts=4,5,14,15)或已转历史档并完结,则完结AGV任务 |
| | | * 2. 如果工作档和历史档都没有数据,但是AGV已确认接收命令后超过1小时处于搬运中(状态8),也结束AGV任务 |
| | | * 注意:只有AGV确认接收命令后(plcStrTime不为空)才开始计时,如果AGV接受命令失败,会继续呼叫AGV |
| | | */ |
| | | @Scheduled(cron = "0/10 * * * * ? ") |
| | | private void checkCompletedTasksInHistory() { |
| | |
| | | new EntityWrapper<Task>() |
| | | .eq("task_type", "agv") |
| | | .eq("wrk_sts", 8L) // 已呼叫AGV状态 |
| | | .isNotNull("wrk_no") |
| | | ); |
| | | |
| | | if (agvTasks.isEmpty()) { |
| | |
| | | Date now = new Date(); |
| | | int completedCount = 0; |
| | | List<Task> completedTasks = new ArrayList<>(); |
| | | // 1小时的毫秒数(从AGV确认接收命令开始计时) |
| | | long oneHourInMillis = 60 * 60 * 1000L; |
| | | |
| | | for (Task agvTask : agvTasks) { |
| | | boolean isCompleted = false; |
| | |
| | | wrkMast = wrkMastService.selectOne( |
| | | new EntityWrapper<WrkMast>().eq("wrk_no", agvTask.getWrkNo()) |
| | | ); |
| | | } |
| | | |
| | | // 检查历史档是否存在(无论工作档是否存在都需要检查) |
| | | WrkMastLog wrkMastLog = null; |
| | | // 优先通过wrk_no查询历史档 |
| | | if (agvTask.getWrkNo() != null) { |
| | | wrkMastLog = wrkMastLogService.selectOne( |
| | | new EntityWrapper<WrkMastLog>().eq("wrk_no", agvTask.getWrkNo()) |
| | | ); |
| | | } |
| | | // 如果通过wrk_no没找到,且有条码,则通过条码查询 |
| | | if (wrkMastLog == null && !Cools.isEmpty(agvTask.getBarcode())) { |
| | | List<WrkMastLog> logList = wrkMastLogService.selectList( |
| | | new EntityWrapper<WrkMastLog>().eq("barcode", agvTask.getBarcode()) |
| | | ); |
| | | if (!logList.isEmpty()) { |
| | | wrkMastLog = logList.get(0); // 取第一个 |
| | | } |
| | | } |
| | | |
| | | // 如果工作档存在,检查是否已完成 |
| | |
| | | reason = String.format("工作档已完成,状态:%d", wrkSts); |
| | | } |
| | | } |
| | | } else { |
| | | // 如果工作档不存在,检查历史档 |
| | | WrkMastLog wrkMastLog = null; |
| | | |
| | | // 优先通过wrk_no查询历史档 |
| | | if (agvTask.getWrkNo() != null) { |
| | | wrkMastLog = wrkMastLogService.selectOne( |
| | | new EntityWrapper<WrkMastLog>().eq("wrk_no", agvTask.getWrkNo()) |
| | | ); |
| | | } |
| | | |
| | | // 如果通过wrk_no没找到,且有条码,则通过条码查询 |
| | | if (wrkMastLog == null && !Cools.isEmpty(agvTask.getBarcode())) { |
| | | List<WrkMastLog> logList = wrkMastLogService.selectList( |
| | | new EntityWrapper<WrkMastLog>().eq("barcode", agvTask.getBarcode()) |
| | | ); |
| | | if (!logList.isEmpty()) { |
| | | wrkMastLog = logList.get(0); // 取第一个 |
| | | } |
| | | } |
| | | |
| | | // 如果历史档存在且已完结,则完结AGV任务 |
| | | if (wrkMastLog != null) { |
| | | // 如果工作档不存在或未完成,检查历史档是否已完结 |
| | | if (!isCompleted && wrkMastLog != null) { |
| | | Integer ioType = agvTask.getIoType(); |
| | | long logWrkSts = wrkMastLog.getWrkSts(); |
| | | |
| | |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 如果工作档和历史档都没有数据,检查是否超过1小时(从AGV确认接收命令开始计时) |
| | | if (!isCompleted && wrkMast == null && wrkMastLog == null) { |
| | | // 只有AGV确认接收命令后(plcStrTime不为空)才开始计时 |
| | | // 如果plcStrTime为空,说明AGV还没有确认接收命令,会继续呼叫,不结束任务 |
| | | Date agvConfirmedTime = agvTask.getPlcStrTime(); |
| | | |
| | | if (agvConfirmedTime != null) { |
| | | long timeDiff = now.getTime() - agvConfirmedTime.getTime(); |
| | | if (timeDiff >= oneHourInMillis) { |
| | | isCompleted = true; |
| | | long hours = timeDiff / (60 * 60 * 1000L); |
| | | long minutes = (timeDiff % (60 * 60 * 1000L)) / (60 * 1000L); |
| | | reason = String.format("工作档和历史档都不存在,AGV确认接收命令后超过1小时(实际:%d小时%d分钟)处于搬运中,自动结束", hours, minutes); |
| | | } |
| | | } |
| | | // 如果plcStrTime为空,说明AGV还没有确认接收命令,不结束任务,继续等待呼叫 |
| | | } |
| | | |
| | | // 如果已完成,更新AGV任务状态并收集到列表 |
| | |
| | | } |
| | | |
| | | if (completedCount > 0) { |
| | | log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档)", completedCount); |
| | | log.info("本次检查完结了{}个AGV呼叫单(工作档已完成或已转历史档或确认接收后超时)", completedCount); |
| | | } |
| | | } catch (Exception e) { |
| | | log.error("检查工作档已完成或历史档完结任务并完结AGV呼叫单异常", e); |
| | |
| | | for (Task task : taskList) { |
| | | // 如果任务状态已经是8(已呼叫AGV,正在搬运),则不再发送指令 |
| | | if (task.getWrkSts() != null && task.getWrkSts() == 8L) { |
| | | log.debug("任务ID:{}状态已是8(正在搬运),跳过发送", task.getId()); |
| | | // log.debug("任务ID:{}状态已是8(正在搬运),跳过发送", task.getId()); |
| | | continue; |
| | | } |
| | | |
| | |
| | | String errorMsg = allocateSiteForTask(task); |
| | | if (errorMsg != null) { |
| | | // 无法分配站点,只在日志中记录,不记录到任务中(app不需要知道) |
| | | log.warn("任务ID:{}无法分配站点:{}", task.getId(), errorMsg); |
| | | // log.warn("任务ID:{}无法分配站点:{}", task.getId(), errorMsg); |
| | | continue; |
| | | } |
| | | // 检查是否成功分配了站点(如果返回null且staNo仍为空,说明所有站点都在搬运,等待下次再试) |
| | |
| | | // 所有站点都在搬运,暂不分配,等待下次定时任务再尝试 |
| | | continue; |
| | | } |
| | | log.info("任务ID:{}已分配站点:{}", task.getId(), staNo); |
| | | // log.info("任务ID:{}已分配站点:{}", task.getId(), staNo); |
| | | } |
| | | |
| | | // 检查目标站点是否有效(不为0且存在) |
| | |
| | | Integer siteNo = Integer.parseInt(staNo); |
| | | // 检查站点是否为0(无效站点),如果是0则不发送,但不清空站点 |
| | | if (siteNo == null || siteNo == 0) { |
| | | log.warn("任务ID:{}的目标站点{}无效(为0),跳过发送,保留站点分配", task.getId(), staNo); |
| | | // log.warn("任务ID:{}的目标站点{}无效(为0),跳过发送,保留站点分配", task.getId(), staNo); |
| | | continue; |
| | | } |
| | | List<BasDevp> basDevpList = basDevpMapper.selectList(new EntityWrapper<BasDevp>().eq("dev_no", siteNo)); |
| | | if (basDevpList == null || basDevpList.isEmpty()) { |
| | | // 站点不存在,跳过发送,不清空站点 |
| | | log.warn("任务ID:{}的目标站点{}不存在,跳过发送,保留站点分配", task.getId(), staNo); |
| | | // log.warn("任务ID:{}的目标站点{}不存在,跳过发送,保留站点分配", task.getId(), staNo); |
| | | continue; |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | // 站点格式错误,跳过发送,不清空站点 |
| | | log.warn("任务ID:{}的目标站点{}格式错误,跳过发送,保留站点分配", task.getId(), staNo); |
| | | // log.warn("任务ID:{}的目标站点{}格式错误,跳过发送,保留站点分配", task.getId(), staNo); |
| | | continue; |
| | | } |
| | | } else { |
| | |
| | | ); |
| | | |
| | | if (!transportingTasks.isEmpty()) { |
| | | log.info("站点{}有{}个正在搬运的{}AGV任务,跳过当前任务ID:{}", |
| | | staNo, transportingTasks.size(), taskType, task.getId()); |
| | | // log.info("站点{}有{}个正在搬运的{}AGV任务,跳过当前任务ID:{}", |
| | | // staNo, transportingTasks.size(), taskType, task.getId()); |
| | | continue; |
| | | } |
| | | } |
| | |
| | | |
| | | // 如果重试次数已达到最大值,跳过本次发送 |
| | | if (retryEnabled && currentRetryCount >= maxRetryCount) { |
| | | log.warn("{}呼叫agv搬运 - 任务ID:{}已达到最大重试次数({}),停止重试", |
| | | namespace, task.getId(), maxRetryCount); |
| | | // log.warn("{}呼叫agv搬运 - 任务ID:{}已达到最大重试次数({}),停止重试", |
| | | // namespace, task.getId(), maxRetryCount); |
| | | // 记录最终失败信息 |
| | | task.setErrorTime(new Date()); |
| | | task.setErrorMemo(String.format("AGV呼叫失败,已达到最大重试次数(%d次)", maxRetryCount)); |
| | |
| | | } |
| | | |
| | | // 打印请求信息(包含重试次数) |
| | | if (currentRetryCount > 0) { |
| | | log.info("{}呼叫agv搬运(第{}次重试) - 请求地址:{}", namespace, currentRetryCount + 1, url); |
| | | } else { |
| | | log.info("{}呼叫agv搬运 - 请求地址:{}", namespace, url); |
| | | } |
| | | log.info("{}呼叫agv搬运 - 请求参数:{}", namespace, body); |
| | | // if (currentRetryCount > 0) { |
| | | // log.info("{}呼叫agv搬运(第{}次重试) - 请求地址:{}", namespace, currentRetryCount + 1, url); |
| | | // } else { |
| | | // log.info("{}呼叫agv搬运 - 请求地址:{}", namespace, url); |
| | | // } |
| | | // log.info("{}呼叫agv搬运 - 请求参数:{}", namespace, body); |
| | | |
| | | try { |
| | | // 使用仙工M4接口 |
| | |
| | | .build() |
| | | .doPost(); |
| | | // 打印返回参数 |
| | | log.info("{}呼叫agv搬运 - 返回参数:{}", namespace, response); |
| | | // log.info("{}呼叫agv搬运 - 返回参数:{}", namespace, response); |
| | | |
| | | // 检查响应是否为空 |
| | | if (response == null || response.trim().isEmpty()) { |
| | | String errorMsg = "AGV接口返回为空"; |
| | | log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | // log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); |
| | | continue; |
| | | } |
| | |
| | | JSONObject jsonObject = JSON.parseObject(response); |
| | | if (jsonObject == null) { |
| | | String errorMsg = "响应JSON解析失败,响应内容:" + response; |
| | | log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | // log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); |
| | | continue; |
| | | } |
| | |
| | | task.setErrorTime(null); |
| | | task.setErrorMemo(null); |
| | | taskService.updateById(task); |
| | | log.info("{}呼叫agv搬运成功 - 任务ID:{}", namespace, task.getId()); |
| | | // log.info("{}呼叫agv搬运成功 - 任务ID:{}", namespace, task.getId()); |
| | | } else { |
| | | String message = jsonObject.getString("message"); |
| | | String errorMsg = String.format("错误码:%s,错误信息:%s", code, message); |
| | | log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | // log.error("{}呼叫agv搬运失败 - 任务ID:{},{}", namespace, task.getId(), errorMsg); |
| | | handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); |
| | | } |
| | | } catch (Exception e) { |
| | | String errorMsg = "异常信息:" + e.getMessage(); |
| | | log.error("{}呼叫agv搬运异常 - 任务ID:{},请求地址:{},请求参数:{},{}", |
| | | namespace, task.getId(), url, body, errorMsg, e); |
| | | // log.error("{}呼叫agv搬运异常 - 任务ID:{},请求地址:{},请求参数:{},{}", |
| | | // namespace, task.getId(), url, body, errorMsg, e); |
| | | handleCallFailure(task, namespace, errorMsg, retryEnabled, maxRetryCount, currentRetryCount); |
| | | } finally { |
| | | try { |
| | |
| | | success |
| | | ); |
| | | } catch (Exception e) { |
| | | log.error(namespace + "呼叫agv保存接口日志异常:", e); |
| | | // log.error(namespace + "呼叫agv保存接口日志异常:", e); |
| | | } |
| | | } |
| | | } |
| | |
| | | task.setErrorTime(new Date()); |
| | | task.setErrorMemo(String.format("AGV呼叫失败(第%d次重试):%s", newRetryCount, errorMsg)); |
| | | taskService.updateById(task); |
| | | log.info("{}呼叫agv搬运失败 - 任务ID:{},已重试{}次,将在下次定时任务时继续重试(最多{}次)", |
| | | namespace, task.getId(), newRetryCount, maxRetryCount); |
| | | // log.info("{}呼叫agv搬运失败 - 任务ID:{},已重试{}次,将在下次定时任务时继续重试(最多{}次)", |
| | | // namespace, task.getId(), newRetryCount, maxRetryCount); |
| | | } else { |
| | | // 不启用重试或已达到最大重试次数,停止重试 |
| | | task.setErrorTime(new Date()); |
| | |
| | | task.setErrorMemo(String.format("AGV呼叫失败(重试未启用):%s", errorMsg)); |
| | | } |
| | | taskService.updateById(task); |
| | | log.warn("{}呼叫agv搬运失败 - 任务ID:{},停止重试。错误信息:{}", |
| | | namespace, task.getId(), errorMsg); |
| | | // log.warn("{}呼叫agv搬运失败 - 任务ID:{},停止重试。错误信息:{}", |
| | | // namespace, task.getId(), errorMsg); |
| | | } |
| | | } |
| | | |
| | |
| | | fromBin = task.getSourceStaNo(); |
| | | } |
| | | if (fromBin == null || fromBin.isEmpty() || "0".equals(fromBin)) { |
| | | log.warn("任务{}的源库位和源站点都为空,使用默认值", task.getId()); |
| | | // log.warn("任务{}的源库位和源站点都为空,使用默认值", task.getId()); |
| | | fromBin = "0"; |
| | | } |
| | | object.put("fromBin", fromBin); |
| | |
| | | // 默认使用东侧 |
| | | targetStations = agvProperties.getEastStations(); |
| | | groupKey = "east"; |
| | | log.warn("任务ID:{}的机器人组{}未识别,使用默认东侧站点", task.getId(), robotGroup); |
| | | // log.warn("任务ID:{}的机器人组{}未识别,使用默认东侧站点", task.getId(), robotGroup); |
| | | } |
| | | |
| | | if (targetStations.isEmpty()) { |
| | | String errorMsg = "没有可用的目标站点配置"; |
| | | log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | // log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | return errorMsg; |
| | | } |
| | | |
| | |
| | | |
| | | if (sites.isEmpty()) { |
| | | String errorMsg = "没有能入站点"; |
| | | log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | // log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | return errorMsg; |
| | | } |
| | | |
| | |
| | | |
| | | if (devListWithConfig.isEmpty()) { |
| | | // 站点配置不允许入库(canining != "Y"),暂不分配,等待配置开通(只在定时任务中记录日志) |
| | | log.warn("任务ID:{}没有可入站点(站点未开通可入允许:canining='Y'),暂不分配站点,等待配置开通", task.getId()); |
| | | // log.warn("任务ID:{}没有可入站点(站点未开通可入允许:canining='Y'),暂不分配站点,等待配置开通", task.getId()); |
| | | return null; // 返回null,表示暂不分配,等待配置开通 |
| | | } |
| | | |
| | |
| | | List<Integer> canInSites = basDevpMapper.getCanInSites(configuredSites); |
| | | if (canInSites.isEmpty()) { |
| | | // 所有已配置可入的站点都有出库任务,暂不分配,等待下次定时任务再尝试(只在定时任务中记录日志) |
| | | log.warn("任务ID:{}没有可入站点(请等待出库完成),暂不分配站点,等待下次定时任务再尝试", task.getId()); |
| | | // log.warn("任务ID:{}没有可入站点(请等待出库完成),暂不分配站点,等待下次定时任务再尝试", task.getId()); |
| | | return null; // 返回null,表示暂不分配,等待下次定时任务再尝试 |
| | | } |
| | | |
| | |
| | | if (devList.isEmpty()) { |
| | | // 理论上不应该到这里,因为前面已经检查过了,但为了安全起见还是保留 |
| | | String errorMsg = "没有可入站点(in_enable='Y'且canining='Y')"; |
| | | log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | // log.warn("任务ID:{}", errorMsg, task.getId()); |
| | | return errorMsg; |
| | | } |
| | | |
| | |
| | | isTransporting = !transportingTasks.isEmpty(); |
| | | |
| | | if (isTransporting) { |
| | | log.debug("站点{}有{}个正在搬运的{}AGV任务,检查下一个站点", |
| | | staNo, transportingTasks.size(), taskTypeName); |
| | | // log.debug("站点{}有{}个正在搬运的{}AGV任务,检查下一个站点", |
| | | // staNo, transportingTasks.size(), taskTypeName); |
| | | continue; // 该站点正在搬运,检查下一个站点 |
| | | } |
| | | } |
| | | |
| | | // 找到第一个空闲站点,分配 |
| | | selectedSite = dev; |
| | | log.info("任务ID:{}按规则应分配到站点{},该站点空闲,分配成功", task.getId(), staNo); |
| | | // log.info("任务ID:{}按规则应分配到站点{},该站点空闲,分配成功", task.getId(), staNo); |
| | | break; |
| | | } |
| | | |
| | |
| | | // 检查站点是否有效(不能为0或null) |
| | | if (endSite == null || endSite == 0) { |
| | | String errorMsg = String.format("分配的站点无效(dev_no=%s)", endSite); |
| | | log.error("任务ID:{},{}", task.getId(), errorMsg); |
| | | // log.error("任务ID:{},{}", task.getId(), errorMsg); |
| | | return errorMsg; |
| | | } |
| | | |
| | |
| | | task.setStaNo(String.valueOf(endSite)); |
| | | taskService.updateById(task); |
| | | |
| | | log.info("任务ID:{}已分配站点:{}", task.getId(), endSite); |
| | | // log.info("任务ID:{}已分配站点:{}", task.getId(), endSite); |
| | | return null; // 分配成功,返回null |
| | | } |
| | | |
| | |
| | | public ReturnT<String> agvDoOut(Task task) { |
| | | if (task.getIoType().equals(101)) { |
| | | Date now = new Date(); |
| | | |
| | | // 检查sourceLocNo是否为空 |
| | | if (task.getSourceLocNo() == null || task.getSourceLocNo().isEmpty()) { |
| | | // log.warn("任务ID:{}的sourceLocNo为空,跳过库位操作(可能是从站点入库的任务)", task.getId()); |
| | | task.setWrkSts(15L); |
| | | if (!taskService.updateById(task)) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | } |
| | | return SUCCESS; |
| | | } |
| | | |
| | | // 查询库位信息 |
| | | LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", task.getSourceLocNo())); |
| | | if (Objects.isNull(locMast)) { |
| | | throw new RuntimeException("数据错误:库位信息不能为空!!"); |
| | | // 如果查询不到库位,可能是sourceLocNo是站点号而不是库位号 |
| | | // 检查BasDevp表中是否存在该站点 |
| | | try { |
| | | Integer siteNo = Integer.parseInt(task.getSourceLocNo()); |
| | | List<BasDevp> basDevpList = basDevpMapper.selectList(new EntityWrapper<BasDevp>().eq("dev_no", siteNo)); |
| | | if (basDevpList != null && !basDevpList.isEmpty()) { |
| | | // sourceLocNo是站点号,这是从站点入库的任务,不需要处理库位 |
| | | // log.info("任务ID:{}的sourceLocNo是站点号:{},跳过库位操作(从站点入库任务)", task.getId(), task.getSourceLocNo()); |
| | | task.setWrkSts(15L); |
| | | if (!taskService.updateById(task)) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | } |
| | | return SUCCESS; |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | // sourceLocNo不是数字,可能是库位号格式错误 |
| | | log.warn("任务ID:{}的sourceLocNo:{}不是有效的数字格式", task.getId(), task.getSourceLocNo()); |
| | | } |
| | | // 既不是库位也不是站点,抛出异常 |
| | | throw new RuntimeException("数据错误:库位信息不能为空!!任务ID:" + task.getId() + ",sourceLocNo:" + task.getSourceLocNo()); |
| | | } |
| | | List<TaskDetl> wrkDetls101 = taskDetlService.selectList(new EntityWrapper<TaskDetl>().eq("wrk_no", task.getWrkNo())); |
| | | if (wrkDetls101.isEmpty()) { |
| | |
| | | if (ioType == 1 || ioType == 10 || ioType == 53 || ioType == 57) { |
| | | // ioType == 1 需要处理组托数据 |
| | | if (ioType == 1) { |
| | | // 检查locNo是否为空 |
| | | if (wrkMast.getLocNo() == null || wrkMast.getLocNo().isEmpty()) { |
| | | log.warn("任务ID:{}的locNo为空,跳过库位操作(可能是从站点入库的任务)", wrkMast.getId()); |
| | | // 更新任务状态为5(库存更新完成) |
| | | wrkMast.setWrkSts(5L); |
| | | wrkMast.setModiTime(new Date()); |
| | | if (!taskService.updateById(wrkMast)) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | } |
| | | return SUCCESS; |
| | | } |
| | | |
| | | LocCache locCache = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo())); |
| | | if (Objects.isNull(locCache)) { |
| | | throw new CoolException("数据错误,库位不存在!!"); |
| | | // 如果查询不到库位,可能是locNo是站点号而不是库位号 |
| | | // 检查BasDevp表中是否存在该站点 |
| | | try { |
| | | Integer siteNo = Integer.parseInt(wrkMast.getLocNo()); |
| | | List<BasDevp> basDevpList = basDevpMapper.selectList(new EntityWrapper<BasDevp>().eq("dev_no", siteNo)); |
| | | if (basDevpList != null && !basDevpList.isEmpty()) { |
| | | // locNo是站点号,这是从站点入库的任务,不需要处理库位明细 |
| | | log.info("任务ID:{}的locNo是站点号:{},跳过库位操作(从站点入库任务)", wrkMast.getId(), wrkMast.getLocNo()); |
| | | // 更新任务状态为5(库存更新完成) |
| | | wrkMast.setWrkSts(5L); |
| | | wrkMast.setModiTime(new Date()); |
| | | if (!taskService.updateById(wrkMast)) { |
| | | throw new CoolException("任务状态修改失败!!"); |
| | | } |
| | | return SUCCESS; |
| | | } |
| | | } catch (NumberFormatException e) { |
| | | // locNo不是数字,可能是库位号格式错误 |
| | | log.warn("任务ID:{}的locNo:{}不是有效的数字格式", wrkMast.getId(), wrkMast.getLocNo()); |
| | | } |
| | | // 既不是库位也不是站点,抛出异常 |
| | | throw new CoolException("数据错误,库位不存在!!任务ID:" + wrkMast.getId() + ",locNo:" + wrkMast.getLocNo()); |
| | | } |
| | | if (!locCache.getLocSts().equals(LocStsType.LOC_STS_TYPE_S.type)) { |
| | | throw new CoolException("当前库位状态为:" + LocStsType.LOC_STS_TYPE_S.type + "." + LocStsType.LOC_STS_TYPE_S.desc + ",不是出库预约状态"); |
| | |
| | | if (user.getDeptId() != null) { |
| | | entity.setDeptId(user.getDeptId()); |
| | | } |
| | | if (user.getAdLogin() != null) { |
| | | entity.setAdLogin(user.getAdLogin()); |
| | | } |
| | | if (user.getEmail() != null) { |
| | | entity.setEmail(user.getEmail()); |
| | | } |
| | | userService.updateById(entity); |
| | | return R.ok(); |
| | | } |
| | |
| | | */ |
| | | private Integer status; |
| | | |
| | | /** |
| | | * AD登录 1: 启用 0: 禁用 |
| | | */ |
| | | @TableField("ad_login") |
| | | private Integer adLogin; |
| | | |
| | | public Long getId() { |
| | | return id; |
| | | } |
| | |
| | | this.status = status; |
| | | } |
| | | |
| | | public Integer getAdLogin() { |
| | | return adLogin; |
| | | } |
| | | |
| | | public void setAdLogin(Integer adLogin) { |
| | | this.adLogin = adLogin; |
| | | } |
| | | |
| | | public String getAdLogin$() { |
| | | if (null == this.adLogin) { |
| | | return "禁用"; |
| | | } |
| | | switch (this.adLogin) { |
| | | case 1: |
| | | return "启用"; |
| | | case 0: |
| | | return "禁用"; |
| | | default: |
| | | return String.valueOf(this.adLogin); |
| | | } |
| | | } |
| | | |
| | | } |
| | |
| | | <property name="CONSOLE_LOG_PATTERN" |
| | | value="%d{yyyy-MM-dd HH:mm:ss.SSS} %highlight(-%5p) ${PID:-} [%15.15t] %-40.40logger{39} : %m%n"> |
| | | </property> |
| | | <property name="LOG_PATH" value="/stock/out/wms/logs"/> |
| | | <!-- 日志路径:D盘(Windows环境),Linux环境使用/stock/out/wms/logs --> |
| | | <property name="LOG_PATH" value="D:/stock/out/wms/logs"/> |
| | | |
| | | <!--控制台--> |
| | | <!--控制台输出--> |
| | | <appender name="CONSOLE" class="ch.qos.logback.core.ConsoleAppender"> |
| | | <encoder> |
| | | <pattern>${CONSOLE_LOG_PATTERN}</pattern> |
| | |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!--info级别--> |
| | | <!--INFO级别日志--> |
| | | <appender name="INFO_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <file>${LOG_PATH}/info.log</file> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <FileNamePattern>${LOG_PATH}/info_%d{yyyy-MM-dd}.%i.log</FileNamePattern> |
| | | <maxHistory>10</maxHistory> |
| | | <!-- 保留15天 --> |
| | | <maxHistory>15</maxHistory> |
| | | <!-- 总大小限制15GB(防止日志占用过多空间) --> |
| | | <totalSizeCap>15GB</totalSizeCap> |
| | | <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
| | | <maxFileSize>10MB</maxFileSize> |
| | | <!-- 单个文件100MB(减少文件数量) --> |
| | | <maxFileSize>100MB</maxFileSize> |
| | | </timeBasedFileNamingAndTriggeringPolicy> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg %n</pattern> |
| | | <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
| | | <charset>UTF-8</charset> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!--error级别--> |
| | | <!--ERROR级别日志--> |
| | | <appender name="ERROR_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <filter class="ch.qos.logback.classic.filter.ThresholdFilter"> |
| | | <level>ERROR</level> |
| | |
| | | <file>${LOG_PATH}/error.log</file> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <FileNamePattern>${LOG_PATH}/error_%d{yyyy-MM-dd}.%i.log</FileNamePattern> |
| | | <maxHistory>10</maxHistory> |
| | | <!-- 错误日志保留30天 --> |
| | | <maxHistory>30</maxHistory> |
| | | <!-- 错误日志总大小限制5GB --> |
| | | <totalSizeCap>5GB</totalSizeCap> |
| | | <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
| | | <maxFileSize>10MB</maxFileSize> |
| | | <maxFileSize>100MB</maxFileSize> |
| | | </timeBasedFileNamingAndTriggeringPolicy> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>%d{HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg %n</pattern> |
| | | <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
| | | <charset>UTF-8</charset> |
| | | </encoder> |
| | | </appender> |
| | | |
| | | <!--WARN级别日志(可选)--> |
| | | <appender name="WARN_FILE" class="ch.qos.logback.core.rolling.RollingFileAppender"> |
| | | <filter class="ch.qos.logback.classic.filter.LevelFilter"> |
| | | <level>WARN</level> |
| | | <onMatch>ACCEPT</onMatch> |
| | | <onMismatch>DENY</onMismatch> |
| | | </filter> |
| | | <file>${LOG_PATH}/warn.log</file> |
| | | <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy"> |
| | | <FileNamePattern>${LOG_PATH}/warn_%d{yyyy-MM-dd}.%i.log</FileNamePattern> |
| | | <!-- 警告日志保留15天 --> |
| | | <maxHistory>15</maxHistory> |
| | | <totalSizeCap>2GB</totalSizeCap> |
| | | <timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP"> |
| | | <maxFileSize>50MB</maxFileSize> |
| | | </timeBasedFileNamingAndTriggeringPolicy> |
| | | </rollingPolicy> |
| | | <encoder> |
| | | <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern> |
| | | <charset>UTF-8</charset> |
| | | </encoder> |
| | | </appender> |
| | |
| | | <appender-ref ref="CONSOLE"/> |
| | | <appender-ref ref="INFO_FILE"/> |
| | | <appender-ref ref="ERROR_FILE"/> |
| | | <appender-ref ref="WARN_FILE"/> |
| | | </root> |
| | | </configuration> |
| | |
| | | <result column="sex" property="sex" /> |
| | | <result column="create_time" property="createTime" /> |
| | | <result column="status" property="status" /> |
| | | <result column="ad_login" property="adLogin" /> |
| | | |
| | | </resultMap> |
| | | |
| | |
| | | ,{field: 'roleName', align: 'center',title: '角色'} |
| | | ,{field: 'email', align: 'center',title: '邮箱'} |
| | | // ,{field: 'sex$', align: 'center',title: '性别'} |
| | | ,{field: 'adLogin$', align: 'center',title: 'AD登录', templet: '#adLoginTpl', width: 100, unresize: true} |
| | | ,{field: 'createTime$', align: 'center',title: '注册时间', hide: true} |
| | | ,{field: 'status$', align: 'center',title: '状态', templet: '#statusTpl', width: 120, unresize: true} |
| | | |
| | |
| | | }) |
| | | }) |
| | | |
| | | // 修改AD登录状态 |
| | | form.on('switch(adLoginSwitch)', function (obj) { |
| | | var index = obj.othis.parents('tr').attr("data-index"); |
| | | var data = tableData[index]; |
| | | data[this.name] = obj.elem.checked?1:0; |
| | | http.post(baseUrl+"/user/edit/auth", {id: data.id, adLogin: data[this.name]}, function (res) { |
| | | layer.msg(res.msg, {icon: 1}); |
| | | }) |
| | | }) |
| | | |
| | | /* 表格2工具条点击事件 */ |
| | | table.on('tool(userTable)', function (obj) { |
| | | var data = obj.data; |
| | |
| | | content: $('#editDialog').html(), |
| | | success: function (layero, dIndex) { |
| | | // 回显表单数据 |
| | | if (mData) { |
| | | form.val('detail', mData); |
| | | // 处理AD登录复选框的回显(编辑用户时) |
| | | if (mData.adLogin === 1 || mData.adLogin === '1') { |
| | | $('input[name="adLogin"]').prop('checked', true); |
| | | } else { |
| | | $('input[name="adLogin"]').prop('checked', false); |
| | | } |
| | | } else { |
| | | // 新增用户时,确保AD登录默认为未选中 |
| | | $('input[name="adLogin"]').prop('checked', false); |
| | | // 清空表单 |
| | | form.val('detail', { |
| | | username: '', |
| | | mobile: '', |
| | | email: '', |
| | | roleId: '', |
| | | roleName: '', |
| | | deptId: '', |
| | | deptName: '', |
| | | adLogin: 0 |
| | | }); |
| | | } |
| | | // 重新渲染表单,确保开关控件正确显示 |
| | | form.render('checkbox'); |
| | | // 表单提交事件 |
| | | form.on('submit(editSubmit)', function (data) { |
| | | if (isEmpty(data.field.roleId)) { |
| | |
| | | layer.msg('请选择部门', {icon: 2}); |
| | | return false; |
| | | } |
| | | // 处理AD登录复选框的值 |
| | | if (data.field.adLogin === '1' || data.field.adLogin === true) { |
| | | data.field.adLogin = 1; |
| | | } else { |
| | | data.field.adLogin = 0; |
| | | } |
| | | var loadIndex = layer.load(2); |
| | | $.ajax({ |
| | | url: baseUrl+"/user/"+(mData?'update':'add')+"/auth", |
| | |
| | | <input type="checkbox" name="status" value="{{d.status}}" lay-skin="switch" lay-text="正常|禁用" lay-filter="statusSwitch" {{ d.status === 1 ? 'checked' : '' }}> |
| | | </script> |
| | | |
| | | <script type="text/html" id="adLoginTpl"> |
| | | <input type="checkbox" name="adLogin" value="{{d.adLogin}}" lay-skin="switch" lay-text="启用|禁用" lay-filter="adLoginSwitch" {{ d.adLogin === 1 ? 'checked' : '' }}> |
| | | </script> |
| | | |
| | | <script type="text/html" id="operate"> |
| | | <a class="layui-btn layui-btn-xs btn-edit" lay-event="edit">编辑</a> |
| | | <a class="layui-btn layui-btn-xs btn-edit layui-btn-warm" lay-event="resetPwd">重置密码</a> |
| | |
| | | </div> |
| | | </div> |
| | | </div> |
| | | |
| | | </div> |
| | | </div> |
| | | <hr class="layui-bg-gray"> |
| | | <div class="layui-row"> |
| | | <div class="layui-col-md12"> |
| | | <div class="layui-form-item"> |
| | | <label class="layui-form-label">AD登录</label> |
| | | <div class="layui-input-block"> |
| | | <input type="checkbox" name="adLogin" value="1" title="启用AD登录" lay-skin="switch" lay-text="启用|禁用" lay-filter="adLoginFormSwitch"> |
| | | <div class="layui-form-mid layui-word-aux" style="margin-left: 10px;">开启后,用户可以使用AD域账号登录系统</div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="layui-form-item text-right"> |
| | | <button class="layui-btn" lay-filter="editSubmit" lay-submit="">保存</button> |
| | | <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> |