| | |
| | | return R.ok(result); |
| | | } |
| | | |
| | | /** AGV任务管理用:仅返回AGV相关工作状态 7、8、9、10 */ |
| | | @RequestMapping(value = "/basWrkStatusQueryAgv/auth") |
| | | @ManagerAuth |
| | | public R queryAgv(String condition) { |
| | | EntityWrapper<BasWrkStatus> wrapper = new EntityWrapper<>(); |
| | | wrapper.in("wrk_sts", 7L, 8L, 9L, 10L); |
| | | if (!Cools.isEmpty(condition)) { |
| | | wrapper.like("wrk_desc", condition); |
| | | } |
| | | Page<BasWrkStatus> page = basWrkStatusService.selectPage(new Page<>(0, 100), wrapper); |
| | | List<Map<String, Object>> result = new ArrayList<>(); |
| | | for (BasWrkStatus basWrkStatus : page.getRecords()) { |
| | | Map<String, Object> map = new HashMap<>(); |
| | | map.put("id", basWrkStatus.getWrkSts()); |
| | | map.put("value", basWrkStatus.getWrkDesc()); |
| | | result.add(map); |
| | | } |
| | | return R.ok(result); |
| | | } |
| | | |
| | | @RequestMapping(value = "/basWrkStatus/check/column/auth") |
| | | @ManagerAuth |
| | | public R query(@RequestBody JSONObject param) { |
| | |
| | | @RequestParam Map<String, Object> param) { |
| | | EntityWrapper<Task> wrapper = new EntityWrapper<>(); |
| | | excludeTrash(param); |
| | | // 移除非表字段参数,避免 SQL 报错「列名 wrk_sts_cb 无效」(agv_task 无此列,多为前端下拉描述字段) |
| | | param.remove("wrk_sts_cb"); |
| | | param.remove("wrkStsCb"); |
| | | convert(param, wrapper); |
| | | wrapper.eq("is_deleted", 0); |
| | | allLike(Task.class, param.keySet(), wrapper, condition); |
| | |
| | | String[] dates = val.split(RANGE_TIME_LINK); |
| | | wrapper.ge(entry.getKey(), DateUtils.convert(dates[0])); |
| | | wrapper.le(entry.getKey(), DateUtils.convert(dates[1])); |
| | | } else if (val.contains(",") && !Cools.isEmpty(val) && !val.equals("null")) { |
| | | // 多值查询:使用 IN 查询(适用于工作状态等多选场景) |
| | | String[] values = val.split(","); |
| | | List<Object> valueList = new ArrayList<>(); |
| | | for (String v : values) { |
| | | v = v.trim(); |
| | | if (!Cools.isEmpty(v) && !v.equals("null")) { |
| | | // 尝试转换为数字类型(工作状态是Long类型) |
| | | try { |
| | | valueList.add(Long.parseLong(v)); |
| | | } catch (NumberFormatException e) { |
| | | // 如果不是数字,保持字符串类型 |
| | | valueList.add(v); |
| | | } |
| | | } |
| | | } |
| | | if (!valueList.isEmpty()) { |
| | | wrapper.in(entry.getKey(), valueList); |
| | | } |
| | | } else { |
| | | wrapper.like(entry.getKey(), val); |
| | | } |
| | |
| | | } else if (type == 3) { |
| | | taskService.pickWrkMast(workNo, getUserId()); |
| | | return R.ok("工作档已拣料"); |
| | | } else if (type == 4) { |
| | | taskService.deleteWrkMast(workNo, getUserId()); |
| | | return R.ok("工作档已删除"); |
| | | } |
| | | return R.ok(); |
| | | } |
| | |
| | | private <T> void convert(Map<String, Object> map, EntityWrapper<T> wrapper) { |
| | | for (Map.Entry<String, Object> entry : map.entrySet()) { |
| | | String val = String.valueOf(entry.getValue()); |
| | | // 跳过空值和 "null" 字符串 |
| | | if (Cools.isEmpty(val) || "null".equals(val)) { |
| | | continue; |
| | | } |
| | |
| | | String[] dates = val.split(RANGE_TIME_LINK); |
| | | wrapper.ge(entry.getKey(), DateUtils.convert(dates[0])); |
| | | wrapper.le(entry.getKey(), DateUtils.convert(dates[1])); |
| | | } else if (val.contains(",") && !val.equals("null")) { |
| | | // 多值查询:工作状态等多选用 IN(与 AGV 任务管理一致) |
| | | String[] values = val.split(","); |
| | | List<Object> valueList = new ArrayList<>(); |
| | | for (String v : values) { |
| | | v = v.trim(); |
| | | if (!Cools.isEmpty(v) && !v.equals("null")) { |
| | | try { |
| | | valueList.add(Long.parseLong(v)); |
| | | } catch (NumberFormatException e) { |
| | | valueList.add(v); |
| | | } |
| | | } |
| | | } |
| | | if (!valueList.isEmpty()) { |
| | | wrapper.in(entry.getKey(), valueList); |
| | | } |
| | | } else { |
| | | wrapper.like(entry.getKey(), val); |
| | | } |
| | |
| | | package com.zy.asrs.controller; |
| | | |
| | | import com.alibaba.fastjson.JSONArray; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.baomidou.mybatisplus.mapper.Wrapper; |
| | |
| | | wrkMast.setModiUser(getUserId()); |
| | | wrkMast.setModiTime(new Date()); |
| | | wrkMastService.updateById(wrkMast); |
| | | return R.ok(); |
| | | } |
| | | |
| | | @RequestMapping(value = "/wrkMast/delete/auth") |
| | | @ManagerAuth(memo = "工作档删除") |
| | | public R delete(@RequestParam String param) { |
| | | List<WrkMast> list = JSONArray.parseArray(param, WrkMast.class); |
| | | if (Cools.isEmpty(list)) { |
| | | return R.error(); |
| | | } |
| | | for (WrkMast entity : list) { |
| | | wrkMastService.delete(new EntityWrapper<>(entity)); |
| | | } |
| | | return R.ok(); |
| | | } |
| | | |
| | |
| | | |
| | | void pickWrkMast(String workNo, Long userId); |
| | | |
| | | /** |
| | | * 删除AGV任务(尝试取消AGV任务,但不会因为AGV取消失败而阻止删除) |
| | | * @param workNo 工作号 |
| | | * @param userId 用户ID |
| | | */ |
| | | void deleteWrkMast(String workNo, Long userId); |
| | | |
| | | List<Task> selectToBeCompleteData(); |
| | | |
| | | List<Task> selectToBeHistoryData(); |
| | |
| | | throw new CoolException("条码组托档已存在:" + barcode); |
| | | } |
| | | |
| | | // 检查是否有任何工作档(空托盘不应该有任何工作档,包括已完成的工作档) |
| | | int wrkMastCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", barcode)); |
| | | if (wrkMastCount != 0) { |
| | | log.warn("条码任务档已存在,不是空托盘:{}", barcode); |
| | | throw new CoolException("条码任务档已存在:" + barcode); |
| | | } |
| | | |
| | | // 检查库位上是否有该条码 |
| | | if (locCache != null && !Cools.isEmpty(locCache.getBarcode()) && locCache.getBarcode().equals(barcode)) { |
| | | log.warn("空托盘入库时,库位上已有该条码,不允许呼叫AGV:库位={},条码={}", sourceSite, barcode); |
| | | throw new CoolException("条码在库,请更换条码" + barcode); |
| | | } |
| | | |
| | | |
| | | // 通过所有检查,确认为空托盘,设置为空托入库 |
| | | ioType = 10; |
| | | log.info("确认为空托盘,设置为空托入库,条码:{},ioType:{}", barcode, ioType); |
| | |
| | | default: |
| | | throw new CoolException("入库类型错误,type:" + type); |
| | | } |
| | | |
| | | // 统一校验:在所有AGV呼叫场景中都需要检查以下条件,有任何一个满足则不允许呼叫AGV |
| | | |
| | | // 1. 校验库位上的条码是否在库:检查LocCache表上是否有该条码,且该条码在LocDetl库存中 |
| | | // 注意:空托盘入库(type=3)不校验库存明细,只在校验库位上是否有条码(已在case 3中处理) |
| | |
| | | throw new CoolException("条码在库,请更换条码" + barcode); |
| | | } |
| | | } |
| | | }else { |
| | | // 检查库位上是否有该条码 |
| | | if (locCache != null && !Cools.isEmpty(locCache.getBarcode()) && locCache.getBarcode().equals(barcode)) { |
| | | log.warn("空托盘入库时,库位上已有该条码,不允许呼叫AGV:库位={},条码={}", sourceSite, barcode); |
| | | throw new CoolException("条码在库,请更换条码" + barcode); |
| | | } |
| | | } |
| | | |
| | | // 2. 校验工作档中运行中的托盘码:检查是否有未完成的工作档(wrk_sts不等于4、14和15) |
| | | // 4=入库完成,14=已出库未确认,15=出库更新完成 |
| | | int runningWrkMastCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>() |
| | | .eq("barcode", barcode) |
| | | .notIn("wrk_sts", Arrays.asList(4L, 14L, 15L))); // 不等于入库完成(4)和出库完成(14,15) |
| | | if (runningWrkMastCount > 0) { |
| | | log.warn("AGV呼叫时,托盘码在工作档中运行中,不允许呼叫AGV:{}", barcode); |
| | | // 2. 校验工作档中运行中的托盘码 |
| | | int wrkMastCount = wrkMastService.selectCount(new EntityWrapper<WrkMast>().eq("barcode", barcode)); |
| | | if (wrkMastCount != 0) { |
| | | log.warn("条码在工作档已存在:{}", barcode); |
| | | throw new CoolException("条码在工作档,请更换条码:" + barcode); |
| | | } |
| | | |
| | | // 3. 校验AGV任务列表中未完成的托盘码:检查是否有未完成的AGV任务(is_deleted=0且wrk_sts不等于4、14和15) |
| | | // 4=入库完成,14=已出库未确认,15=出库更新完成 |
| | | |
| | | // 3. 校验AGV任务列表中未完成的托盘码:检查是否有未完成的AGV任务(is_deleted=0) |
| | | int unfinishedTaskCount = taskService.selectCount(new EntityWrapper<Task>() |
| | | .eq("barcode", barcode) |
| | | .eq("is_deleted", 0) |
| | | .notIn("wrk_sts", Arrays.asList(4L, 14L, 15L))); // 不等于入库完成(4)和出库完成(14,15) |
| | | .eq("is_deleted", 0)); |
| | | if (unfinishedTaskCount > 0) { |
| | | log.warn("AGV呼叫时,托盘码在AGV任务列表中未完成,不允许呼叫AGV:{}", barcode); |
| | | log.warn("AGV呼叫时,条码在AGV任务档,不允许呼叫AGV:{}", barcode); |
| | | throw new CoolException("条码在AGV任务档,请更换条码:" + barcode); |
| | | } |
| | | |
| | |
| | | import com.zy.asrs.entity.*; |
| | | import com.zy.asrs.mapper.TaskMapper; |
| | | import com.zy.asrs.service.*; |
| | | import com.zy.asrs.task.handler.AgvHandler; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | |
| | | import java.util.Objects; |
| | | import java.util.concurrent.TimeUnit; |
| | | |
| | | @Slf4j |
| | | @Service("taskService") |
| | | public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService { |
| | | |
| | |
| | | private OrderPakoutService orderPakoutService; |
| | | @Autowired |
| | | private OrderDetlPakoutService orderDetlPakoutService; |
| | | @Autowired |
| | | private AgvHandler agvHandler; |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | |
| | | if (Cools.isEmpty(wrkMast)) { |
| | | throw new CoolException(workNo + "工作档不存在"); |
| | | } |
| | | |
| | | // 如果是AGV任务,根据任务状态决定是否需要调用AGV接口取消任务 |
| | | // 仅状态7(新建AGV任务)不访问AGV直接取消;其他状态必须先调用AGV取消接口,AGV返回成功才能取消 |
| | | if ("agv".equals(wrkMast.getTaskType())) { |
| | | Long wrkSts = wrkMast.getWrkSts(); |
| | | if (wrkSts != null && wrkSts == 7L) { |
| | | // 状态7:新建AGV任务,未发送给AGV,无需调用AGV接口,直接取消 |
| | | String displayTaskId = (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId()); |
| | | log.info("取消AGV任务:任务ID:{},状态:7(新建AGV任务),无需调用AGV接口,直接取消", displayTaskId); |
| | | } else { |
| | | // 非状态7(含8、9、10等):必须先调用AGV取消接口,AGV返回成功才能取消 |
| | | if (wrkMast.getId() == null) { |
| | | throw new CoolException("取消AGV任务失败:任务ID为空"); |
| | | } |
| | | String agvWrkNo = wrkMast.getAgvWrkNo(); |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Long taskId = wrkMast.getId(); |
| | | if ((agvWrkNo == null || agvWrkNo.isEmpty()) && wrkNo == null && taskId == null) { |
| | | throw new CoolException("取消AGV任务失败:无法获取有效的任务标识(agvWrkNo、wrkNo和id都为空)"); |
| | | } |
| | | String errorMsg = agvHandler.cancelAgvTask(wrkMast); |
| | | if (errorMsg != null) { |
| | | log.warn("取消AGV任务失败,AGV未返回成功 - 任务ID:{},错误:{}", |
| | | (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId()), errorMsg); |
| | | throw new CoolException("取消AGV任务失败:" + errorMsg); |
| | | } |
| | | } |
| | | } |
| | | |
| | | String locNo = ""; // 待修改目标库位 |
| | | String locSts = ""; // 待修改目标库位状态 |
| | | // 入库取消(修改目标库位) |
| | |
| | | } |
| | | |
| | | @Override |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public void deleteWrkMast(String workNo, Long userId) { |
| | | Date now = new Date(); |
| | | Task wrkMast = this.selectOne(new EntityWrapper<Task>() |
| | | .eq("wrk_no", workNo) |
| | | .andNew("(is_deleted = 0)")); |
| | | if (Cools.isEmpty(wrkMast)) { |
| | | throw new CoolException(workNo + "工作档不存在"); |
| | | } |
| | | |
| | | String displayTaskId = (wrkMast.getWrkNo() != null) ? String.valueOf(wrkMast.getWrkNo()) : String.valueOf(wrkMast.getId()); |
| | | |
| | | // 如果是AGV任务,尝试同步申请AGV取消(但不会被AGV返回的错误校验拦截,会继续删除) |
| | | if ("agv".equals(wrkMast.getTaskType())) { |
| | | Long wrkSts = wrkMast.getWrkSts(); |
| | | // 状态8和9:已发送给AGV任务,尝试调用AGV接口取消任务 |
| | | // 状态10:AGV呼叫异常,可以取消,但不会请求AGV取消接口 |
| | | // 状态7或更早:还未发送给AGV,无需调用AGV接口 |
| | | if (wrkSts != null && wrkSts >= 8L && wrkSts != 10L) { |
| | | try { |
| | | // 验证任务信息是否完整 |
| | | if (wrkMast.getId() != null) { |
| | | // 验证taskId是否可用(agvWrkNo、wrkNo或id至少有一个) |
| | | String agvWrkNo = wrkMast.getAgvWrkNo(); |
| | | Integer wrkNo = wrkMast.getWrkNo(); |
| | | Long taskId = wrkMast.getId(); |
| | | if ((agvWrkNo != null && !agvWrkNo.isEmpty()) || wrkNo != null || taskId != null) { |
| | | // 同步申请AGV取消,但不抛出异常(不会被错误校验拦截) |
| | | String errorMsg = agvHandler.cancelAgvTask(wrkMast); |
| | | if (errorMsg != null) { |
| | | log.warn("删除AGV任务:尝试取消AGV任务失败,但继续执行删除操作,任务ID:{},错误:{}", displayTaskId, errorMsg); |
| | | } else { |
| | | log.info("删除AGV任务:成功取消AGV任务,任务ID:{}", displayTaskId); |
| | | } |
| | | } else { |
| | | log.warn("删除AGV任务:无法获取有效的任务标识(agvWrkNo、wrkNo和id都为空),跳过AGV取消,继续执行删除操作,任务ID:{}", displayTaskId); |
| | | } |
| | | } else { |
| | | log.warn("删除AGV任务:任务ID为空,跳过AGV取消,继续执行删除操作,任务ID:{}", displayTaskId); |
| | | } |
| | | } catch (Exception e) { |
| | | // 捕获所有异常,记录日志但不阻止删除操作(不会被AGV返回的错误校验拦截) |
| | | log.error("删除AGV任务:尝试取消AGV任务时发生异常,但继续执行删除操作,任务ID:{}", displayTaskId, e); |
| | | } |
| | | } else { |
| | | // 状态10(AGV呼叫异常)或状态7或更早,无需调用AGV接口 |
| | | if (wrkSts != null && wrkSts == 10L) { |
| | | log.info("删除AGV任务:任务ID:{},状态:{}(AGV呼叫异常),无需调用AGV接口,直接删除", displayTaskId, wrkSts); |
| | | } else { |
| | | log.info("删除AGV任务:任务ID:{},状态:{}(待呼叫AGV或更早),无需调用AGV接口,直接删除", displayTaskId, wrkSts); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 释放库位等资源(类似cancelWrkMast的逻辑) |
| | | String locNo = ""; // 待修改目标库位 |
| | | String locSts = ""; // 待修改目标库位状态 |
| | | // 入库取消(修改目标库位) |
| | | if (wrkMast.getIoType() < 100) { |
| | | locNo = wrkMast.getLocNo(); |
| | | locSts = "O"; |
| | | |
| | | // 库位转移 |
| | | if (wrkMast.getIoType() == 11) { |
| | | // 库位转移:源库位 |
| | | LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getSourceLocNo())); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | locMast.setLocSts(wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F"); |
| | | locMast.setModiTime(now); |
| | | locMast.setModiUser(userId); |
| | | locCacheService.updateById(locMast); |
| | | } |
| | | } |
| | | // 出库取消(修改源库位) |
| | | } else { |
| | | locNo = wrkMast.getSourceLocNo(); |
| | | // 出库 ===>> F.在库 |
| | | if (wrkMast.getIoType() > 100 && wrkMast.getIoType() != 110) { |
| | | locSts = "F"; |
| | | // 空板出库 ===>> D.空桶/空栈板 |
| | | } else if (wrkMast.getIoType() == 110) { |
| | | locSts = "D"; |
| | | // 库位转移 ===>> D.空桶/空栈板 |
| | | } else if (wrkMast.getIoType() == 11) { |
| | | locSts = wrkMast.getFullPlt().equalsIgnoreCase("N") ? "D" : "F"; |
| | | // 库位转移:目标库位 |
| | | LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo())); |
| | | if (!Cools.isEmpty(locMast)) { |
| | | locMast.setLocSts("O"); |
| | | locMast.setModiTime(now); |
| | | locMast.setModiUser(userId); |
| | | locCacheService.updateById(locMast); |
| | | } |
| | | } |
| | | } |
| | | |
| | | //取消入库工作档时,查询组托表,如果有将状态改为待处理 |
| | | if (wrkMast.getIoType() == 1) { |
| | | List<WaitPakin> waitPakins = waitPakinService.selectList(new EntityWrapper<WaitPakin>().eq("zpallet", wrkMast.getBarcode())); |
| | | for (WaitPakin waitPakin : waitPakins) { |
| | | if (!Cools.isEmpty(waitPakin)) { |
| | | waitPakin.setIoStatus("N"); |
| | | waitPakin.setLocNo(""); |
| | | waitPakinService.update(waitPakin, new EntityWrapper<WaitPakin>() |
| | | .eq("zpallet", waitPakin.getZpallet()) |
| | | .eq("matnr", waitPakin.getMatnr()) |
| | | .eq("batch", waitPakin.getBatch())); |
| | | } |
| | | } |
| | | } |
| | | |
| | | // 删除操作人员记录 |
| | | wrkMast.setManuType("手动删除"); |
| | | wrkMast.setModiUser(userId); |
| | | wrkMast.setModiTime(now); |
| | | // 逻辑删除工作主档 |
| | | wrkMast.setIsDeleted(1); |
| | | if (!taskService.updateById(wrkMast)) { |
| | | throw new CoolException("删除工作档失败"); |
| | | } |
| | | |
| | | if (wrkMast.getIoType() != 10 && wrkMast.getIoType() != 110) { |
| | | // 删除工作档明细 |
| | | taskDetlService.delete(new EntityWrapper<TaskDetl>().eq("wrk_no", workNo)); |
| | | } |
| | | |
| | | // 修改库位状态(如果库位不为空) |
| | | if (!Cools.isEmpty(locNo) && wrkMast.getIoType() > 100) { |
| | | LocCache locMast = locCacheService.selectOne(new EntityWrapper<LocCache>().eq("loc_no", locNo)); |
| | | if (!Cools.isEmpty(locMast) && !Cools.isEmpty(locSts)) { |
| | | locMast.setLocSts(locSts); |
| | | locMast.setModiTime(now); |
| | | locMast.setModiUser(userId); |
| | | locCacheService.updateById(locMast); |
| | | } |
| | | } |
| | | |
| | | // 如果是入库任务,释放预约库位 |
| | | if (wrkMast.getIoType() != null && wrkMast.getIoType() < 100 && !Cools.isEmpty(wrkMast.getLocNo())) { |
| | | try { |
| | | LocCache locCache = locCacheService.selectOne( |
| | | new EntityWrapper<LocCache>().eq("loc_no", wrkMast.getLocNo()) |
| | | ); |
| | | if (locCache != null && "S".equals(locCache.getLocSts())) { |
| | | // 库位状态为S(入库预约),释放为O(闲置) |
| | | locCache.setLocSts("O"); |
| | | locCache.setModiTime(now); |
| | | locCache.setModiUser(userId); |
| | | locCacheService.updateById(locCache); |
| | | log.info("删除AGV任务:已释放预约库位:{}(S→O),任务ID:{}", wrkMast.getLocNo(), displayTaskId); |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("删除AGV任务:释放预约库位失败,库位:{},任务ID:{}", wrkMast.getLocNo(), displayTaskId, e); |
| | | } |
| | | } |
| | | |
| | | log.info("删除AGV任务成功:任务ID:{},工作号:{}", displayTaskId, workNo); |
| | | } |
| | | |
| | | @Override |
| | | public List<Task> selectToBeHistoryData() { |
| | | return this.baseMapper.selectToBeHistoryData(); |
| | | } |
| | |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.Collections; |
| | | import java.util.Calendar; |
| | | import java.util.Date; |
| | | import java.util.HashMap; |
| | | import java.util.List; |
| | |
| | | * 每次只处理一个任务,避免高并发执行 |
| | | * 使用AtomicBoolean确保单线程执行循环 |
| | | */ |
| | | @Scheduled(cron = "0/5 * * * * ? ") |
| | | @Scheduled(cron = "0/15 * * * * ? ") |
| | | private void allocateSite() { |
| | | if (!schedulerProperties.isEnabled()) { |
| | | log.debug("定时任务allocateSite:调度器未启用,跳过执行"); |
| | |
| | | if (!schedulerProperties.isEnabled()) { |
| | | return; |
| | | } |
| | | List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().eq("wrk_sts", 9).eq("is_deleted", 0)); |
| | | List<Task> taskList = taskService.selectList(new EntityWrapper<Task>().in("wrk_sts", 9L,10L).eq("is_deleted", 0)); |
| | | if (taskList.isEmpty()) { |
| | | return; |
| | | } |
| | |
| | | ); |
| | | } |
| | | // 如果通过wrk_no没找到,且有条码,则通过条码查询 |
| | | // 注意:通过条码查询时,需要验证工作档是否真的已完成(通过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订单创建时间之后,且不超过AGV创建时间之后6小时 |
| | | Wrapper<WrkMastLog> logWrapper = new EntityWrapper<WrkMastLog>() |
| | | |
| | | .eq("barcode", agvTask.getBarcode()); |
| | | // 如果AGV订单有创建时间,添加时间过滤条件 |
| | | if (agvTask.getAppeTime() != null) { |
| | | // 计算AGV创建时间之后6小时的时间 |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(agvTask.getAppeTime()); |
| | | calendar.add(Calendar.HOUR_OF_DAY, 6); // 加6小时 |
| | | Date endTime = calendar.getTime(); |
| | | // 查询条件:历史档创建时间 >= AGV订单创建时间 且 <= AGV创建时间之后6小时 |
| | | logWrapper = logWrapper.ge("appe_time", agvTask.getAppeTime()) |
| | | .le("appe_time", endTime) |
| | | .eq("barcode", agvTask.getBarcode()) |
| | | ; |
| | | } |
| | | List<WrkMastLog> logList = wrkMastLogService.selectList(logWrapper); |
| | | // 过滤:只保留工作号匹配的历史档,避免重复条码导致误判 |
| | | for (WrkMastLog log : logList) { |
| | | if (agvTask.getWrkNo() != null && log.getWrkNo() != null && |
| | | log.getWrkNo().equals(agvTask.getWrkNo())) { |
| | | wrkMastLog = log; |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | String displayTaskId = (agvTask.getWrkNo() != null) ? String.valueOf(agvTask.getWrkNo()) : String.valueOf(agvTask.getId()); |
| | | // 如果订单创建超过五分钟,查询AGV订单状态 |
| | | if (shouldCheckAgvStatus) { |
| | | String agvOrderStatus = queryAgvOrderStatus(agvTask, displayTaskId); |
| | | if (agvOrderStatus != null) { |
| | | // 根据订单状态处理 |
| | | boolean shouldComplete = processAgvOrderStatus(agvTask, agvOrderStatus, displayTaskId, now); |
| | | if (shouldComplete) { |
| | | completedTasks.add(agvTask); |
| | | } |
| | | // queryAgvOrderStatus内部已经调用processAgvOrderStatus进行归类处理 |
| | | // 返回true表示应该完结订单,添加到完成列表 |
| | | boolean shouldComplete = queryAgvOrderStatus(agvTask, displayTaskId); |
| | | if (shouldComplete) { |
| | | completedTasks.add(agvTask); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * 查询AGV订单状态 |
| | | * 查询AGV订单状态并归类处理 |
| | | * @param agvTask AGV任务 |
| | | * @param displayTaskId 显示的任务ID |
| | | * @return 订单状态(Building/Created/Assigned/Failed/Done/Cancelled),如果查询失败返回null |
| | | * @return true表示应该完结订单,false表示不应该完结(跳过),如果查询失败返回false |
| | | */ |
| | | private String queryAgvOrderStatus(Task agvTask, String displayTaskId) { |
| | | private boolean queryAgvOrderStatus(Task agvTask, String displayTaskId) { |
| | | try { |
| | | // 构建订单ID,优先使用agvWrkNo,如果为空则使用T+wrkNo(向后兼容) |
| | | String orderId = agvTask.getAgvWrkNo(); |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | |
| | | // 解析响应 |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | |
| | | try { |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | |
| | | // 获取订单信息 |
| | |
| | | String status = entityValue.getString("status"); |
| | | if (status != null) { |
| | | log.info("查询AGV订单状态成功 - 任务ID:{},订单ID:{},状态:{}", displayTaskId, orderId, status); |
| | | return status; |
| | | // 查询后使用processAgvOrderStatus方法归类 |
| | | Date now = new Date(); |
| | | boolean shouldComplete = processAgvOrderStatus(agvTask, status, displayTaskId, now); |
| | | return shouldComplete; |
| | | } else { |
| | | String errorMsg = String.format("查询AGV订单状态响应中缺少status字段,请求:%s,响应:%s", requestBody, response); |
| | | log.warn("查询AGV订单状态失败 - 任务ID:{},订单ID:{},{}", displayTaskId, orderId, errorMsg); |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | } else { |
| | | String errorMsg = String.format("查询AGV订单状态响应中缺少entityValue字段,请求:%s,响应:%s", requestBody, response); |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | } catch (com.alibaba.fastjson.JSONException e) { |
| | | String errorMsg = String.format("解析AGV订单状态响应JSON失败:%s,请求:%s,响应:%s", e.getMessage(), requestBody, response); |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | } catch (Exception e) { |
| | | String errorMsg = String.format("查询AGV订单状态异常:%s", e.getMessage()); |
| | |
| | | agvTask.setErrorMemo2(errorMsg); |
| | | agvTask.setErrorTime2(new Date()); |
| | | taskService.updateById(agvTask); |
| | | return null; |
| | | return false; |
| | | } |
| | | } |
| | | |
| | |
| | | import com.alibaba.fastjson.JSON; |
| | | import com.alibaba.fastjson.JSONObject; |
| | | import com.baomidou.mybatisplus.mapper.EntityWrapper; |
| | | import com.baomidou.mybatisplus.mapper.Wrapper; |
| | | import com.core.common.Cools; |
| | | import com.zy.asrs.entity.Task; |
| | | import com.zy.asrs.entity.TaskLog; |
| | | import com.zy.asrs.entity.WrkMast; |
| | | import com.zy.asrs.entity.BasDevp; |
| | | import com.zy.asrs.entity.LocCache; |
| | | import com.zy.asrs.entity.*; |
| | | import com.zy.asrs.mapper.BasDevpMapper; |
| | | import com.zy.asrs.mapper.BasStationMapper; |
| | | import com.zy.asrs.mapper.WrkMastMapper; |
| | | import com.zy.asrs.service.ApiLogService; |
| | | import com.zy.asrs.service.LocCacheService; |
| | | import com.zy.asrs.service.TaskLogService; |
| | | import com.zy.asrs.service.TaskService; |
| | | import com.zy.asrs.service.WrkMastService; |
| | | import com.zy.asrs.service.WrkMastLogService; |
| | | import com.zy.asrs.entity.WrkMastLog; |
| | | import com.zy.asrs.service.*; |
| | | import com.zy.common.constant.ApiInterfaceConstant; |
| | | import com.zy.common.properties.AgvProperties; |
| | | import com.zy.common.utils.AgvUtils; |
| | | import com.zy.common.utils.HttpHandler; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.springframework.beans.BeanUtils; |
| | | import org.springframework.beans.factory.annotation.Autowired; |
| | | import org.springframework.stereotype.Service; |
| | | import org.springframework.transaction.annotation.Transactional; |
| | | |
| | |
| | | |
| | | @Resource |
| | | private WrkMastLogService wrkMastLogService; |
| | | |
| | | @Resource |
| | | private LocMastService locMastService; |
| | | /** |
| | | * 站点轮询计数器,用于平均分配站点 |
| | | * Key: 站点组标识(如 "east" 或 "west"),Value: 当前轮询索引 |
| | |
| | | * @param taskList 任务列表(通常只包含一个任务) |
| | | * @return 是否成功处理了任务(成功呼叫AGV,状态从7变为8) |
| | | */ |
| | | @Transactional(rollbackFor = Exception.class) |
| | | public boolean callAgv(List<Task> taskList) { |
| | | // 记录调用堆栈,确保只能从定时任务调用 |
| | | StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); |
| | |
| | | WrkMast wrkMast = null; |
| | | if (agvTask.getWrkNo() != null) { |
| | | wrkMast = wrkMastService.selectOne( |
| | | new EntityWrapper<WrkMast>().eq("wrk_no", agvTask.getWrkNo()) |
| | | new EntityWrapper<WrkMast>() |
| | | .eq("barcode", agvTask.getBarcode()) |
| | | ); |
| | | } |
| | | |
| | | // 检查历史档是否存在 |
| | | WrkMastLog wrkMastLog = null; |
| | | if (agvTask.getWrkNo() != null) { |
| | | wrkMastLog = wrkMastLogService.selectOne( |
| | | new EntityWrapper<WrkMastLog>().eq("wrk_no", agvTask.getWrkNo()) |
| | | if (agvTask.getBarcode() != null) { |
| | | Wrapper<WrkMastLog> wrkMastLogMapper = new EntityWrapper<WrkMastLog>() |
| | | .eq("barcode", agvTask.getBarcode()); |
| | | if (agvTask.getAppeTime() != null) { |
| | | // 计算AGV创建时间之后6小时的时间 |
| | | Calendar calendar = Calendar.getInstance(); |
| | | calendar.setTime(agvTask.getAppeTime()); |
| | | calendar.add(Calendar.HOUR_OF_DAY, 6); // 加6小时 |
| | | Date endTime = calendar.getTime(); |
| | | // 查询条件:历史档创建时间 >= AGV订单创建时间 且 <= AGV创建时间之后6小时 |
| | | wrkMastLogMapper = wrkMastLogMapper.ge("appe_time", agvTask.getAppeTime()) |
| | | .le("appe_time", endTime).eq("barcode", agvTask.getBarcode()).orderBy("appe_time DESC"); |
| | | } |
| | | List<WrkMastLog> wrkMastLogList = wrkMastLogService.selectList( |
| | | wrkMastLogMapper |
| | | ); |
| | | } |
| | | // 如果通过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); |
| | | if(wrkMastLogList.size()==1){ |
| | | wrkMastLog=wrkMastLogList.get(0); |
| | | }else if(wrkMastLogList.size()>1){ |
| | | int locmastCount = locMastService.selectCount(new EntityWrapper<LocMast>().eq("loc_sts", "F").eq("barcode", agvTask.getBarcode())); |
| | | if(locmastCount>0){ |
| | | wrkMastLog=wrkMastLogList.get(0); |
| | | } |
| | | } |
| | | } |
| | | |
| | |
| | | * 取消AGV任务(仙工M4接口) |
| | | * |
| | | * @param task 任务对象 |
| | | * @return 是否成功 |
| | | * @return 成功返回 null,失败返回错误原因 |
| | | */ |
| | | public boolean cancelAgvTask(Task task) { |
| | | public String cancelAgvTask(Task task) { |
| | | if (!agvProperties.isSendTask()) { |
| | | return false; |
| | | return "未启用AGV任务下发"; |
| | | } |
| | | |
| | | if (task == null || task.getId() == null) { |
| | | log.error("取消AGV任务失败:任务或任务ID为空"); |
| | | return false; |
| | | return "任务或任务ID为空"; |
| | | } |
| | | |
| | | String response = ""; |
| | |
| | | String displayTaskId = (task.getWrkNo() != null) ? String.valueOf(task.getWrkNo()) : String.valueOf(task.getId()); |
| | | log.info(namespace + "取消AGV任务成功:{}", displayTaskId); |
| | | } else { |
| | | String errMsg = jsonObject.getString("message"); |
| | | if (errMsg == null || errMsg.isEmpty()) { |
| | | errMsg = "response: " + response; |
| | | } |
| | | log.error(namespace + "取消AGV任务失败!!!url:{};request:{};response:{}", url, body, response); |
| | | return errMsg; |
| | | } |
| | | } catch (Exception e) { |
| | | log.error(namespace + "取消AGV任务异常", e); |
| | | return e.getMessage() != null ? e.getMessage() : "取消AGV任务异常"; |
| | | } finally { |
| | | try { |
| | | // 保存接口日志 |
| | |
| | | } |
| | | } |
| | | |
| | | return success; |
| | | return success ? null : "取消AGV任务失败"; |
| | | } |
| | | } |
| | |
| | | import com.core.common.R; |
| | | import com.core.exception.CoolException; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.apache.catalina.connector.ClientAbortException; |
| | | import org.springframework.web.HttpRequestMethodNotSupportedException; |
| | | import org.springframework.web.bind.annotation.ExceptionHandler; |
| | | import org.springframework.web.bind.annotation.RestControllerAdvice; |
| | |
| | | @Override |
| | | public void addInterceptors(InterceptorRegistry registry) { |
| | | registry.addInterceptor(adminInterceptor) |
| | | .addPathPatterns("/**").excludePathPatterns("/license/getServerlnfos") |
| | | .addPathPatterns("/**").excludePathPatterns("/license/getServerInfos") |
| | | ; |
| | | } |
| | | |
| | |
| | | //每天晚上11点更新系统激活状态 |
| | | @Scheduled(cron = "0 0 23 * * ? ") |
| | | public void timer() { |
| | | if (!schedulerProperties.isEnabled()) { |
| | | return; |
| | | } |
| | | try { |
| | | getRemoteLicense(); |
| | | } catch (Exception e) { |
| | |
| | | var cacd = cacw.parent().find(".cool-auto-complete-div"); |
| | | var realDom = cacd.prev(); |
| | | // id字段 |
| | | var selectOptionDom = selectDom.find("option:selected"); |
| | | var html = selectOptionDom.html(); |
| | | if (html === "取消选择") { |
| | | cacd.val(""); |
| | | realDom.val(""); |
| | | var selectOptionDoms = selectDom.find("option:selected"); |
| | | |
| | | // 检查是否是多选 |
| | | if (selectDom.attr("multiple") === "multiple" || selectDom.attr("multiple") === true) { |
| | | // 多选处理 |
| | | var selectedValues = []; |
| | | var selectedTexts = []; |
| | | selectOptionDoms.each(function() { |
| | | var option = $(this); |
| | | var html = option.html(); |
| | | if (html !== "取消选择") { |
| | | selectedValues.push(option.attr("title")); |
| | | selectedTexts.push(html); |
| | | } |
| | | }); |
| | | |
| | | if (selectedValues.length === 0) { |
| | | cacd.val(""); |
| | | realDom.val(""); |
| | | } else { |
| | | cacd.val(selectedTexts.join(", ")); |
| | | realDom.val(selectedValues.join(",")); |
| | | } |
| | | } else { |
| | | cacd.val(selectOptionDom.html()); |
| | | realDom.val(selectOptionDom.attr("title")); |
| | | // 单选处理(原有逻辑) |
| | | var html = selectOptionDoms.html(); |
| | | if (html === "取消选择") { |
| | | cacd.val(""); |
| | | realDom.val(""); |
| | | } else { |
| | | cacd.val(selectOptionDoms.html()); |
| | | realDom.val(selectOptionDoms.attr("title")); |
| | | } |
| | | } |
| | | inputDom.val(""); |
| | | } |
| | |
| | | var pageCurr; |
| | | var tableIns; |
| | | layui.config({ |
| | | base: baseUrl + "/static/layui/lay/modules/" |
| | | }).use(['table', 'laydate', 'form', 'admin'], function () { |
| | |
| | | var form = layui.form; |
| | | var admin = layui.admin; |
| | | |
| | | // 数据渲染 |
| | | tableIns = table.render({ |
| | | // AGV任务管理:工作状态用多选框(勾选多项),仅本页;用原生 checkbox 不经过 layui 美化,保证勾选与框内显示始终一致 |
| | | function updateTaskWrkStsFromCheckbox() { |
| | | var ids = [], texts = []; |
| | | $('#taskWrkStsCheckboxWrap input:checkbox:checked').each(function () { |
| | | var $input = $(this); |
| | | ids.push($input.val()); |
| | | var text = $input.data('text') || $input.closest('label').clone().children().remove().end().text().trim() || $input.val(); |
| | | texts.push(text); |
| | | }); |
| | | $('input[name="wrk_sts"]').val(ids.join(',')); |
| | | $('#wrkSts\\$').val(texts.join(', ')); |
| | | } |
| | | |
| | | $(document).on('change', '#taskWrkStsCheckboxWrap input:checkbox', updateTaskWrkStsFromCheckbox); |
| | | |
| | | function initWrkStsDropdownThenTable() { |
| | | $.ajax({ |
| | | url: baseUrl + '/basWrkStatusQueryAgv/auth', |
| | | headers: {token: localStorage.getItem('token')}, |
| | | data: {condition: ''}, |
| | | method: 'POST', |
| | | traditional: true, |
| | | success: function (res) { |
| | | var $wrap = $('#taskWrkStsCheckboxWrap'); |
| | | $wrap.empty(); |
| | | var defaultIds = {'7': true, '8': true, '9': true}; |
| | | if (res.code === 200 && res.data && res.data.length) { |
| | | res.data.forEach(function (item) { |
| | | var id = String(item.id); |
| | | var text = item.value || id; |
| | | var checked = defaultIds[id] ? ' checked' : ''; |
| | | $wrap.append( |
| | | '<label class="task-wrksts-cb-label" style="display: inline-block; margin: 4px 12px 4px 0; cursor: pointer;"><input type="checkbox" value="' + id + '" data-text="' + (text.replace(/"/g, '"')) + '"' + checked + '> ' + text + '</label>' |
| | | ); |
| | | }); |
| | | updateTaskWrkStsFromCheckbox(); |
| | | } |
| | | |
| | | // 点击输入框展开/收起下拉(不调用 autoShow,避免走全局逻辑) |
| | | $('#wrkSts\\$').off('click').on('click', function () { |
| | | var $win = $('#taskWrkStsWindow'); |
| | | $win.toggle(); |
| | | }); |
| | | |
| | | var initialWhere = {}; |
| | | $.each($('#search-box [name]').serializeArray(), function () { |
| | | initialWhere[this.name] = this.value; |
| | | }); |
| | | renderTaskTable(initialWhere); |
| | | }, |
| | | error: function () { |
| | | renderTaskTable({}); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | function renderTaskTable(initialWhere) { |
| | | tableIns = table.render({ |
| | | elem: '#task', |
| | | headers: {token: localStorage.getItem('token')}, |
| | | url: baseUrl + '/task/list/auth', |
| | | where: initialWhere, |
| | | page: true, |
| | | limit: 15, |
| | | limits: [15, 30, 50, 100, 200, 500], |
| | |
| | | , {field: 'staNo$', align: 'center', title: '目标站', width: 120} |
| | | , {field: 'locNo', align: 'center', title: '目标库位', width: 120} |
| | | , {field: 'barcode', align: 'center', title: '条码', width: 110} |
| | | , {field: 'errorMemo', align: 'center', title: '错误原因', width: 200} |
| | | , {field: 'errorMemo2', align: 'center', title: '错误原因2', width: 200, hide: true} |
| | | , {field: 'errorMemo', align: 'center', title: 'AGV回复报文', width: 200, hide: true} |
| | | , {field: 'errorMemo2', align: 'center', title: 'AGV回复报文2', width: 200, hide: true} |
| | | , {field: 'errorTime$', align: 'center', title: '错误时间', width: 160, hide: true} |
| | | , {field: 'preHave', align: 'center', title: '先入品', hide: true} |
| | | , {field: 'takeNone', align: 'center', title: '空操作', hide: true} |
| | |
| | | pageCurr = curr; |
| | | limit(); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | initWrkStsDropdownThenTable(); |
| | | |
| | | // 监听排序事件 |
| | | table.on('sort(task)', function (obj) { |
| | |
| | | }, function () { |
| | | }); |
| | | break; |
| | | // 删除(单条) |
| | | case 'delete': |
| | | layer.confirm('确定要删除该条AGV任务吗?', { |
| | | title: '工作号:' + data.wrkNo, |
| | | shadeClose: true |
| | | }, function (i) { |
| | | layer.close(i); |
| | | var loadIndex = layer.load(2); |
| | | $.ajax({ |
| | | url: baseUrl + "/task/delete/auth", |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | data: {'ids[]': [data.id]}, |
| | | traditional: true, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | layer.close(loadIndex); |
| | | if (res.code === 200) { |
| | | layer.msg(res.msg || '删除成功', {icon: 1}); |
| | | tableReload(); |
| | | } else if (res.code === 403) { |
| | | top.location.href = baseUrl + "/"; |
| | | } else { |
| | | layer.msg(res.msg, {icon: 2}); |
| | | } |
| | | } |
| | | }); |
| | | }); |
| | | break; |
| | | } |
| | | }); |
| | | |
| | |
| | | $.ajax({ |
| | | url: baseUrl + "/task/delete/auth", |
| | | headers: {'token': localStorage.getItem('token')}, |
| | | data: {ids: ids}, |
| | | data: {'ids[]': ids}, |
| | | method: 'POST', |
| | | success: function (res) { |
| | | layer.close(loadIndex); |
| | |
| | | }); |
| | | |
| | | function tableReload(child) { |
| | | if (!tableIns) return; |
| | | var searchData = {}; |
| | | $.each($('#search-box [name]').serializeArray(), function () { |
| | | searchData[this.name] = this.value; |
| | |
| | | var pageCurr; |
| | | var wrkNo; |
| | | var ioTime; |
| | | var tableIns; |
| | | layui.use(['table', 'laydate', 'form'], function () { |
| | | var table = layui.table; |
| | | var $ = layui.jquery; |
| | |
| | | var layDate = layui.laydate; |
| | | var form = layui.form; |
| | | |
| | | // 数据渲染 |
| | | tableIns = table.render({ |
| | | elem: '#taskLog', |
| | | headers: { token: localStorage.getItem('token') }, |
| | | url: baseUrl + '/taskLog/list/auth', |
| | | page: true, |
| | | limit: 16, |
| | | limits: [16, 30, 50, 100, 200, 500], |
| | | // AGV工作档日志:工作状态多选(与AGV任务管理一致),默认 7、8、9 |
| | | function updateTaskLogWrkStsFromCheckbox() { |
| | | var ids = [], texts = []; |
| | | $('#taskLogWrkStsCheckboxWrap input:checkbox:checked').each(function () { |
| | | var $input = $(this); |
| | | ids.push($input.val()); |
| | | var text = $input.data('text') || $input.closest('label').clone().children().remove().end().text().trim() || $input.val(); |
| | | texts.push(text); |
| | | }); |
| | | $('#taskLogWrkSts').val(ids.join(',')); |
| | | $('#taskLogWrkStsDisp').val(texts.join(', ')); |
| | | } |
| | | $(document).on('change', '#taskLogWrkStsCheckboxWrap input:checkbox', updateTaskLogWrkStsFromCheckbox); |
| | | |
| | | function initTaskLogWrkStsThenTable() { |
| | | $.ajax({ |
| | | url: baseUrl + '/basWrkStatusQueryAgv/auth', |
| | | headers: { token: localStorage.getItem('token') }, |
| | | data: { condition: '' }, |
| | | method: 'POST', |
| | | traditional: true, |
| | | success: function (res) { |
| | | var $wrap = $('#taskLogWrkStsCheckboxWrap'); |
| | | $wrap.empty(); |
| | | var defaultIds = { '7': true, '8': true, '9': true }; |
| | | if (res.code === 200 && res.data && res.data.length) { |
| | | res.data.forEach(function (item) { |
| | | var id = String(item.id); |
| | | var text = item.value || id; |
| | | var checked = defaultIds[id] ? ' checked' : ''; |
| | | $wrap.append( |
| | | '<label class="taskLog-wrksts-cb-label" style="display: inline-block; margin: 4px 12px 4px 0; cursor: pointer;"><input type="checkbox" value="' + id + '" data-text="' + (text.replace(/"/g, '"')) + '"' + checked + '> ' + text + '</label>' |
| | | ); |
| | | }); |
| | | updateTaskLogWrkStsFromCheckbox(); |
| | | } |
| | | $('#taskLogWrkStsDisp').off('click').on('click', function () { |
| | | $('#taskLogWrkStsWindow').toggle(); |
| | | }); |
| | | var initialWhere = {}; |
| | | $.each($('#search-box [name]').serializeArray(), function () { |
| | | initialWhere[this.name] = this.value; |
| | | }); |
| | | renderTaskLogTable(initialWhere); |
| | | }, |
| | | error: function () { |
| | | renderTaskLogTable({}); |
| | | } |
| | | }); |
| | | } |
| | | |
| | | function renderTaskLogTable(initialWhere) { |
| | | tableIns = table.render({ |
| | | elem: '#taskLog', |
| | | headers: { token: localStorage.getItem('token') }, |
| | | url: baseUrl + '/taskLog/list/auth', |
| | | where: initialWhere || {}, |
| | | page: true, |
| | | limit: 15, |
| | | limits: [15, 30, 50, 100, 200, 500], |
| | | even: true, |
| | | toolbar: '#toolbar', |
| | | cellMinWidth: 50, |
| | | height: 'full-120', |
| | | cols: [[ |
| | | // {field: 'id', align: 'center', title: 'id'} |
| | | { field: 'wrkNo', align: 'center', title: '工作号', sort: true, width: 105 } |
| | | , { field: 'ioTime$', align: 'center', title: '工作时间', } |
| | | , { field: 'wrkSts$', align: 'center', title: '工作状态', } |
| | | , { field: 'agvWrkNo', align: 'center', title: 'AGV工作号', width: 180 } |
| | | , { field: 'ioTime$', align: 'center', title: '工作时间', width: 160 } |
| | | , { field: 'wrkSts$', align: 'center', title: '工作状态', width: 150 } |
| | | , { field: 'ioType$', align: 'center', title: '入出库类型', width: 150 } |
| | | , { field: 'ioPri', align: 'center', title: '优先级', width: 80 } |
| | | , { field: 'taskType$', align: 'center', title: '任务类型', width: 120 } |
| | |
| | | , { field: 'staNo$', align: 'center', title: '目标站', width: 120 } |
| | | , { field: 'locNo', align: 'center', title: '目标库位', width: 120 } |
| | | , { field: 'barcode', align: 'center', title: '条码', width: 110 } |
| | | , { field: 'errorMemo', align: 'center', title: 'AGV回复报文', width: 200, hide: true } |
| | | , { field: 'errorMemo2', align: 'center', title: 'AGV回复报文2', width: 200, hide: true } |
| | | , { field: 'errorTime$', align: 'center', title: '错误时间', width: 160, hide: true } |
| | | , { field: 'preHave', align: 'center', title: '先入品', hide: true } |
| | | , { field: 'takeNone', align: 'center', title: '空操作', hide: true } |
| | | , { field: 'modiUser$', align: 'center', title: '修改人员', hide: true } |
| | | , { field: 'modiTime$', align: 'center', title: '修改时间', hide: true, width: 160 } |
| | | , { fixed: 'right', title: '操作', align: 'center', toolbar: '#operate', width: 200 } |
| | | , { fixed: 'right', title: '操作', align: 'center', toolbar: '#operate', width: 250 } |
| | | ]], |
| | | request: { |
| | | pageName: 'curr', |
| | |
| | | } |
| | | }); |
| | | } |
| | | }); |
| | | }); |
| | | } |
| | | |
| | | initTaskLogWrkStsThenTable(); |
| | | |
| | | // 监听排序事件 |
| | | table.on('sort(taskLog)', function (obj) { |
| | |
| | | form.on('submit(reset)', function (data) { |
| | | pageCurr = 1; |
| | | clearFormVal($('#search-box')); |
| | | $('#taskLogWrkStsCheckboxWrap input:checkbox').prop('checked', false); |
| | | $('#taskLogWrkSts').val(''); |
| | | $('#taskLogWrkStsDisp').val(''); |
| | | tableReload(false); |
| | | }); |
| | | |
| | |
| | | }); |
| | | |
| | | function tableReload(child) { |
| | | var ins = child ? parent.tableIns : tableIns; |
| | | if (!ins) return; |
| | | var searchData = {}; |
| | | $.each($('#search-box [name]').serializeArray(), function () { |
| | | searchData[this.name] = this.value; |
| | | }); |
| | | (child ? parent.tableIns : tableIns).reload({ |
| | | ins.reload({ |
| | | where: searchData, |
| | | page: { |
| | | curr: pageCurr |
| | |
| | | } |
| | | pageCurr = curr; |
| | | if (res.data.length === 0 && count !== 0) { |
| | | tableIns.reload({ |
| | | ins.reload({ |
| | | where: searchData, |
| | | page: { |
| | | curr: pageCurr - 1 |
| | |
| | | cols: [[ |
| | | {type: 'checkbox'} |
| | | ,{field: 'wrkNo', align: 'center',title: '工作号',sort: true, width: 95} |
| | | ,{field: 'agvWrkNo', align: 'center',title: 'AGV工作号', width: 180} |
| | | ,{field: 'ioTime$', align: 'center',title: '工作时间',sort: true, width: 170} |
| | | ,{field: 'wrkSts$', align: 'center',title: '工作状态', width: 120} |
| | | ,{field: 'ioType$', align: 'center',title: '入出库类型', width: 140} |
| | |
| | | username: username, |
| | | password: hex_md5(password) |
| | | }; |
| | | debugger |
| | | $.ajax({ |
| | | url: baseUrl+"/login.action", |
| | | data: user, |
| | |
| | | <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/admin.css?v=318" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/cool.css" media="all"> |
| | | <style> |
| | | /* AGV任务管理-工作状态多选:选中后高亮 */ |
| | | .task-wrksts-cb-wrap .task-wrksts-cb-label:has(input:checked) { |
| | | color: #1890ff; |
| | | font-weight: 500; |
| | | background-color: #e6f7ff; |
| | | border-radius: 4px; |
| | | padding: 2px 6px; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | |
| | |
| | | <input class="layui-input" type="text" name="id" placeholder="编号" autocomplete="off"> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline"> |
| | | <div class="layui-input-inline cool-auto-complete" id="taskWrkStsWrap"> |
| | | <input id="wrkSts" class="layui-input" name="wrk_sts" type="text" placeholder="请输入" autocomplete="off" style="display: none"> |
| | | <input id="wrkSts$" class="layui-input cool-auto-complete-div" type="text" placeholder="工作状态" readonly onfocus="this.blur()"> |
| | | <div class="cool-auto-complete-window" id="taskWrkStsWindow" style="display: none;"> |
| | | <div style="padding: 6px 8px 0; color: #999; font-size: 12px;">可多选,直接点击勾选</div> |
| | | <div id="taskWrkStsCheckboxWrap" class="task-wrksts-cb-wrap" style="padding: 8px; max-height: 200px; overflow-y: auto;"></div> |
| | | </div> |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline" style="width: 300px"> |
| | | <div class="layui-input-inline"> |
| | | <input class="layui-input layui-laydate-range" name="create_time" type="text" |
| | | <input class="layui-input layui-laydate-range" name="appe_time" type="text" |
| | | placeholder="起始时间 - 终止时间" autocomplete="off" style="width: 300px"> |
| | | </div> |
| | | </div> |
| | |
| | | </div> |
| | | </div> |
| | | |
| | | <script type="text/html" id="toolbar"> |
| | | <div class="layui-btn-container"> |
| | | <button class="layui-btn layui-btn-primary layui-btn-sm" lay-event="exportData"><i class="layui-icon"></i>导出</button> |
| | | </div> |
| | | </script> |
| | | |
| | | <script type="text/html" id="operate"> |
| | | {{#if (d.preHave === 'Y' && d.wrkSts === 3) { }} |
| | | <a class="layui-btn layui-btn-primary layui-border-red layui-btn-xs btn-error" lay-event="preHave">先入品</a> |
| | |
| | | <a class="layui-btn layui-btn-xs btn-detlShow" lay-event="detlShow">明细</a> |
| | | <a class="layui-btn layui-btn-danger layui-btn-xs btn-complete" lay-event="complete">完成</a> |
| | | <a class="layui-btn layui-btn-primary layui-btn-xs btn-cancel" lay-event="cancel">取消</a> |
| | | <a class="layui-btn layui-btn-primary layui-btn-xs btn-delete" lay-event="delete">删除</a> |
| | | {{#if (d.ioType === 103) { }} |
| | | <a class="layui-btn layui-btn-warm layui-btn-xs btn-pick" lay-event="pick">拣</a> |
| | | {{# } }} |
| | |
| | | <link rel="stylesheet" href="../../static/layui/css/layui.css" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/cool.css" media="all"> |
| | | <link rel="stylesheet" href="../../static/css/common.css" media="all"> |
| | | <style> |
| | | .taskLog-wrksts-cb-wrap .taskLog-wrksts-cb-label:has(input:checked) { |
| | | color: #1890ff; |
| | | font-weight: 500; |
| | | background-color: #e6f7ff; |
| | | border-radius: 4px; |
| | | padding: 2px 6px; |
| | | } |
| | | </style> |
| | | </head> |
| | | <body> |
| | | <!-- 搜索栏 --> |
| | |
| | | </div> |
| | | </div> |
| | | <div class="layui-inline"> |
| | | <div class="layui-input-inline cool-auto-complete"> |
| | | <input id="wrkSts" class="layui-input" name="wrk_sts" type="text" placeholder="请输入" autocomplete="off" style="display: none"> |
| | | <input id="wrkSts$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="工作状态" onfocus=this.blur()> |
| | | <div class="cool-auto-complete-window"> |
| | | <input class="cool-auto-complete-window-input" data-key="basWrkStatusQueryBywrkSts" onkeyup="autoLoad(this.getAttribute('data-key'))"> |
| | | <select class="cool-auto-complete-window-select" data-key="basWrkStatusQueryBywrkStsSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple"> |
| | | </select> |
| | | <div class="layui-input-inline cool-auto-complete" id="taskLogWrkStsWrap"> |
| | | <input id="taskLogWrkSts" class="layui-input" name="wrk_sts" type="text" placeholder="请输入" autocomplete="off" style="display: none"> |
| | | <input id="taskLogWrkStsDisp" class="layui-input cool-auto-complete-div" type="text" placeholder="工作状态" readonly onfocus="this.blur()"> |
| | | <div class="cool-auto-complete-window" id="taskLogWrkStsWindow" style="display: none;"> |
| | | <div style="padding: 6px 8px 0; color: #999; font-size: 12px;">可多选,直接点击勾选</div> |
| | | <div id="taskLogWrkStsCheckboxWrap" class="taskLog-wrksts-cb-wrap" style="padding: 8px; max-height: 200px; overflow-y: auto;"></div> |
| | | </div> |
| | | </div> |
| | | </div> |