src/main/java/basAgvLocDetl.sql
@@ -16,3 +16,11 @@ insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'basAgvLocDetl#btn-edit', N'编辑', '', '3', '2', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'basAgvLocDetl#btn-delete', N'删除', '', '3', '3', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'basAgvLocDetl#btn-export', N'导出', '', '3', '4', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGrouping/orderCargoGroupingOperate.html', N'basAgvLocDetl管理', '40524', '2', '0', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGroupingOperate#view', N'查询', '90634', '3', '0', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGroupingOperate#btn-add', N'新增', '90634', '3', '1', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGroupingOperate#btn-edit', N'编辑', '90634', '3', '2', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGroupingOperate#btn-delete', N'删除', '90634', '3', '3', '1'); insert [dbo].[sys_resource] ( [code], [name], [resource_id], [level], [sort], [status]) values ( N'orderCargoGroupingOperate#btn-export', N'导出', '90634', '3', '4', '1'); src/main/java/com/zy/asrs/controller/OpenController.java
@@ -332,6 +332,33 @@ /** * 托盘就绪状态查询 */ @PostMapping("/arm/task/loc_status") @AppAuth(memo = "托盘就绪状态查询") public synchronized R TaskArmLocStatus(@RequestHeader(required = false) String appkey, @RequestBody ArmOKParam param, HttpServletRequest request) { auth(appkey, param, request); if (Cools.isEmpty(param)) { return R.parse(BaseRes.PARAM); } if (Cools.isEmpty(param.getArmNo())) { return R.error("机械臂编号[armNo]不能为空"); } if (Cools.isEmpty(param.getStaNo())) { return R.error("站点编号[staNo]不能为空"); } boolean taskArmLocStatus = openService.TaskArmLocStatus(param); if (taskArmLocStatus){ return new R(200,"OK").add(true); } return R.error("不符合").add(false); } /** * 异常上报 */ @PostMapping("/armAbnormalOperation") @@ -373,6 +400,9 @@ param.OrderIdTwo(sign_arm_order,sign_arm_sku); } catch (Exception e){ return R.error("单据编号[order_id]以 "+sign_arm_sku+" 与 "+sign_arm_order+" 作为拆分标记拆分失败!!!"); } if (param.getArm_no()>4){ return R.ok(); } openService.taskArmWorkOrderStatus(param); @@ -451,7 +481,7 @@ boolean taskAgvReport = openService.TaskAgvReport(param); if (taskAgvReport){ agvBindAndBin(String.valueOf(param.getTaskNo())); return R.ok(); return new R(0,"成功"); } return R.error("任务号不存在"); } @@ -551,7 +581,7 @@ Thread.sleep(500); openService.agvBindAndBin(taskNo); } catch (Exception e) { log.error("异步处理AGV光栅后续逻辑失败", e); log.error("异步处理AGV搬运后续逻辑失败", e); } } src/main/java/com/zy/asrs/controller/OrderDetlPakinController.java
@@ -15,10 +15,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.*; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.*; @RestController @RequestMapping("order/pakin") src/main/java/com/zy/asrs/entity/BasAgvMast.java
@@ -136,9 +136,15 @@ @TableField("devp_id") private Integer devpId; /** * barcode */ @ApiModelProperty(value= "barcode") private String barcode; @ApiModelProperty(value= "任务类型") @TableField("io_type") private Integer ioType; private Integer ioType;//AGV库位==》输送线站点 0 AGV库位==》AGV库位 1 输送线站点==》AGV库位 2 输送线站点==》输送线站点 3 public BasAgvMast() { SnowflakeIdWorker snowflakeIdWorker = SpringUtils.getBean(SnowflakeIdWorker.class); src/main/java/com/zy/asrs/entity/BasAgvMastLog.java
@@ -87,6 +87,12 @@ private Integer floorNo; /** * barcode */ @ApiModelProperty(value= "barcode") private String barcode; /** * 状态 0: 初始 1: 作业中 2: 完成 */ @ApiModelProperty(value= "状态 0: 初始 1: 作业中 2: 完成 ") src/main/java/com/zy/asrs/entity/param/AgvBindCtnrAndBinTwoParam.java
New file @@ -0,0 +1,15 @@ package com.zy.asrs.entity.param; import lombok.Data; /* * Created by Monkey D. Luffy on 2025.09.09 * */ @Data public class AgvBindCtnrAndBinTwoParam { private String reqCode; private String podcode;//托盘码 private String positionCode = "2034";//站点 private String indBind; } src/main/java/com/zy/asrs/entity/param/AgvGoParam.java
@@ -10,5 +10,6 @@ String reqCode; //任务号 String code; // String message; // 位置 String taskCode; // } src/main/java/com/zy/asrs/entity/param/AgvGoTheArnParam.java
@@ -23,7 +23,7 @@ case "3100101": case "3100201": ArmAgvGratingParam armAgvGratingParam1 = new ArmAgvGratingParam(); armAgvGratingParam1.setArmNo(5); armAgvGratingParam1.setArmNo(6); armAgvGratingParam1.setChannel("A1"); armList.add(armAgvGratingParam1); return armList; @@ -34,11 +34,11 @@ case "2900101": case "2900201": ArmAgvGratingParam armAgvGratingParam2 = new ArmAgvGratingParam(); armAgvGratingParam2.setArmNo(5); armAgvGratingParam2.setArmNo(6); armAgvGratingParam2.setChannel("A2"); armList.add(armAgvGratingParam2); ArmAgvGratingParam armAgvGratingParam3 = new ArmAgvGratingParam(); armAgvGratingParam3.setArmNo(6); armAgvGratingParam3.setArmNo(5); armAgvGratingParam3.setChannel("A1"); armList.add(armAgvGratingParam3); return armList; @@ -47,7 +47,7 @@ case "2800101": case "2800201": ArmAgvGratingParam armAgvGratingParam4 = new ArmAgvGratingParam(); armAgvGratingParam4.setArmNo(6); armAgvGratingParam4.setArmNo(5); armAgvGratingParam4.setChannel("A2"); armList.add(armAgvGratingParam4); return armList; src/main/java/com/zy/asrs/entity/param/ArmOKParam.java
New file @@ -0,0 +1,10 @@ package com.zy.asrs.entity.param; import lombok.Data; @Data public class ArmOKParam { Integer armNo; //任务号 Integer staNo; //站点编号 } src/main/java/com/zy/asrs/entity/param/bindCtnrAndBinParam.java
@@ -7,5 +7,6 @@ String barcode; //托盘条码 String staNo; // 目标站点 String locNo; // 目标库位 Integer floorNo = 1; // 目标楼层 String indBind; // 0:解绑 1:绑定 } src/main/java/com/zy/asrs/service/OpenService.java
@@ -47,6 +47,7 @@ void taskArmReport(TaskArmReportParam param); void taskArmCycleResult(TaskArmCycleResultParam param); void taskArmWorkspaceStatus(TaskArmWorkspaceStatusParam param); boolean TaskArmLocStatus(ArmOKParam param); void taskArmWorkOrderStatus(OrderArmEndParam param); boolean TaskArmWorkOrderSign(OrderArmEndParam param); boolean TaskAgvReport(TaskAgvReportParam param); src/main/java/com/zy/asrs/service/impl/OpenServiceImpl.java
@@ -18,6 +18,7 @@ import com.zy.asrs.utils.MatUtils; import com.zy.asrs.utils.OrderInAndOutUtil; import com.zy.asrs.utils.Utils; import com.zy.common.constant.AgvConstant; import com.zy.common.constant.ArmConstant; import com.zy.common.model.DetlDto; import com.zy.common.service.CommonService; @@ -720,6 +721,40 @@ @Override @Transactional public boolean TaskArmLocStatus(ArmOKParam param) { BasArm basArm = basArmService.selectOne(new EntityWrapper<BasArm>() .eq("arm_no", param.getArmNo()) .eq("sta_no", param.getStaNo()) .eq("status", 1) ); if (Cools.isEmpty(basArm)){ log.error("机械臂配置异常,查询不到机械臂数据!!!"+ JSON.toJSONString(param)); return false; } LocMast locMast = locMastService.selectOne(new EntityWrapper<LocMast>().eq("loc_no", basArm.getStaNoSou())); if (Cools.isEmpty(locMast)){ log.error("查询不到locMast数据!!!"+ JSON.toJSONString(param)); return false; } if (locMast.getLocSts().equals("D")){ BasArmMast basArmMast = basArmMastService.selectOne( new EntityWrapper<BasArmMast>() .eq("sta_no", basArm.getStaNoSou()) .eq("arm_no", param.getArmNo()) .eq("status", 3) ); if (Cools.isEmpty(basArmMast)){ return true; } log.error("未查询到相关机械臂拆码垛任务!!!"+ JSON.toJSONString(param)); } else { log.error("locMast状态不为D!!!"+ JSON.toJSONString(param)); } return false; } @Override @Transactional public void taskArmWorkspaceStatus(TaskArmWorkspaceStatusParam param) { BasArm basArm = basArmService.selectOne(new EntityWrapper<BasArm>() .eq("arm_no", param.getArm_no()) @@ -807,6 +842,8 @@ basAgvMast.setStaNo(param.getStaNo()); basAgvMast.setSourceLocNo(param.getSourceLocNo()); basAgvMast.setLocNo(param.getLocNo()); String locNo = null; String staNo = null; // 默认值 basAgvMast.setPriority(1L); // 默认优先级 basAgvMast.setStatus(0); // 初始状态 @@ -814,11 +851,33 @@ basAgvMast.setModiTime(new Date()); // 修改时间 basAgvMast.setIoType(param.getIoType());// 任务类型 basAgvMast.setFloorNo(param.getFloorNo()); //楼层 switch (basAgvMast.getIoType()){ // AGV库位==》输送线站点 0 // AGV库位==》AGV库位 1 // 输送线站点==》AGV库位 2 // 输送线站点==》输送线站点 3 case 0: case 1: locNo = param.getSourceLocNo(); break; case 2: case 3: staNo = param.getSourceStaNo().toString(); break; } // 插入数据库 basAgvMastService.insert(basAgvMast); return true; bindCtnrAndBinParam bindParam = new bindCtnrAndBinParam(); bindParam.setBarcode(basAgvMast.getTimestamp().toString()); bindParam.setIndBind("1"); bindParam.setFloorNo(basAgvMast.getFloorNo()); bindParam.setLocNo(locNo); bindParam.setStaNo(staNo); if(bindCtnrAndBin(bindParam)){ return true; }else{ throw new CoolException("未能绑定"); } } @Override @@ -865,51 +924,53 @@ if (param == null) { throw new CoolException("参数不能为空"); } AgvBindCtnrAndBinParam agvBindCtnrAndBinParam = new AgvBindCtnrAndBinParam(); BasAgvLocNoService basAgvLocNoService = SpringUtils.getBean(BasAgvLocNoService.class); BasAgvLocNo basAgvLocNoSou = basAgvLocNoService.selectOne(new EntityWrapper<BasAgvLocNo>().eq("loc_no", param.getLocNo())); BasAgvLocNo basAgvLocNoEnd = basAgvLocNoService.selectOne(new EntityWrapper<BasAgvLocNo>().eq("sta_no", param.getStaNo())); agvBindCtnrAndBinParam.setReqCode(String.valueOf(System.currentTimeMillis())); agvBindCtnrAndBinParam.setCtnrCode(param.getBarcode()); agvBindCtnrAndBinParam.setCtnrTyp("1"); if(basAgvLocNoEnd != null && basAgvLocNoEnd.getAgvLocNo() != null){ agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoEnd.getAgvLocNo()); } if(basAgvLocNoSou != null && basAgvLocNoSou.getAgvLocNo() != null){ agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoSou.getAgvLocNo()); } agvBindCtnrAndBinParam.setIndBind(param.getIndBind()); try { String URL = "http://10.10.10.200:8181/rcms/services/rest/hikRpcService"; // AGV接口地址 String mesPath = "bindCtnrAndBin"; // 接口路径 String response = ""; boolean success = false; if (param.getFloorNo()==1){ AgvBindCtnrAndBinParam agvBindCtnrAndBinParam = new AgvBindCtnrAndBinParam(); BasAgvLocNoService basAgvLocNoService = SpringUtils.getBean(BasAgvLocNoService.class); BasAgvLocNo basAgvLocNoSou = basAgvLocNoService.selectOne(new EntityWrapper<BasAgvLocNo>().eq("loc_no", param.getLocNo())); BasAgvLocNo basAgvLocNoEnd = basAgvLocNoService.selectOne(new EntityWrapper<BasAgvLocNo>().eq("sta_no", param.getStaNo())); agvBindCtnrAndBinParam.setReqCode(String.valueOf(System.currentTimeMillis())); agvBindCtnrAndBinParam.setCtnrCode(param.getBarcode()); agvBindCtnrAndBinParam.setCtnrTyp("1"); if(basAgvLocNoEnd != null && basAgvLocNoEnd.getAgvLocNo() != null){ agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoEnd.getAgvLocNo()); } if(basAgvLocNoSou != null && basAgvLocNoSou.getAgvLocNo() != null){ agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoSou.getAgvLocNo()); } agvBindCtnrAndBinParam.setIndBind(param.getIndBind()); try { log.info("AGV绑定容器接口请求参数: {}", JSON.toJSONString(agvBindCtnrAndBinParam)); String URL = AgvConstant.AGV_URL+"/"+AgvConstant.AGV_hikRpcService; // AGV接口地址 String mesPath = AgvConstant.getAGVADAPTOR(param.getFloorNo()); // 接口路径 String response = ""; boolean success = false; try { log.info("AGV绑定容器接口请求参数: {}", JSON.toJSONString(agvBindCtnrAndBinParam)); response = new HttpHandler.Builder() .setUri(URL) .setPath(mesPath) .setJson(JSON.toJSONString(agvBindCtnrAndBinParam)) .build() .doPost(); response = new HttpHandler.Builder() .setUri(URL) .setPath(mesPath) .setJson(JSON.toJSONString(agvBindCtnrAndBinParam)) .build() .doPost(); log.info("AGV绑定容器接口响应: {}", response); JSONObject jsonObject = JSON.parseObject(response); log.info("AGV绑定容器接口响应: {}", response); JSONObject jsonObject = JSON.parseObject(response); if (jsonObject.getInteger("code") != null && jsonObject.getInteger("code").equals(0)) { success = true; } else { log.error("AGV绑定容器失败!!!url:{};request:{};response:{}", URL + "/" + mesPath, JSON.toJSONString(agvBindCtnrAndBinParam), response); throw new CoolException("AGV绑定容器失败: " + jsonObject.getString("msg")); if (jsonObject.getInteger("code") != null && jsonObject.getInteger("code").equals(0)) { success = true; } else { log.error("AGV绑定容器失败!!!url:{};request:{};response:{}", URL + "/" + mesPath, JSON.toJSONString(agvBindCtnrAndBinParam), response); throw new CoolException("AGV绑定容器失败: " + jsonObject.getString("msg")); } } catch (Exception e) { log.error("AGV绑定容器接口调用异常!!!url:{};request:{};response:{}", URL + "/" + mesPath, JSON.toJSONString(agvBindCtnrAndBinParam), response, e); throw new CoolException("AGV绑定容器接口调用异常: " + e.getMessage()); } } catch (Exception e) { log.error("AGV绑定容器接口调用异常!!!url:{};request:{};response:{}", URL + "/" + mesPath, JSON.toJSONString(agvBindCtnrAndBinParam), response, e); throw new CoolException("AGV绑定容器接口调用异常: " + e.getMessage()); throw new CoolException(e.getMessage()); } } catch (Exception e) { throw new CoolException(e.getMessage()); } } else {} return true; } @@ -933,7 +994,8 @@ agvGoParam.setCode("0"); agvGoParam.setMessage("继续执行"); agvGoParam.setReqCode(param.getReqCode()); ReturnT<String> result = new PostMesDataUtils().postMesDataArmGrating("光栅下发后继续任务:", URL, AGVPath, param); agvGoParam.setTaskCode(param.getTaskCode()); ReturnT<String> result = new PostMesDataUtils().postMesDataArmGrating("光栅下发后继续任务:", URL, AGVPath, agvGoParam); if (result.getCode()==200){ return true; } @@ -946,21 +1008,49 @@ String URL = "http://10.10.10.200:8181/"; // AGV接口地址 String AGVPath = "rcms/services/rest/hikRpcService/bindCtnrAndBin"; // 接口路径 BasAgvMast basAgvMast = basAgvMastService.selectOne(new EntityWrapper<BasAgvMast>().eq("task_no",taskNo)); BasAgvLocNoService basAgvLocNoService = SpringUtils.getBean(BasAgvLocNoService.class); BasAgvLocNo basAgvLocNoEnd = basAgvLocNoService.selectOne( new EntityWrapper<BasAgvLocNo>().eq("sta_no", basAgvMast.getStaNo()) ); AgvBindCtnrAndBinParam agvBindCtnrAndBinParam = new AgvBindCtnrAndBinParam(); agvBindCtnrAndBinParam.setReqCode(basAgvMast.getTaskNo() + "-" + basAgvMast.getTimestamp()); agvBindCtnrAndBinParam.setCtnrCode(basAgvMast.getTimestamp().toString()); agvBindCtnrAndBinParam.setCtnrTyp("1"); agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoEnd.getAgvLocNo()); agvBindCtnrAndBinParam.setIndBind("0"); ReturnT<String> resultBind = new PostMesDataUtils().postMesDataArmGrating("AGV容器绑定解绑", URL,AGVPath, agvBindCtnrAndBinParam); if (resultBind.getCode()!=200){ return true; if (Cools.isEmpty(basAgvMast)){ return false; } if (basAgvMast.getFloorNo()==1){ BasAgvLocNoService basAgvLocNoService = SpringUtils.getBean(BasAgvLocNoService.class); BasAgvLocNo basAgvLocNoEnd = basAgvLocNoService.selectOne( new EntityWrapper<BasAgvLocNo>().eq("sta_no", basAgvMast.getStaNo()) ); if (Cools.isEmpty(basAgvMast)){ return false; } AgvBindCtnrAndBinParam agvBindCtnrAndBinParam = new AgvBindCtnrAndBinParam(); agvBindCtnrAndBinParam.setReqCode(basAgvMast.getTaskNo() + "-" + basAgvMast.getTimestamp()); agvBindCtnrAndBinParam.setCtnrCode(basAgvMast.getTimestamp().toString()); agvBindCtnrAndBinParam.setCtnrTyp("1"); agvBindCtnrAndBinParam.setStgBinCode(basAgvLocNoEnd.getAgvLocNo()); agvBindCtnrAndBinParam.setIndBind("0"); ReturnT<String> resultBind = new PostMesDataUtils().postMesDataArmGrating("AGV容器绑定解绑", URL,AGVPath, agvBindCtnrAndBinParam); if (resultBind.getCode()!=200){ basAgvMast.setStatus(4); basAgvMastService.updateById(basAgvMast); return true; } return false; }else { if (basAgvMast.getIoType()==0 && (basAgvMast.getStaNo()==2034 || basAgvMast.getStaNo()==4003)){ AgvBindCtnrAndBinTwoParam agvBindCtnrAndBinTwoParam = new AgvBindCtnrAndBinTwoParam(); agvBindCtnrAndBinTwoParam.setReqCode(String.valueOf(snowflakeIdWorker.nextId())); agvBindCtnrAndBinTwoParam.setPodcode(basAgvMast.getBarcode()); agvBindCtnrAndBinTwoParam.setPositionCode(basAgvMast.getStaNo().toString()); agvBindCtnrAndBinTwoParam.setIndBind("0");; ReturnT<String> resultBind = new PostMesDataUtils().postMesDataArmGrating("AGV容器绑定解绑", AgvConstant.AGV_URL+"/"+AgvConstant.AGV_hikRpcService,AgvConstant.getAGVADAPTOR(2), agvBindCtnrAndBinTwoParam); if (resultBind.getCode()!=200){ basAgvMast.setStatus(4); basAgvMastService.updateById(basAgvMast); return true; } } } return false; } src/main/java/com/zy/asrs/task/OrderToSortLineScheduler.java
@@ -31,6 +31,8 @@ @Autowired private OrderToLineHandler orderToLineHandler; @Autowired private MatService matService; @Autowired private BasArmMastSignService basArmMastSignService; @Scheduled(cron = "0/3 * * * * ? ") @@ -63,7 +65,8 @@ } List<ItemUtilParam.Item> items = new ArrayList<>(); for (OrderDetlPakin orderDetl:orderDetlPakinList){ Integer number = basArmRulesService.getNumber(orderDetl.getWeight(),orderDetl.getVolume(),orderDetl.getManLength(),orderDetl.getWidth(),orderDetl.getHeight()); Mat mat = matService.selectByMatnr(orderDetl.getMatnr()); Integer number = basArmRulesService.getNumber(mat.getWeight(),mat.getVolume(),mat.getManLength(),mat.getWidth(),mat.getHeight()); if (number == null) { BasArmRules basArmRules = new BasArmRules(); basArmRules.setMaterialHeight(orderDetl.getHeight()); @@ -73,6 +76,7 @@ basArmRulesService.insert(basArmRules); return; } else if (number == 0){ Integer status = basArmRulesService.getStatus(orderDetl.getWeight(),orderDetl.getVolume(),orderDetl.getManLength(),orderDetl.getWidth(),orderDetl.getHeight()); if (!Cools.isEmpty(status) && status == 2){ continue; src/main/java/com/zy/asrs/task/WorkLogScheduler.java
@@ -72,7 +72,7 @@ @Scheduled(cron = "0/10 * * * * ? ") private void executeAgv(){ List<BasAgvMast> basAgvstList = basAgvMastService.selectList(new EntityWrapper<BasAgvMast>().eq("status", 3)); List<BasAgvMast> basAgvstList = basAgvMastService.selectList(new EntityWrapper<BasAgvMast>().eq("status", 4)); if (basAgvstList.isEmpty()) { return; } src/main/java/com/zy/common/constant/AgvConstant.java
New file @@ -0,0 +1,23 @@ package com.zy.common.constant; /* * Created by Monkey D. Luffy on 2025.09.09 * */ public class AgvConstant { public static final String AGV_URL = "http://10.10.10.200:8181"; public static final String AGV_hikRpcService = "rcms/services/rest/hikRpcService"; public static final String AGV_bindPodAndBerth = "bindPodAndBerth";//bangding 2 public static final String AGV_bindCtnrAndBin = "bindCtnrAndBin";//bangding 1 public static String getAGVADAPTOR(int f) { switch (f) { case 1: return AGV_bindCtnrAndBin; default: return AGV_bindPodAndBerth; } } } src/main/resources/mapper/BasAgvMastLogMapper.xml
@@ -13,6 +13,7 @@ <result column="loc_no" property="locNo" /> <result column="priority" property="priority" /> <result column="floor_no" property="floorNo" /> <result column="barcode" property="barcode" /> <result column="status" property="status" /> <result column="error_time" property="errorTime" /> <result column="error_memo" property="errorMemo" /> src/main/webapp/static/js/common.js
@@ -203,8 +203,8 @@ ,{field: 'safeQty', align: 'center',title: '总件数', hide: true} ,{field: 'weight', align: 'center',title: '单箱净重kg', hide: false} ,{field: 'manLength', align: 'center',title: '长(毫米)', hide: false} ,{field: 'height', align: 'center',title: '宽(毫米)', hide: false} ,{field: 'width', align: 'center',title: '高(毫米)', hide: false} ,{field: 'width', align: 'center',title: '宽(毫米)', hide: false} ,{field: 'height', align: 'center',title: '高(毫米)', hide: false} // ,{field: 'length', align: 'center',title: '单箱毛重', hide: true} src/main/webapp/views/orderCargoGrouping/orderCargoGroupingOperate.html
New file @@ -0,0 +1,872 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>订单入库数量修改</title> <link rel="stylesheet" href="../../static/css/element.css"> <link rel="stylesheet" href="../../static/css/element-ui.css"> <link rel="icon" href="../../static/images/favicon.ico" type="image/x-icon"> <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../../static/js/common.js"></script> <script type="text/javascript" src="../../static/js/vue.min.js"></script> <script type="text/javascript" src="../../static/js/element.js"></script> <style> .container { padding: 20px; width: 100%; max-width: 1200px; margin: 0 auto; } .table-container { margin-bottom: 20px; box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1); border-radius: 4px; overflow: hidden; } .detail-dialog .el-dialog__body { padding: 20px; } .pagination-container { margin-top: 15px; text-align: right; } .operation-cell { display: flex; justify-content: center; gap: 8px; } /* 搜索栏样式 */ .search-container { background: #f5f7fa; padding: 15px; margin-bottom: 20px; border-radius: 4px; box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); } .search-form { display: flex; flex-wrap: wrap; align-items: center; gap: 15px; } .search-item { display: flex; align-items: center; margin-right: 15px; } .search-label { min-width: 80px; text-align: right; margin-right: 10px; font-size: 14px; color: #606266; } .search-actions { display: flex; gap: 10px; margin-left: auto; } /* 确认上报按钮样式 */ .confirm-report-btn { border: 2px solid #F56C6C; color: #F56C6C; font-weight: bold; background-color: transparent; padding: 10px 20px; } .confirm-report-btn:hover { background-color: #F56C6C; color: white; } .dialog-footer { display: flex; justify-content: flex-end; align-items: center; gap: 10px; margin-top: 20px; } /* 二次确认对话框样式 */ .confirm-dialog .el-message-box__message { text-align: center; font-size: 16px; line-height: 1.5; } .confirm-dialog .el-message-box__status { font-size: 24px !important; } </style> </head> <body> <div id="app" style="display: flex;justify-content: center;flex-wrap: wrap;"> <!-- 搜索栏 --> <div class="search-container" style="width: 100%;"> <el-form :inline="true" class="search-form"> <div class="search-item"> <span class="search-label">组货单号:</span> <el-input v-model="searchForm.orderNo" placeholder="请输入组货单号" clearable style="width: 150px;" @keyup.enter.native="handleSearch" ></el-input> </div> <div class="search-item"> <span class="search-label">客户名称:</span> <el-input v-model="searchForm.cstmrName" placeholder="请输入客户名称" clearable style="width: 180px;" @keyup.enter.native="handleSearch" ></el-input> </div> <div class="search-item"> <span class="search-label">状态:</span> <el-select v-model="searchForm.settle" placeholder="请选择状态" clearable style="width: 150px;" > <el-option label="初始化" value="0"></el-option> <el-option label="待处理" value="1"></el-option> <el-option label="作业中" value="2"></el-option> <el-option label="已取消" value="3"></el-option> <el-option label="已完成" value="4"></el-option> <el-option label="准备取消" value="5"></el-option> <el-option label="上报完成" value="6"></el-option> <el-option label="数据异常" value="7"></el-option> <el-option label="审核完成" value="8"></el-option> <el-option label="提交完成" value="9"></el-option> <el-option label="保存完成" value="10"></el-option> <el-option label="上报完成未完结" value="98"></el-option> <el-option label="重新下发" value="99"></el-option> </el-select> </div> <div class="search-actions"> <el-button type="primary" icon="el-icon-search" @click="handleSearch">搜索</el-button> <el-button icon="el-icon-refresh" @click="handleReset">重置</el-button> </div> </el-form> </div> <!-- 主表A --> <div class="table-container" style="width: 100%;"> <el-table border ref="mainTable" :data="tableDataA" highlight-current-row style="width: 100%" v-loading="loading" @sort-change="handleSortChange"> <el-table-column prop="orderNo" label="订单号" width="240" align="center" sortable="custom"></el-table-column> <el-table-column prop="cstmrName" label="货主" min-width="120" align="center"></el-table-column> <!-- <el-table-column prop="orderCount" label="组货单数" width="80" align="center"></el-table-column>--> <el-table-column prop="settle$" label="状态" min-width="100" align="center" :formatter="formatStatus"></el-table-column> <el-table-column prop="createTime" label="日期" min-width="100" align="center" :formatter="formatDateColumn"></el-table-column> <el-table-column prop="updateTime" label="更新日期" min-width="100" align="center" :formatter="formatDateColumn"></el-table-column> <el-table-column label="操作" width="150" align="center" fixed="right"> <template slot-scope="scope"> <div class="operation-cell"> <el-button type="primary" size="mini" @click="showDetail(scope.row)"> 明细查看 </el-button> </div> </template> </el-table-column> </el-table> <!-- 分页控件 --> <div class="pagination-container"> <el-pagination @size-change="handleSizeChange" @current-change="handleCurrentChange" :current-page="currentPage" :page-sizes="[10, 20, 50, 100]" :page-size="pageSize" layout="total, sizes, prev, pager, next, jumper" :total="total"> </el-pagination> </div> </div> <!-- 子表B详情弹窗 --> <el-dialog title="明细" :visible.sync="detailDialogVisible" width="80%" class="detail-dialog" @close="closeDetailDialog"> <div v-if="currentRow"> <h3>组货单主表 (组货单号: {{ currentRow.itemName }})</h3> <el-descriptions :column="2" border> <el-descriptions-item label="客户名称">{{ currentRow.cstmrName }}</el-descriptions-item> <el-descriptions-item label="状态">{{ formatStatus(currentRow)}}</el-descriptions-item> <el-descriptions-item label="创建时间">{{ formatDate(currentRow.createTime) }}</el-descriptions-item> <el-descriptions-item label="备注">{{ currentRow.memo || '无' }}</el-descriptions-item> </el-descriptions> <h3 style="margin-top: 20px;">组货单明细</h3> <el-table border :data="tableDataB" style="width: 100%" v-loading="detailLoading"> <el-table-column prop="matnr" label="商品编号" min-width="80" align="center"></el-table-column> <el-table-column prop="maktx" label="名称" min-width="80" align="center"></el-table-column> <el-table-column prop="standby1" label="客户PO" min-width="80" align="center" ></el-table-column> <el-table-column prop="standby2" label="UPC" min-width="80" align="center" ></el-table-column> <el-table-column prop="standby3" label="客户SKU" min-width="80" align="center" ></el-table-column> <!-- <el-table-column prop="boxType1" label="货主" min-width="80" align="center" ></el-table-column>--> <!-- <el-table-column prop="boxType2" label="货主" min-width="80" align="center" ></el-table-column>--> <el-table-column prop="boxType3" label="采购单号" min-width="80" align="center" ></el-table-column> <el-table-column prop="anfme" label="数量" min-width="100" align="center"></el-table-column> <el-table-column prop="status" label="状态" min-width="100" align="center" :formatter="formatStatusB"></el-table-column> <!-- 新增操作列,根据status值控制显示 --> <el-table-column label="是否上报" width="120" align="center" fixed="right"> <template slot-scope="scope"> <div class="operation-cell"> <el-button v-if="scope.row.status === 2" type="primary" size="mini" @click="handleModifyN(scope.row)"> 否 </el-button> <el-button v-if="scope.row.status === 1" type="primary" size="mini" @click="handleModifyY(scope.row)"> 是 </el-button> </div> </template> </el-table-column> </el-table> <!-- 子表分页 --> <div class="pagination-container"> <el-pagination @size-change="handleDetailSizeChange" @current-change="handleDetailCurrentChange" :current-page="detailCurrentPage" :page-sizes="[5, 10, 20]" :page-size="detailPageSize" layout="total, sizes, prev, pager, next, jumper" :total="detailTotal"> </el-pagination> </div> </div> <div slot="footer" class="dialog-footer"> <el-button class="confirm-report-btn" @click="showConfirmDialog" :loading="reportLoading"> <!-- 直接在模板中判断 --> {{ settleA === 17 ? '再次上报' : '确认上报' }} </el-button> <el-button @click="closeDetailDialog">关闭</el-button> </div> </el-dialog> </div> <script> var app = new Vue({ el: '#app', data: { // 搜索表单 searchForm: { item_name: '', cstmr_name: '', settle: '', order_no: '' }, // 排序相关 orderByField: '', orderByType: 'asc', // 主表A数据 tableDataA: [], // 子表B数据 tableDataB: [], // 分页相关 currentPage: 1, pageSize: 10, total: 0, // 详情弹窗控制 detailDialogVisible: false, currentRow: null, // 子表分页 detailCurrentPage: 1, settleA: 1, detailPageSize: 5, detailTotal: 0, // 加载状态 loading: false, detailLoading: false, reportLoading: false }, created() { this.init(); }, methods: { init() { this.getTableDataA(); // 每5秒自动刷新数据 setInterval(() => { this.getTableDataA(); }, 10000); }, // 获取主表A数据 - 使用新的API getTableDataA() { let that = this; that.loading = true; // 构建请求参数 let params = { curr: that.currentPage, limit: that.pageSize }; // 添加排序参数 if (that.orderByField) { params.orderByField = that.orderByField; params.orderByType = that.orderByType; } // 添加搜索参数 Object.keys(that.searchForm).forEach(key => { if (that.searchForm[key] !== '') { if (key === 'orderNo'){ params['order_no'] = that.searchForm[key]; } else if (key === 'itemName'){ params['item_name'] = that.searchForm[key]; } else if (key === 'cstmrName'){ params['cstmr_name'] = that.searchForm[key]; } else { params[key] = that.searchForm[key]; } } }); $.ajax({ url: baseUrl + "/order/pakin/order/head/page/auth", headers: { 'token': localStorage.getItem('token') }, data: params, dataType: 'json', method: 'get', success: function (res) { if (res.code === 200 || res.success) { that.tableDataA = res.data.records || []; that.total = res.data.total || 0; } else { that.$message.error(res.message || '获取数据失败'); that.tableDataA = []; that.total = 0; } that.loading = false; }, error: function(xhr, status, error) { that.loading = false; that.$message.error('网络请求失败'); console.error('API调用失败:', error); // 模拟数据(实际项目中应删除) that.mockTableAData(); } }); }, // 获取子表B数据(根据实际业务调整) getTableDataB(orderNo) { let that = this; that.detailLoading = true; // 构建请求参数 let params = { order_no: orderNo, curr: that.detailCurrentPage, limit: that.detailPageSize }; // 模拟API调用 - 根据实际业务调整API地址 $.ajax({ url: baseUrl + "/order/pakin/orderDetl/list/auth", headers: { 'token': localStorage.getItem('token') }, data: params, dataType: 'json', contentType: 'application/json;charset=UTF-8', method: 'get', success: function (res) { if (res.code === 200 || res.success) { that.tableDataB = res.data.records || []; that.detailTotal = res.data.total || 0; } else { that.$message.error(res.message || '获取数据失败'); that.tableDataB = []; that.detailTotal = 0; } that.detailLoading = false; }, error: function() { that.detailLoading = false; // 实际项目中应使用真实API,这里使用模拟数据 that.mockTableBData(itemName); } }); }, // 处理修改按钮点击事件 handleModifyY(row) { if (!this.currentRow) { this.$message.error('没有选择主表数据'); return; } const groupOrderNo = this.currentRow.itemName; // 组货单号 const batch = row.batch; // 箱号 const status = 2; // 箱号 this.$confirm( `确定将组货单号: <strong style="color: #409EFF;">${groupOrderNo}</strong> 中的箱号: <strong style="color: #409EFF;">${batch}</strong> 添加到上报列吗?`, '确认修改', { confirmButtonText: '确认修改', cancelButtonText: '取消', type: 'warning', dangerouslyUseHTMLString: true } ).then(() => { this.submitModify(groupOrderNo, batch, status); }).catch(() => { this.$message({ type: 'info', message: '已取消修改' }); }); }, // 处理修改按钮点击事件 handleModifyN(row) { if (!this.currentRow) { this.$message.error('没有选择主表数据'); return; } const groupOrderNo = this.currentRow.itemName; // 组货单号 const batch = row.batch; // 箱号 const status = 1; // 箱号 this.$confirm( `确定将组货单号: <strong style="color: #409EFF;">${groupOrderNo}</strong> 、箱号: <strong style="color: #409EFF;">${batch}</strong> 添加到上报列吗?`, '确认修改', { confirmButtonText: '确认修改', cancelButtonText: '取消', type: 'warning', dangerouslyUseHTMLString: true } ).then(() => { this.submitModify(groupOrderNo, batch, status); }).catch(() => { this.$message({ type: 'info', message: '已取消修改' }); }); }, // 提交修改到后台 submitModify(groupOrderNo, batch, status) { // 显示加载状态 const loadingInstance = this.$loading({ lock: true, text: '提交修改中...', spinner: 'el-icon-loading', background: 'rgba(0, 0, 0, 0.7)' }); $.ajax({ url: baseUrl + "/order/pakout/orderDetl/batch/report/auth", headers: {'token': localStorage.getItem('token')}, data: top.reObject({ item_name: groupOrderNo, // 组货单号 batch: batch, // 箱号 status: status // 箱号 }), method: 'POST', success: (res) => { loadingInstance.close(); if (res.code === 200 || res.success) { this.$message({ message: `修改成功!组货单号: ${groupOrderNo}, 箱号: ${batch}`, type: 'success', duration: 3000 }); this.getTableDataB(groupOrderNo); } else { this.$message.error(res.message || '修改失败'); } }, error: (error) => { loadingInstance.close(); console.error('修改失败:', error); this.$message.error('修改失败,请检查网络连接'); } }); }, // 表格排序变化 handleSortChange(column) { if (column.prop) { this.orderByField = column.prop; this.orderByType = column.order === 'ascending' ? 'asc' : 'desc'; } else { this.orderByField = ''; this.orderByType = 'asc'; } this.currentPage = 1; this.getTableDataA(); }, showConfirmDialog() { if (!this.currentRow) { this.$message.error('没有选择要上报的数据'); return; } const groupOrderNo = this.currentRow.itemName; this.$confirm( `是否确认开始上报组货单号 <strong style="color: #F56C6C; font-size: 16px;">${groupOrderNo}</strong>?<br/><br/>将生成实际组货单,单一组货单号只能操作一次!!!`, '确认上报', { confirmButtonText: '确认上报', cancelButtonText: '取消', type: 'warning', dangerouslyUseHTMLString: true, customClass: 'confirm-dialog', confirmButtonClass: 'confirm-report-btn', beforeClose: (action, instance, done) => { if (action === 'confirm') { instance.confirmButtonLoading = true; this.confirmReport(groupOrderNo, done); } else { done(); } } } ).then(() => { // 确认上报后的处理在beforeClose中完成 }).catch(() => { this.$message({ type: 'info', message: '已取消操作' }); }); }, // 确认上报 confirmReport(groupOrderNo, done) { this.reportLoading = true; // 调用后台API上报数据 $.ajax({ url: baseUrl + "/order/pakout/actual/shipment/order/report/auth", headers: {'token': localStorage.getItem('token')}, data: { itemName: groupOrderNo // 传递组货单号 }, method: 'POST', success: (res) => { this.reportLoading = false; if (typeof done === 'function') { done(); } if (res.code === 200 || res.success) { this.$message({ message: `组货单号 ${groupOrderNo} 上报成功`, type: 'success', duration: 3000 }); // 上报成功后关闭弹窗并刷新数据 setTimeout(() => { this.closeDetailDialog(); this.getTableDataA(); // 刷新主表数据 }, 1500); } else { this.$message.error(res.message || '上报失败'); } }, error: (error) => { this.reportLoading = false; if (typeof done === 'function') { done(); } console.error('上报失败:', error); this.$message.error('上报失败,请检查网络连接'); } }); }, // 搜索处理 handleSearch() { this.currentPage = 1; this.orderByField = ''; this.orderByType = 'asc'; this.getTableDataA(); }, // 重置搜索条件 handleReset() { this.searchForm = { item_name: '', cstmr_name: '', settle: '', order_no: '' }; this.orderByField = ''; this.orderByType = 'asc'; this.currentPage = 1; this.getTableDataA(); }, // 显示详情弹窗 showDetail(row) { this.currentRow = row; this.detailDialogVisible = true; this.detailCurrentPage = 1; this.settleA = row.settle; this.getTableDataB(row.orderNo); }, // 关闭详情弹窗 closeDetailDialog() { this.detailDialogVisible = false; this.currentRow = null; this.tableDataB = []; this.reportLoading = false; }, // 主表分页大小改变 handleSizeChange(val) { this.pageSize = val; this.currentPage = 1; this.getTableDataA(); }, // 主表页码改变 handleCurrentChange(val) { this.currentPage = val; this.getTableDataA(); }, // 子表分页大小改变 handleDetailSizeChange(val) { this.detailPageSize = val; this.detailCurrentPage = 1; if (this.currentRow) { this.getTableDataB(this.currentRow.itemName); } }, // 子表页码改变 handleDetailCurrentChange(val) { this.detailCurrentPage = val; if (this.currentRow) { this.getTableDataB(this.currentRow.itemName); } }, // 格式化状态显示 formatStatus(row) { if (row.settle === 10) { return '待处理'; } else if (row.settle === 11) { return '检验中'; } else if (row.settle === 12) { return '出库中'; } else if (row.settle === 13) { return '存在不合格'; } else if (row.settle === 15) { return '待上报'; } else if (row.settle === 16) { return '上报完成'; } else if (row.settle === 17) { return '上报失败'; } else if (row.settle === 98) { return '异常'; } else if (row.settle === 99) { return '废弃'; } else { return row.settle || '未知'; } }, // 格式化状态显示 formatStatusB(row) { if (row.status === 0) { return '异常'; } else if (row.status === 1) { return '不上报'; } else if (row.status === 2) { return '待上报'; } else if (row.status === 3) { return '已上报'; } else { return row.status || '未知'; } }, // 格式化金额显示 formatCurrency(row) { if (row.totalFee) { return '¥' + parseFloat(row.totalFee).toFixed(2); } return '¥0.00'; }, // 模拟主表数据 - 实际项目中应删除 mockTableAData() { this.tableDataA = [ { itemName: 'zh20251110', orderNo: 'ORDER2024001', cstmrName: 'zh20251110', settle: 10, totalFee: 1500.00, createTime: '2025-11-10T09:50:16.343+0000', memo: '测试数据' } ]; this.total = 1; this.loading = false; }, // 模拟子表数据 - 实际项目中应删除 mockTableBData(itemName) { this.tableDataB = [ { matnr: '6μm×436mm', batch: 'L241034114', model: '24092501D01A6', origin: '1', danger: '1', memo: '', status: 1 // 状态为1,会显示修改按钮 } ]; this.detailTotal = 1; this.detailLoading = false; }, // 为表格列添加格式化方法 formatDateColumn(row, column, cellValue) { return this.formatDate(cellValue); }, // // 格式化日期显示 // formatDate(dateStr) { // if (!dateStr) return ''; // // 简单的日期格式化,可以根据实际格式调整 // return dateStr; // }, // 在Vue实例的methods中添加或修改formatDate方法 formatDate(dateStr) { if (!dateStr) return ''; try { // 创建Date对象 const date = new Date(dateStr); // 检查日期是否有效 if (isNaN(date.getTime())) { return dateStr; // 如果解析失败,返回原字符串 } // 获取各个时间组件 const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); // 返回格式化后的字符串:YYYY-MM-DD HH:mm:ss return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } catch (error) { console.error('日期格式化错误:', error); return dateStr; // 如果出错,返回原字符串 } }, //本地时区的时间 formatDate2(dateStr) { if (!dateStr) return ''; try { const date = new Date(dateStr); if (isNaN(date.getTime())) { return dateStr; } // 使用本地时区 const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } catch (error) { console.error('日期格式化错误:', error); return dateStr; } }, //保持UTC时间但转换为更易读的格式 formatDate3(dateStr) { if (!dateStr) return ''; try { // 直接解析字符串,不转换时区 const date = new Date(dateStr); if (isNaN(date.getTime())) { return dateStr; } // 使用UTC时间组件 const year = date.getUTCFullYear(); const month = String(date.getUTCMonth() + 1).padStart(2, '0'); const day = String(date.getUTCDate()).padStart(2, '0'); const hours = String(date.getUTCHours()).padStart(2, '0'); const minutes = String(date.getUTCMinutes()).padStart(2, '0'); const seconds = String(date.getUTCSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } catch (error) { console.error('日期格式化错误:', error); return dateStr; } } } }); </script> </body> </html>