src/main/java/com/zy/asrs/controller/ReviewController.java
New file @@ -0,0 +1,116 @@ package com.zy.asrs.controller; import com.alibaba.excel.EasyExcel; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.plugins.Page; import com.core.annotations.ManagerAuth; import com.core.common.Cools; import com.core.common.DateUtils; import com.core.common.R; import com.core.common.SnowflakeIdWorker; import com.core.exception.CoolException; import com.zy.asrs.entity.Review; import com.zy.asrs.importexcle.ImportReviewDto; import com.zy.asrs.importexcle.ImportReviewListener; import com.zy.asrs.mapper.ReviewDetlMapper; import com.zy.asrs.service.ReviewDetlService; import com.zy.asrs.service.ReviewService; import com.zy.common.web.BaseController; import io.swagger.annotations.ApiOperation; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.MediaType; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.IOException; import java.util.Date; import java.util.Map; @RestController public class ReviewController extends BaseController { @Autowired private ReviewService reviewService; @Autowired private ReviewDetlService reviewDetlService; @Autowired private SnowflakeIdWorker snowflakeIdWorker; @Resource private ReviewDetlMapper reviewDetlMapper; @PostMapping("/importReview") @ManagerAuth(memo = "单据导入") @ApiOperation(value = "单据导入", produces = MediaType.APPLICATION_JSON_VALUE) public R importOrderData(@RequestParam("file") MultipartFile multipartFile) { try { importOrder(multipartFile); } catch (Exception e) { e.printStackTrace(); return R.error(e.getMessage()); } return R.ok("导入成功"); } @Transactional(rollbackFor = Exception.class) public void importOrder(MultipartFile multipartFile) throws IOException { // 考核数据的判重使用order_id,check_type的组合唯一索引解决 EasyExcel.read(multipartFile.getInputStream(), ImportReviewDto.class, new ImportReviewListener(snowflakeIdWorker, getUserId())).sheet().doReadSync(); } @RequestMapping(value = "/review/head/page/auth") @ManagerAuth public R head(@RequestParam(defaultValue = "1") Integer curr, @RequestParam(defaultValue = "10") Integer limit, @RequestParam(required = false) String orderByField, @RequestParam(required = false) String orderByType, @RequestParam Map<String, Object> param) { EntityWrapper<Review> wrapper = new EntityWrapper<>(); excludeTrash(param); convert(param, wrapper); if (!Cools.isEmpty(orderByField)) { wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType)); } else { wrapper.orderBy("settle").orderBy("create_time", false); } wrapper.eq("status", 1); return R.ok(reviewService.selectPage(new Page<>(curr, limit), wrapper)); } 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()); if (val.contains(RANGE_TIME_LINK)) { String[] dates = val.split(RANGE_TIME_LINK); wrapper.ge(entry.getKey(), DateUtils.convert(dates[0])); wrapper.le(entry.getKey(), DateUtils.convert(dates[1])); } else { wrapper.like(entry.getKey(), val); } } } @RequestMapping(value = "/review/update/auth") @ManagerAuth public R update(Review review) { if (Cools.isEmpty(review) || null == review.getId()) { return R.error(); } Review review2 = reviewService.selectById(review.getId()); review2.setSettle(review.getSettle()); review.setUpdateBy(getUserId()); review.setUpdateTime(new Date()); if (!reviewService.updateById(review)) { throw new CoolException("修改失败"); } return R.ok(); } } src/main/java/com/zy/asrs/controller/ReviewDetlController.java
New file @@ -0,0 +1,132 @@ package com.zy.asrs.controller; import com.alibaba.fastjson.JSONObject; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.mapper.Wrapper; import com.baomidou.mybatisplus.plugins.Page; import com.core.annotations.ManagerAuth; import com.core.common.BaseRes; import com.core.common.Cools; import com.core.common.DateUtils; import com.core.common.R; import com.zy.asrs.entity.ReviewDetl; import com.zy.asrs.service.ReviewDetlService; import com.zy.common.web.BaseController; 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; @RestController public class ReviewDetlController extends BaseController { @Autowired private ReviewDetlService reviewDetlService; @RequestMapping(value = "/reviewDetl/{id}/auth") @ManagerAuth public R get(@PathVariable("id") String id) { return R.ok(reviewDetlService.selectById(String.valueOf(id))); } @RequestMapping(value = "/reviewDetl/list/auth") @ManagerAuth public R list(@RequestParam(defaultValue = "1") Integer curr, @RequestParam(defaultValue = "10") Integer limit, @RequestParam(required = false) String orderByField, @RequestParam(required = false) String orderByType, @RequestParam Map<String, Object> param) { EntityWrapper<ReviewDetl> wrapper = new EntityWrapper<>(); excludeTrash(param); convert(param, wrapper); if (!Cools.isEmpty(orderByField)) { wrapper.orderBy(humpToLine(orderByField), "asc".equals(orderByType)); } else { wrapper.orderBy("create_time", false); } wrapper.eq("status", 1); Page<ReviewDetl> reviewDetlPage = reviewDetlService.selectPage(new Page<>(curr, limit), wrapper); return R.ok(reviewDetlPage); } 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()); if (val.contains(RANGE_TIME_LINK)) { String[] dates = val.split(RANGE_TIME_LINK); wrapper.ge(entry.getKey(), DateUtils.convert(dates[0])); wrapper.le(entry.getKey(), DateUtils.convert(dates[1])); } else { wrapper.like(entry.getKey(), val); } } } @RequestMapping(value = "/reviewDetl/add/auth") @ManagerAuth public R add(ReviewDetl reviewDetl) { reviewDetlService.insert(reviewDetl); return R.ok(); } @RequestMapping(value = "/reviewDetl/update/auth") @ManagerAuth public R update(ReviewDetl reviewDetl) { if (Cools.isEmpty(reviewDetl) || null == reviewDetl.getId()) { return R.error(); } reviewDetlService.updateById(reviewDetl); return R.ok(); } @RequestMapping(value = "/reviewDetl/delete/auth") @ManagerAuth public R delete(@RequestParam(value = "ids[]") Long[] ids) { for (Long id : ids) { reviewDetlService.deleteById(id); } return R.ok(); } @RequestMapping(value = "/reviewDetl/export/auth") @ManagerAuth public R export(@RequestBody JSONObject param) { EntityWrapper<ReviewDetl> wrapper = new EntityWrapper<>(); List<String> fields = JSONObject.parseArray(param.getJSONArray("fields").toJSONString(), String.class); Map<String, Object> map = excludeTrash(param.getJSONObject("reviewDetl")); convert(map, wrapper); List<ReviewDetl> list = reviewDetlService.selectList(wrapper); return R.ok(exportSupport(list, fields)); } @RequestMapping(value = "/reviewDetlQuery/auth") @ManagerAuth public R query(String condition) { EntityWrapper<ReviewDetl> wrapper = new EntityWrapper<>(); wrapper.like("id", condition); Page<ReviewDetl> page = reviewDetlService.selectPage(new Page<>(0, 10), wrapper); List<Map<String, Object>> result = new ArrayList<>(); for (ReviewDetl reviewDetl : page.getRecords()) { Map<String, Object> map = new HashMap<>(); map.put("id", reviewDetl.getId()); map.put("value", reviewDetl.getId()); result.add(map); } return R.ok(result); } @RequestMapping(value = "/reviewDetl/check/column/auth") @ManagerAuth public R query(@RequestBody JSONObject param) { Wrapper<ReviewDetl> wrapper = new EntityWrapper<ReviewDetl>().eq(humpToLine(String.valueOf(param.get("key"))), param.get("val")); if (null != reviewDetlService.selectOne(wrapper)) { return R.parse(BaseRes.REPEAT).add(getComment(ReviewDetl.class, String.valueOf(param.get("key")))); } return R.ok(); } } src/main/java/com/zy/asrs/entity/Review.java
New file @@ -0,0 +1,344 @@ package com.zy.asrs.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import com.core.common.Cools; import com.core.common.SpringUtils; import com.zy.asrs.service.DocTypeService; import com.zy.asrs.service.OrderSettleService; import com.zy.system.entity.User; import com.zy.system.service.UserService; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date; @Data @TableName("man_review") public class Review implements Serializable { private static final long serialVersionUID = 1L; /** * ID */ @ApiModelProperty(value = "ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 编号 */ @ApiModelProperty(value = "编号") private String uuid; /** * 订单编号 */ @ApiModelProperty(value = "订单编号") @TableField("order_no") private String orderNo; /** * 单据日期 */ @ApiModelProperty(value = "单据日期") @TableField("order_time") private String orderTime; /** * 单据类型 */ @ApiModelProperty(value = "单据类型") @TableField("doc_type") private Long docType; /** * 项目编号 */ @ApiModelProperty(value = "项目编号") @TableField("item_id") private Long itemId; @ApiModelProperty(value = "") @TableField("item_name") private String itemName; /** * 调拨项目编号 */ @ApiModelProperty(value = "调拨项目编号") @TableField("allot_item_id") private Long allotItemId; /** * 初始票据号 */ @ApiModelProperty(value = "初始票据号") @TableField("def_number") private String defNumber; /** * 票据号 */ @ApiModelProperty(value = "票据号") private String number; /** * 客户编号 */ @ApiModelProperty(value = "客户编号") private Long cstmr; /** * 客户 */ @ApiModelProperty(value = "客户") @TableField("cstmr_name") private String cstmrName; /** * 联系方式 */ @ApiModelProperty(value = "联系方式") private String tel; /** * 操作人员 */ @ApiModelProperty(value = "操作人员") @TableField("oper_memb") private String operMemb; /** * 合计金额 */ @ApiModelProperty(value = "合计金额") @TableField("total_fee") private Double totalFee; /** * 优惠率 */ @ApiModelProperty(value = "优惠率") private Double discount; /** * 优惠金额 */ @ApiModelProperty(value = "优惠金额") @TableField("discount_fee") private Double discountFee; /** * 销售或采购费用合计 */ @ApiModelProperty(value = "销售或采购费用合计") @TableField("other_fee") private Double otherFee; /** * 实付金额 */ @ApiModelProperty(value = "实付金额") @TableField("act_fee") private Double actFee; /** * 付款类型 1: 现金 2: 记账 */ @ApiModelProperty(value = "付款类型 1: 现金 2: 记账 ") @TableField("pay_type") private Integer payType; /** * 业务员 */ @ApiModelProperty(value = "业务员") private String salesman; /** * 结算天数 */ @ApiModelProperty(value = "结算天数") @TableField("account_day") private Integer accountDay; /** * 邮费支付类型 1: 在线支付 2: 货到付款 */ @ApiModelProperty(value = "邮费支付类型 1: 在线支付 2: 货到付款 ") @TableField("post_fee_type") private Integer postFeeType; /** * 邮费 */ @ApiModelProperty(value = "邮费") @TableField("post_fee") private Double postFee; /** * 付款时间 */ @ApiModelProperty(value = "付款时间") @TableField("pay_time") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date payTime; /** * 发货时间 */ @ApiModelProperty(value = "发货时间") @TableField("send_time") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date sendTime; /** * 物流名称 */ @ApiModelProperty(value = "物流名称") @TableField("ship_name") private String shipName; /** * 物流单号 */ @ApiModelProperty(value = "物流单号") @TableField("ship_code") private String shipCode; /** * 订单状态 */ @ApiModelProperty(value = "订单状态") private Long settle; /** * 状态 1: 正常 0: 禁用 */ @ApiModelProperty(value = "状态 1: 正常 0: 禁用 ") private Integer status; /** * 添加人员 */ @ApiModelProperty(value = "添加人员") @TableField("create_by") private Long createBy; /** * 添加时间 */ @ApiModelProperty(value = "添加时间") @TableField("create_time") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 修改人员 */ @ApiModelProperty(value = "修改人员") @TableField("update_by") private Long updateBy; /** * 修改时间 */ @ApiModelProperty(value = "修改时间") @TableField("update_time") @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss") private Date updateTime; /** * 备注 */ @ApiModelProperty(value = "备注") private String memo; public String getPayTime$() { if (Cools.isEmpty(this.payTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.payTime); } public String getSendTime$() { if (Cools.isEmpty(this.sendTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.sendTime); } public String getSettle$() { OrderSettleService service = SpringUtils.getBean(OrderSettleService.class); OrderSettle orderSettle = service.selectById(this.settle); if (!Cools.isEmpty(orderSettle)) { return String.valueOf(orderSettle.getSettleName()); } return null; } public String getStatus$() { if (null == this.status) { return null; } switch (this.status) { case 1: return "正常"; case 0: return "禁用"; default: return String.valueOf(this.status); } } public String getCreateBy$() { UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.createBy); if (!Cools.isEmpty(user)) { return String.valueOf(user.getUsername()); } return null; } public String getCreateTime$() { if (Cools.isEmpty(this.createTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime); } public String getUpdateBy$() { UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.updateBy); if (!Cools.isEmpty(user)) { return String.valueOf(user.getUsername()); } return null; } public String getUpdateTime$() { if (Cools.isEmpty(this.updateTime)) { return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime); } public String getTkType() { DocTypeService service = SpringUtils.getBean(DocTypeService.class); DocType docType = service.selectById(this.docType); if (!Cools.isEmpty(docType)) { return docType.getPakout().toString(); } return "0"; } } src/main/java/com/zy/asrs/entity/ReviewDetl.java
New file @@ -0,0 +1,386 @@ package com.zy.asrs.entity; import com.baomidou.mybatisplus.annotations.TableField; import com.baomidou.mybatisplus.annotations.TableId; import com.baomidou.mybatisplus.annotations.TableName; import com.baomidou.mybatisplus.enums.IdType; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.core.common.Cools; import com.core.common.SpringUtils; import com.zy.asrs.service.BasBoxTypeService; import com.zy.asrs.service.OrderService; import com.zy.common.utils.Synchro; import com.zy.system.entity.User; import com.zy.system.service.UserService; import io.swagger.annotations.ApiModelProperty; import lombok.Data; import org.springframework.format.annotation.DateTimeFormat; import java.io.Serializable; import java.text.SimpleDateFormat; import java.util.Date; @Data @TableName("man_review_detl") public class ReviewDetl implements Serializable { private static final long serialVersionUID = 1L; /** * ID */ @ApiModelProperty(value= "ID") @TableId(value = "id", type = IdType.AUTO) private Long id; /** * 订单内码 */ @ApiModelProperty(value= "订单内码") @TableField("order_id") private Long orderId; /** * 单据编号 */ @ApiModelProperty(value= "单据编号") @TableField("order_no") private String orderNo; /** * 数量 */ @ApiModelProperty(value= "数量") private Double anfme; /** * 作业数量 * * 入库 : 组托完成,组托档、工作档、入库完成数量 * 出库 : 工作档、出库完成数量 */ @ApiModelProperty(value= "作业数量") @TableField("work_qty") private Double workQty; /** * 完成数量 * * 入库 : qty 👆 * 出库 : qty 👆 */ @ApiModelProperty(value= "完成数量") private Double qty; /** * 商品编码 */ @ApiModelProperty(value= "商品编码") private String matnr; /** * 商品名称 */ @ApiModelProperty(value= "商品名称") private String maktx; /** * 批号 */ @ApiModelProperty(value= "批号") private String batch; /** * 规格 */ @ApiModelProperty(value= "规格") private String specs; /** * 型号 */ @ApiModelProperty(value= "型号") private String model; /** * 颜色 */ @ApiModelProperty(value= "颜色") private String color; /** * 品牌 */ @ApiModelProperty(value= "品牌") private String brand; /** * 单位 */ @ApiModelProperty(value= "单位") private String unit; /** * 单价 */ @ApiModelProperty(value= "单价") private Double price; /** * sku */ @ApiModelProperty(value= "sku") private String sku; /** * 单位量 */ @ApiModelProperty(value= "单位量") private Double units; /** * 条码 */ @ApiModelProperty(value= "条码") private String barcode; /** * 产地 */ @ApiModelProperty(value= "产地") private String origin; /** * 厂家 、、江铜:暂存库位号 */ @ApiModelProperty(value= "厂家") private String manu; /** * 生产日期 */ @ApiModelProperty(value= "生产日期") @TableField("manu_date") private String manuDate; /** * 品项数 */ @ApiModelProperty(value= "品项数") @TableField("item_num") private String itemNum; /** * 安全库存量 */ @ApiModelProperty(value= "安全库存量") @TableField("safe_qty") private Double safeQty; /** * 重量 */ @ApiModelProperty(value= "重量") private Double weight; /** * 长度 */ @ApiModelProperty(value= "长度") private Double length; /** * 体积 */ @ApiModelProperty(value= "体积") private Double volume; /** * 三方编码 */ @ApiModelProperty(value= "三方编码") @TableField("three_code") private String threeCode; /** * 供应商 */ @ApiModelProperty(value= "供应商") private String supp; /** * 供应商编码 */ @ApiModelProperty(value= "供应商编码") @TableField("supp_code") private String suppCode; /** * 是否批次 1: 是 0: 否 */ @ApiModelProperty(value= "是否批次 1: 是 0: 否 ") @TableField("be_batch") private Integer beBatch; /** * 保质期 */ @ApiModelProperty(value= "保质期") @TableField("dead_time") private String deadTime; /** * 预警天数 */ @ApiModelProperty(value= "预警天数") @TableField("dead_warn") private Integer deadWarn; /** * 制购 1: 制造 2: 采购 3: 外协 、、江铜:是否确认 1: 确认 2: 未确认 */ @ApiModelProperty(value= "制购 1: 制造 2: 采购 3: 外协 ") private Integer source; /** * 要求检验 1: 是 0: 否 */ @ApiModelProperty(value= "要求检验 1: 是 0: 否 ") private Integer inspect; /** * 危险品 1: 是 0: 否 */ @ApiModelProperty(value= "危险品 1: 是 0: 否 ") private Integer danger; /** * 状态 1: 正常 0: 禁用 */ @ApiModelProperty(value= "状态 1: 正常 0: 禁用 ") private Integer status; /** * 添加人员 */ @ApiModelProperty(value= "添加人员") @TableField("create_by") private Long createBy; /** * 添加时间 */ @ApiModelProperty(value= "添加时间") @TableField("create_time") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date createTime; /** * 修改人员 */ @ApiModelProperty(value= "修改人员") @TableField("update_by") private Long updateBy; /** * 修改时间 */ @ApiModelProperty(value= "修改时间") @TableField("update_time") @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") private Date updateTime; /** * 备注 */ @ApiModelProperty(value= "备注") private String memo; @ApiModelProperty(value = "退库标记") @TableField("tk_type") private Integer tkType; /** * 卷信息ID */ @ApiModelProperty(value= "卷信息ID") @TableField("roll_up") private Long rollUp; public String getStatus$(){ if (null == this.status){ return null; } switch (this.status){ case 1: return "正常"; case 0: return "禁用"; default: return String.valueOf(this.status); } } public String getCreateBy$(){ UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.createBy); if (!Cools.isEmpty(user)){ return String.valueOf(user.getUsername()); } return null; } public String getCreateTime$(){ if (Cools.isEmpty(this.createTime)){ return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.createTime); } public String getUpdateBy$(){ UserService service = SpringUtils.getBean(UserService.class); User user = service.selectById(this.updateBy); if (!Cools.isEmpty(user)){ return String.valueOf(user.getUsername()); } return null; } public String getUpdateTime$(){ if (Cools.isEmpty(this.updateTime)){ return ""; } return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime); } public String getQty$(){ if (getAnfme().equals(getQty())){ return "已完成"; } return "未完成"; } public Double getEnableQty() { if (null != this.anfme && this.workQty != null) { return this.anfme - this.workQty; } // if (null != this.anfme && this.qty != null) { // return this.anfme - this.qty; // } return null; } public void sync(Object source) { Synchro.Copy(source, this); } public String getBrand$(){ BasBoxTypeService basBoxTypeService = SpringUtils.getBean(BasBoxTypeService.class); BasBoxType basBoxType = basBoxTypeService.selectOne(new EntityWrapper<BasBoxType>().eq("box_type", this.brand)); if (!Cools.isEmpty(basBoxType)){ return String.valueOf(basBoxType.getBoxSpecs()); } return this.brand; } } src/main/java/com/zy/asrs/importexcle/ImportReviewDto.java
New file @@ -0,0 +1,28 @@ package com.zy.asrs.importexcle; import com.alibaba.excel.annotation.ExcelProperty; import lombok.Data; /** * @author pang.jiabao * @description 导入订单dto * @createDate 2024/9/2 9:55 */ @Data public class ImportReviewDto { @ExcelProperty(value = "包装组号/源库位",index = 0) private String column1; @ExcelProperty(value = "出库单号/单据类型/客户名称/备注/目标库位",index = 1) private String column2; @ExcelProperty(value = "目标巷道/客户名称",index = 2) private String column3; @ExcelProperty(value = "备注",index = 3) private String column4; } src/main/java/com/zy/asrs/importexcle/ImportReviewListener.java
New file @@ -0,0 +1,162 @@ package com.zy.asrs.importexcle; import com.alibaba.excel.context.AnalysisContext; import com.alibaba.excel.event.AnalysisEventListener; import com.alibaba.fastjson.JSON; import com.core.common.Cools; import com.core.common.SnowflakeIdWorker; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.service.ReviewDetlService; import com.zy.asrs.service.ReviewService; import lombok.SneakyThrows; import lombok.extern.slf4j.Slf4j; import java.util.*; /** * @author pang.jiabao * @description 导入订单监听器 * @createDate 2024/9/2 9:56 */ @Slf4j public class ImportReviewListener extends AnalysisEventListener<ImportReviewDto> { /** * 每隔1000条存储数据库,实际使用中可以3000条,然后清理list ,方便内存回收 */ private static final int BATCH_COUNT = 400; private int count = 0; private String orderNo; private long orderId; private long docTypeId; List<ImportReviewDto> list = new ArrayList<>(); /** * 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。 */ private ReviewService reviewService; private ReviewDetlService reviewDetlService; private final SnowflakeIdWorker snowflakeIdWorker; private final Long userId; /** * 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来 */ public ImportReviewListener(SnowflakeIdWorker snowflakeIdWorker, Long userId) { this.snowflakeIdWorker = snowflakeIdWorker; this.userId = userId; } private Set<String> uniquePackNos = new HashSet<>(); // 用于去重包装组号 @SneakyThrows @Override public void invoke(ImportReviewDto data, AnalysisContext context) { log.info("解析到第 {} 条数据:{}", ++count, JSON.toJSONString(data)); // 获取包装组号(column1) String packNo = data.getColumn1(); if (Cools.isEmpty(packNo)) { log.warn("包装组号为空,跳过该行!"); return; } // 如果已经处理过该包装组号,则跳过 if (uniquePackNos.contains(packNo)) { log.info("重复的包装组号:{},跳过", packNo); return; } // 首次出现,记录并处理 uniquePackNos.add(packNo); list.add(data); if (context.getCurrentRowNum() == 3) { return; } if (list.size() >= BATCH_COUNT) { saveData(); list.clear(); } } /** * 所有数据解析完成了 都会来调用 */ @Override public void doAfterAllAnalysed(AnalysisContext context) { // 这里也要保存数据,确保最后遗留的数据也存储到数据库 if (list.size() > 0) { saveData(); } log.info("所有数据解析完成!"); } private static final int MAX_BATCH_SIZE = 50; // 建议 100~200,根据字段数控制 /** * 分批存储数据库,避免SQL Server参数上限(2100)错误 */ private void saveData() { log.info("{}条数据,开始存储数据库!", list.size()); log.info("单据号:{},数据:{},", orderNo, JSON.toJSONString(list)); List<OrderDetl> orderDetlList = new ArrayList<>(); for (ImportReviewDto importOrderDto : list) { OrderDetl orderDetl = new OrderDetl(); if (docTypeId == 24) { orderDetl.setSpecs(String.format("%07d", Integer.parseInt(importOrderDto.getColumn1()))); // 源库位 if (importOrderDto.getColumn2() != null) { orderDetl.setModel(String.format("%07d", Integer.parseInt(importOrderDto.getColumn2()))); // 目标库位 } if (importOrderDto.getColumn3() != null) { orderDetl.setBeBatch(Integer.parseInt(importOrderDto.getColumn3())); // 巷道 } } else { orderDetl.setBrand(importOrderDto.getColumn1()); orderDetl.setSupp(importOrderDto.getColumn3()); orderDetl.setMemo(importOrderDto.getColumn4()); } orderDetl.setBatch(""); orderDetl.setOrderId(orderId); orderDetl.setOrderNo(orderNo); orderDetl.setCreateBy(9527L); orderDetl.setCreateTime(new Date()); orderDetl.setUpdateBy(9527L); orderDetl.setUpdateTime(new Date()); orderDetl.setStatus(1); orderDetl.setQty(0.0D); orderDetl.setAnfme(1.0); orderDetlList.add(orderDetl); } // ✅ 关键点:分批提交 for (int i = 0; i < orderDetlList.size(); i += MAX_BATCH_SIZE) { int end = Math.min(i + MAX_BATCH_SIZE, orderDetlList.size()); List<OrderDetl> batch = orderDetlList.subList(i, end); //reviewDetlService.batchDetls(batch); } log.info("存储数据库成功!"); } /** * 解析出现错误会进入该方法 具体看源代码或文档 */ @Override public void onException(Exception exception, AnalysisContext context) throws Exception { log.error("处理异常:" + exception.getMessage()); throw exception; } } src/main/java/com/zy/asrs/mapper/ReviewDetlMapper.java
New file @@ -0,0 +1,19 @@ package com.zy.asrs.mapper; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.entity.Review; import com.zy.asrs.entity.ReviewDetl; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; import java.util.Map; @Mapper @Repository public interface ReviewDetlMapper extends BaseMapper<ReviewDetl> { int addToLogTable(ReviewDetl order); } src/main/java/com/zy/asrs/mapper/ReviewMapper.java
New file @@ -0,0 +1,18 @@ package com.zy.asrs.mapper; import com.baomidou.mybatisplus.mapper.BaseMapper; import com.zy.asrs.entity.Order; import com.zy.asrs.entity.OrderStatisticsDto; import com.zy.asrs.entity.Review; import org.apache.ibatis.annotations.Mapper; import org.apache.ibatis.annotations.Param; import org.springframework.stereotype.Repository; import java.util.List; @Mapper @Repository public interface ReviewMapper extends BaseMapper<Review> { int addToLogTable(Review order); } src/main/java/com/zy/asrs/service/ReviewDetlService.java
New file @@ -0,0 +1,14 @@ package com.zy.asrs.service; import com.baomidou.mybatisplus.plugins.Page; import com.baomidou.mybatisplus.service.IService; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.entity.ReviewDetl; import java.util.List; public interface ReviewDetlService extends IService<ReviewDetl> { boolean addToLogTable(ReviewDetl orderDetl); } src/main/java/com/zy/asrs/service/ReviewService.java
New file @@ -0,0 +1,12 @@ package com.zy.asrs.service; import com.baomidou.mybatisplus.service.IService; import com.zy.asrs.entity.*; import java.util.List; public interface ReviewService extends IService<Review> { boolean addToLogTable(Review order); } src/main/java/com/zy/asrs/service/impl/ReviewDetlServiceImpl.java
New file @@ -0,0 +1,24 @@ package com.zy.asrs.service.impl; import com.baomidou.mybatisplus.mapper.EntityWrapper; import com.baomidou.mybatisplus.plugins.Page; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.core.common.Cools; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.entity.ReviewDetl; import com.zy.asrs.mapper.OrderDetlMapper; import com.zy.asrs.mapper.ReviewDetlMapper; import com.zy.asrs.service.OrderDetlService; import com.zy.asrs.service.ReviewDetlService; import org.springframework.stereotype.Service; import java.util.List; @Service("reviewDetlService") public class ReviewDetlServiceImpl extends ServiceImpl<ReviewDetlMapper, ReviewDetl> implements ReviewDetlService { @Override public boolean addToLogTable(ReviewDetl orderDetl) { return this.baseMapper.addToLogTable(orderDetl) > 0; } } src/main/java/com/zy/asrs/service/impl/ReviewServiceImpl.java
New file @@ -0,0 +1,19 @@ package com.zy.asrs.service.impl; import com.baomidou.mybatisplus.service.impl.ServiceImpl; import com.zy.asrs.entity.Order; import com.zy.asrs.entity.Review; import com.zy.asrs.mapper.ReviewMapper; import com.zy.asrs.service.ReviewService; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Service; @Slf4j @Service("reviewService") public class ReviewServiceImpl extends ServiceImpl<ReviewMapper, Review> implements ReviewService { @Override public boolean addToLogTable(Review order) { return this.baseMapper.addToLogTable(order) > 0; } } src/main/java/com/zy/asrs/task/OrderMoveHistoryScheduler.java
@@ -18,4 +18,12 @@ public void execute(){ orderMoveHistoryHandler.start(); } /** * 将已完成order和orderDetl移动到log表 */ @Scheduled(cron = "0/30 * * * * ?") public void execute2(){ orderMoveHistoryHandler.start2(); } } src/main/java/com/zy/asrs/task/handler/OrderMoveHistoryHandler.java
@@ -4,8 +4,12 @@ import com.core.common.Cools; import com.zy.asrs.entity.Order; import com.zy.asrs.entity.OrderDetl; import com.zy.asrs.entity.Review; import com.zy.asrs.entity.ReviewDetl; import com.zy.asrs.service.OrderDetlService; import com.zy.asrs.service.OrderService; import com.zy.asrs.service.ReviewDetlService; import com.zy.asrs.service.ReviewService; import com.zy.asrs.task.AbstractHandler; import com.zy.asrs.task.core.ReturnT; import lombok.extern.slf4j.Slf4j; @@ -23,6 +27,11 @@ @Autowired private OrderDetlService orderDetlService; @Autowired private ReviewService reviewService; @Autowired private ReviewDetlService reviewDetlService; public ReturnT<String> start(){ List<Order> settleEqual6 = orderService.selectList(new EntityWrapper<Order>() .eq("settle", 6)); @@ -31,6 +40,18 @@ .eq("order_no", order.getOrderNo())); moveBoth(order,orderDetls); log.info("已完成单据移动至历史表成功 =====>" +order); } return SUCCESS; } public ReturnT<String> start2() { List<Review> settleEqual6 = reviewService.selectList(new EntityWrapper<Review>() .eq("settle", 6)); for (Review order : settleEqual6) { List<ReviewDetl> orderDetls = reviewDetlService.selectList(new EntityWrapper<ReviewDetl>() .eq("order_no", order.getOrderNo())); moveBoth2(order, orderDetls); log.info("已完成复合单据移动至历史表成功 =====>" + order); } return SUCCESS; } @@ -55,4 +76,24 @@ } } private void moveBoth2(Review order, List<ReviewDetl> orderDetls) { Date now = new Date(); if (!Cools.isEmpty(orderDetls)) { for (ReviewDetl orderDetl : orderDetls) { orderDetl.setUpdateBy(0L); orderDetl.setUpdateTime(now); reviewDetlService.addToLogTable(orderDetl); reviewDetlService.delete(new EntityWrapper<ReviewDetl>() .eq("id", orderDetl.getId())); } } if (!Cools.isEmpty(order)) { order.setUpdateBy(0L); order.setUpdateTime(now); reviewService.addToLogTable(order); reviewService.delete(new EntityWrapper<Review>() .eq("id", order.getId())); } } } src/main/resources/mapper/ReviewDetlMapper.xml
New file @@ -0,0 +1,12 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.asrs.mapper.ReviewDetlMapper"> <insert id="addToLogTable"> INSERT INTO man_review_detl_log SELECT * FROM man_review_detl WHERE id = #{id} </insert> </mapper> src/main/resources/mapper/ReviewMapper.xml
New file @@ -0,0 +1,14 @@ <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.zy.asrs.mapper.ReviewMapper"> <insert id="addToLogTable"> INSERT INTO man_review_log SELECT * FROM man_review WHERE id = #{id} </insert> </mapper> src/main/webapp/static/js/review/review.js
New file @@ -0,0 +1,839 @@ var insTbCount = 0; var tableCache2 = []; layui.config({ base: baseUrl + "/static/layui/lay/modules/" }).extend({ notice: 'notice/notice', }).use(['layer', 'form', 'table','upload','element', 'util', 'admin', 'xmSelect', 'laydate', 'tableMerge', 'notice'], function () { var $ = layui.jquery; var layer = layui.layer; var form = layui.form; var table = layui.table; var util = layui.util; var upload = layui.upload; var admin = layui.admin; var xmSelect = layui.xmSelect; var layDate = layui.laydate; var laytpl = layui.laytpl; var tableMerge = layui.tableMerge; var notice = layui.notice; var element = layui.element; // 渲染表格 var insTb = table.render({ elem: '#order', url: baseUrl+'/review/head/page/auth', headers: {token: localStorage.getItem('token')}, page: true, cellMinWidth: 100, cols: [[ {type: 'numbers'}, {field: 'orderNo', title: '单据编号'}, {field: 'cstmrName', align: 'center',title: '客户名称'}, {align: 'center', title: '明细', toolbar: '#tbLook', minWidth: 160, width: 160}, {field: 'createTime$', title: '创建时间', minWidth: 200, width: 200}, {field: 'settle$', align: 'center', title: '状态', templet: '#settleTpl', minWidth: 160, width: 160}, //{field: 'memo', align: 'center',title: '备注'}, {align: 'center', title: '操作', toolbar: '#operate', width: 240} ]], request: { pageName: 'curr', pageSize: 'limit' }, parseData: function (res) { return { 'code': res.code, 'msg': res.msg, 'count': res.data.total, 'data': res.data.records } }, response: { statusCode: 200 }, done: function (res, curr, count) { limit(); if (res.code === 403) { top.location.href = baseUrl+"/"; } insTbCount = count; } }); // 搜索 form.on('submit(tbSearch)', function (data) { insTb.reload({where: data.field, page: {curr: 1}}); }); //多文件列表 var uploadListIns = upload.render({ elem: '#data-btn-file2' ,elemList: $('#data-btn-file3') //列表元素对象 ,url: baseUrl+'/review/insert/labelUp/file/auth' ,accept: 'file' ,multiple: true ,number: 10 ,auto: false ,bindAction: '#testListAction' ,choose: function(obj){ // 赋值 this.data.orderId=$('.layui-layer-title').text() var that = this; var files = this.files = obj.pushFile(); //将每次选择的文件追加到文件队列 //读取本地文件 obj.preview(function(index, file, result){ var tr = $(['<tr id="upload-'+ index +'">' ,'<td>'+ file.name +'</td>' ,'<td>'+ (file.size/1014).toFixed(1) +'kb</td>' ,'<td><div class="layui-progress" lay-filter="progress-demo-'+ index +'"><div class="layui-progress-bar" lay-percent=""></div></div></td>' ,'<td>' ,'<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>' // ,'<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>' ,'</td>' ,'</tr>'].join('')); //单个重传 tr.find('.demo-reload').on('click', function(){ obj.upload(index, file); }); //删除 tr.find('.demo-delete').on('click', function(){ delete files[index]; //删除对应的文件 tr.remove(); uploadListIns.config.elem.next()[0].value = ''; //清空 input file 值,以免删除后出现同名文件不可选 }); that.elemList.append(tr); element.render('progress'); //渲染新加的进度条组件 }); } ,done: function(res, index, upload){ //成功的回调 var that = this; //if(res.code == 0){ //上传成功 var tr = that.elemList.find('tr#upload-'+ index) ,tds = tr.children(); tds.eq(3).html(''); //清空操作 delete this.files[index]; //删除文件队列已经上传成功的文件 return; //} this.error(index, upload); } ,allDone: function(obj){ //多文件上传完毕后的状态回调 console.log(obj) } ,error: function(index, upload){ //错误回调 var that = this; var tr = that.elemList.find('tr#upload-'+ index) ,tds = tr.children(); tds.eq(3).find('.demo-reload').removeClass('layui-hide'); //显示重传 } ,progress: function(n, elem, e, index){ //注意:index 参数为 layui 2.6.6 新增 element.progress('progress-demo-'+ index, n + '%'); //执行进度条。n 即为返回的进度百分比 } }); // 添加 $("#orderAddBtn").click(function () { showEditModel(); }); // 工具条点击事件 table.on('tool(order)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { showEditModel(data); } else if (layEvent === 'wrkTrace') { showWrkTrace(data.id); } else if (layEvent === 'del') { doDel(data.id); } else if (layEvent === 'labelUp') { //上传标签 // 打开弹窗 // 构建带参数的内容 layer.open({ area: '1020px', type: 1, title: '上传文件-'+data.id, content: $('#myModal') }); // 获取路径下的文件列表,使用 jQuery 的 ajax 方法 $.ajax({ url: baseUrl+'/review/view/labelUp/file/auth', data:{ orderId:data.id }, success: function(response) { if (response.code==200){ var targetTable = document.getElementById("data-btn-file3"); targetTable.innerHTML = ''; // 将获取到的文件列表添加到文件队列中进行显示 response.data.forEach(function(file,index) { // 创建tr元素 var tr = document.createElement("tr"); tr.id = "upload-"+index; tr.innerHTML = '<td>' + file.name + '</td>' + '<td>' + (file.size / 1024).toFixed(1) + 'kb</td>' + '<td><div class="layui-progress" lay-filter="progress-demo-' + index + '"><div class="layui-progress-bar" lay-percent=""></div></div></td>' + '<td>' + '<button class="layui-btn layui-btn-xs demo-reload layui-hide">重传</button>' // + '<button class="layui-btn layui-btn-xs layui-btn-danger demo-delete">删除</button>' + '</td>'; // 将tr元素添加到目标table中 targetTable.appendChild(tr); }); }else { console.log('Failed to get file list error.'); } }, error: function() { console.log('Failed to get file list.'); } }); } else if (layEvent === 'refundLoc') { //退库 pakoutPreview([data.id]); } else if (layEvent === 'complete') { doModify(data.id, data.orderNo, 4); } else if (layEvent === 'look') { var $a = $(obj.tr).find('a[lay-event="look"]'); var offset = $a.offset(); var top = offset.top; var left = offset.left; layer.open({ type: 1, title: false, area: '1020px', offset: [top + 'px', (left - 530 + $a.outerWidth()) + 'px'], shade: .01, shadeClose: true, fixed: false, content: '<table id="lookSSXMTable" lay-filter="lookSSXMTable"></table>', success: function (layero) { table.render({ elem: '#lookSSXMTable', headers: {token: localStorage.getItem('token')}, url: baseUrl+'/reviewDetl/list/auth', where: { order_id: data.id }, page: true, cellMinWidth: 100, cols: [[ {type: 'numbers'}, {field: 'matnr', title: '物质编码'}, {field: 'maktx', title: '产品名称'}, {field: 'specs', title: '规格型号'}, {field: 'batch', title: '批次号'}, {field: 'color', title: '卷号'}, {field: 'qty', title: '出库数量'}, {field: 'deadTime', title: '出库日期'}, {field: 'source', title: '复核状态'}, {field: 'memo', title: '复核备注'} ]], request: { pageName: 'curr', pageSize: 'limit' }, parseData: function (res) { return { 'code': res.code, 'msg': res.msg, 'count': res.data.total, 'data': res.data.records } }, response: { statusCode: 200 }, done: function () { $(layero).find('.layui-table-view').css('margin', '0'); }, size: '' }); } }); } }); // 显示表单弹窗 function showEditModel(expTpe) { admin.open({ type: 1, title: (expTpe ? '修改' : '添加') + '单据', content: $('#editDialog').html(), area: '1300px', success: function (layero, dIndex) { $(layero).children('.layui-layer-content').css('overflow', 'visible'); var isExpAdd = !expTpe; // 回显数据 form.val('editForm', expTpe); if (expTpe) { $('#orderNo').attr("disabled", "disabled"); } // 表单提交事件 form.on('submit(orderEditSubmit)', function (data) { // 组装数据 if (xxDataList.length <= 0) { layer.tips('请添加单据明细', '#matAddBtnComment', {tips: [1, '#ff4c4c']}); return false; } let nList = admin.util.deepClone(xxDataList); for (let xi = 0; xi < nList.length; xi++) { if (nList[xi].anfme <= 0){ layer.msg('明细修改数量不合法', {icon: 2}); return false; } if (nList[xi].anfme < nList[xi].workQty){ layer.msg('数量不能小于已作业数量', {icon: 2}); return false; } } layer.load(2); $.ajax({ url: baseUrl+"/review/form/" + (isExpAdd?"add":"modify") + "/auth", headers: {'token': localStorage.getItem('token')}, data: JSON.stringify({ orderId: Number(data.field.id), docType: Number(data.field.docType), orderNo: data.field.orderNo, orderDetlList: nList }), contentType:'application/json;charset=UTF-8', method: 'POST', success: function (res) { layer.closeAll('loading'); if (res.code === 200){ layer.close(dIndex); $(".layui-laypage-btn")[0].click(); layer.msg(res.msg, {icon: 1}); } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}); } } }) return false; }); // 明细表格 var xxDataList = []; var tbOptions = { elem: '#formSSXMTable', headers: {token: localStorage.getItem('token')}, data: xxDataList, page: true, height: '350px;', cellMinWidth: 100, cols: [[ {type: 'numbers', title: '#'}, {field: 'matnr', title: '规格', width: 160}, {field: 'maktx', title: '商品名称', width: 200}, {field: 'batch', title: '箱号', edit: true}, {field: 'specs', title: '接头'}, {field: 'anfme', title: '数量(修改)', style: 'color: blue;font-weight: bold', edit: true, minWidth: 110, width: 110}, {field: 'workQty', title: '作业数量', minWidth: 100, width: 100}, // {field: 'unit', title: '单位', width: 80}, {field: 'memo', title: '备注' , edit: true}, {align: 'center', title: '操作', toolbar: '#formSSXMTableBar', minWidth: 80, width: 80, fixed: 'right'} ]], done: function (res) { $(layero).find('.layui-table-view').css('margin', '0'); }, size: '' }; if (!isExpAdd) { $.ajax({ url: baseUrl+"/review/detl/all/auth?orderId=" + expTpe.id, headers: {'token': localStorage.getItem('token')}, method: 'GET', async: false, success: function (res) { if (res.code === 200){ xxDataList = res.data; tbOptions.data = xxDataList; } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}) } } }) } var insTbSSXM = table.render(tbOptions); // 工具条点击事件 table.on('tool(formSSXMTable)', function (obj) { var data = obj.data; var layEvent = obj.event; if (layEvent === 'edit') { showEditModel2(data); } else if (layEvent === 'del') { if(data.workQty > 0){ layer.msg("已存在作业数量,不能删除", {icon: 2}); return; } layer.confirm('确定要删除吗?', { shade: .1, skin: 'layui-layer-admin' }, function (i) { layer.close(i); for (var j = 0; j < xxDataList.length; j++) { if (xxDataList[j].matnr === data.matnr && xxDataList[j].batch === data.batch) { xxDataList.splice(j, 1); break; } } insTbSSXM.reload({data: xxDataList, page: {curr: 1}}); }); } }); // 明细数据修改 table.on('edit(formSSXMTable)', function (obj) { let index = obj.tr.attr("data-index"); let data = xxDataList[index]; if (obj.field === 'anfme'){ let vle = Number(obj.value); if (isNaN(vle)) { layer.msg("请输入数字", {icon: 2}); return false; } else { if (vle <= 0) { layer.msg("数量必须大于零", {icon: 2}); // data[obj.field] = 0; // insTbSSXM.reload({data: xxDataList}); return false; } if(obj.value < data.workQty){ layer.msg("输入数量不能小于作业中数量", {icon: 2}); // data[obj.field] = 0; // insTbSSXM.reload({data: xxDataList}); return false; } } } data[obj.field] = obj.value; insTbSSXM.reload({data: xxDataList}); }); $('#matAddBtnComment').click(function () { showEditModel2(); }); // 显示添加明细表单弹窗 function showEditModel2(exp) { admin.open({ type: 1, offset: '150px', area: '680px', title: (exp ? '修改' : '添加') + '明细', content: $('#matEditDialog').html(), success: function (layero, dIndex) { // 回显数据 form.val('matEditForm', exp); // 表单提交事件 form.on('submit(matEditSubmit)', function (data) { let selectList = matXmSelect.getValue(); for (let i = 0; i<selectList.length; i++) { let item = selectList[i]; // 查询物料详情 $.ajax({ url: baseUrl+"/mat/covert/"+item.value+"/auth", headers: {'token': localStorage.getItem('token')}, method: 'GET', async: false, success: function (res) { if (res.code === 200){ xxDataList.push(res.data); insTbSSXM.reload({data: xxDataList, page: {curr: 1}}); } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}) } } }) } layer.close(dIndex); return false; }); // 渲染物料选择 var matXmSelect = xmSelect.render({ el: '#mat', style: { width: '340px', }, autoRow: true, toolbar: { show: true }, filterable: true, remoteSearch: true, remoteMethod: function(val, cb, show){ $.ajax({ url: baseUrl+"/mat/all/get/kv", headers: {'token': localStorage.getItem('token')}, data: { condition: val }, method: 'POST', success: function (res) { if (res.code === 200){ cb(res.data) } else { cb([]); layer.msg(res.msg, {icon: 2}); } } }); } }) // 弹窗不出现滚动条 $(layero).children('.layui-layer-content').css('overflow', 'visible'); layui.form.render('select'); } }); } } }); } // 删除单据 function doDel(orderId) { layer.confirm('确定要删除吗?', { shade: .1, skin: 'layui-layer-admin' }, function (i) { layer.close(i); layer.load(2); $.ajax({ url: baseUrl+"/review/delete/auth", headers: {'token': localStorage.getItem('token')}, data: { orderId: orderId }, method: 'POST', success: function (res) { layer.closeAll('loading'); if (res.code === 200){ if (insTbCount === 0) { insTb.reload({page: {curr: 1}}); } else { $(".layui-laypage-btn")[0].click(); } layer.msg(res.msg, {icon: 1}); } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}); } } }) }); } // 修改订单状态 function doModify(orderId, orderNo, settle) { layer.confirm('确定要手动完结吗?', { shade: .1, skin: 'layui-layer-admin' }, function (i) { layer.close(i); layer.load(2); console.log(orderId); console.log(settle); $.ajax({ url: baseUrl+"/review/update/auth", headers: {'token': localStorage.getItem('token')}, data: { id: orderId, orderNo: orderNo, settle: settle }, method: 'POST', success: function (res) { layer.closeAll('loading'); if (res.code === 200){ if (insTbCount === 0) { insTb.reload({page: {curr: 1}}); } else { $(".layui-laypage-btn")[0].click(); } layer.msg(res.msg, {icon: 1}); } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}); } } }) }); } // 任务追溯 function showWrkTrace(orderId) { let loadIndex = layer.msg('请求中...', {icon: 16, shade: 0.01, time: false}); $.ajax({ url: baseUrl+"/review/wrk/trace/auth", headers: {'token': localStorage.getItem('token')}, data: { orderId: orderId }, method: 'POST', success: function (res) { layer.close(loadIndex); if (res.code === 200){ laytpl(wrkTraceDialog.innerHTML).render(res.data, function (html) { admin.open({ type: 1, title: '任务追溯', area: ['800px', '450px'], shadeClose: true, content: html, success: function (layero, dIndex) { $(layero).children('.layui-layer-content').css('overflow', 'visible'); /** 统计图表 */ var traceCharts = echarts.init(document.getElementById('wrkTraceCharts')); var traceOptions = { title: { text: '总量/作业/完成', x: 'center', y: '38%', textStyle: {fontSize: 18, color: '#262626', fontWeight: 'normal'}, subtextStyle: {fontSize: 36, color: '#10B4E8'}, itemGap: 20 }, color: ['#10B4E8', '#E0E0E0', '#FF0000'], tooltip: {trigger: 'item'}, series: [{name: '箱子数量', type: 'pie', radius: ['75%', '80%'], label: {normal: {show: false}}}] }; traceCharts.setOption(traceOptions); // 赋值 traceCharts.setOption({ title: { subtext: res.data.totalQty+"/"+res.data.wrkQty+"/"+res.data.endQty }, series: [ { data: [ {name: '已作业', value: res.data.wrkQty}, {name: '未作业', value: res.data.totalQty-res.data.wrkQty-res.data.lackQty}, {name: '库存不足', value: res.data.lackQty}, ] } ] }); } }); }); } else if (res.code === 403){ top.location.href = baseUrl+"/"; }else { layer.msg(res.msg, {icon: 2}); } } }) } layDate.render({ elem: '.layui-laydate-range' ,type: 'datetime' ,range: true }); function pakoutPreview(ids) { let loadIndex = layer.load(2); $.ajax({ url: baseUrl + "/out/refund/loc/preview/auth", headers: {'token': localStorage.getItem('token')}, contentType: 'application/json;charset=UTF-8', data: JSON.stringify(ids), method: 'POST', success: function (res) { layer.close(loadIndex); var tableCache; if (res.code === 200){ layer.open({ type: 1 ,title: false ,closeBtn: false ,offset: '50px' ,area: ['1500px', '700px'] ,shade: 0.5 ,shadeClose: false ,btn: ['生成退库单', '稍后处理'] ,btnAlign: 'c' ,moveType: 1 //拖拽模式,0或者1 ,content: $('#pakoutPreviewBox').html() ,success: function(layero, index){ stoPreTabIdx = table.render({ elem: '#stoPreTab', data: res.data, height: 520, page: false, limit: Number.MAX_VALUE, cellMinWidth: 100, cols: [[ {type: 'checkbox'}, // {type: 'checkbox', merge: ['orderNo']}, {field: 'orderNo', title: '单据编号', align: 'center'}, // {field: 'orderNo', title: '单据编号', merge: true, align: 'center'}, {field: 'title', title: '商品', align: 'center', width: 350}, // {field: 'title', title: '商品', merge: true, align: 'center', width: 350}, {field: 'batch', title: '箱号', align: 'center'}, {field: 'model', title: '卷号', align: 'center', hide: false}, {field: 'specs', title: '接头', align: 'center'}, // {field: 'brand', title: '木箱类型', align: 'center'}, {field: 'brand$', title: '木箱类型', align: 'center'}, {field: 'zpallet', title: '托盘码', align: 'center'}, {field: 'anfme', title: '数量', align: 'center', width: 90, style: 'font-weight: bold'}, {field: 'count', title: '数量', align: 'center', width: 90, style: 'font-weight: bold'}, {field: 'locNo', title: '货位', align: 'center', width: 100, templet: '#locNoTpl'}, {field: 'tkType$', title: 'TK标记', align: 'center', width: 100}, // {field: 'staNos', align: 'center', title: '出库站', merge: ['locNo'], templet: '#tbBasicTbStaNos'}, // {type: 'checkbox', merge: ['locNo']}, ]], done: function (res) { tableMerge.render(this); $('.layui-table-body.layui-table-main').css("overflow", "auto"); tableCache = tableData = table.cache.stoPreTab; } }); // 修改出库站 form.on('select(tbBasicTbStaNos)', function (obj) { let index = obj.othis.parents('tr').attr("data-index"); let data = tableCache[index]; for (let i = 0; i<tableCache.length; i++) { if (tableCache[i].locNo === data.locNo) { tableCache[i]['staNo'] = Number(obj.elem.value); } } obj.othis.children().find("input").css("color", "blue"); return false; }); // 批量修改出库站 form.on('submit(batchModifySta)', function () { let stoPreTabData = layui.table.checkStatus('stoPreTab').data; if (stoPreTabData.length < 1) { layer.msg("请至少选择一条以上合并数据", {icon: 7}); return false; } modifySta(stoPreTabData); }); // 批量修改出库站 - 站点选择 function modifySta(stoPreTabData) { // 出库站取交集 let staBatchSelectVal = []; for(let i = 0; i<stoPreTabData.length; i++) { let staNos = stoPreTabData[i].staNos; if (staNos !== null) { if (staBatchSelectVal.length === 0) { staBatchSelectVal = staNos; } else { staBatchSelectVal = staBatchSelectVal.filter(val => { return new Set(staNos).has(val) } ) } } } if (staBatchSelectVal.length === 0) { layer.msg("出库站没有交集,无法批量修改", {icon: 2}); return; } admin.open({ type: 1, area: '300px', offset: 'auto', title: '请选择站点', content: $('#staBatchSelectDialog').html(), success: function (layero, ddIndex) { // 渲染下拉框 let template = Handlebars.compile($('#batchStaSelectTpl').html()); $('#batchSelectStaBox').html(template({list: staBatchSelectVal})); // 确认 form.on('submit(staBatchSelectConfirm)', function (obj) { let loadIdx = layer.load(2); let batchSta = Number(obj.field.batchSta); let arr = []; for (let j = 0; j<stoPreTabData.length; j++) { for (let i = 0; i<tableCache.length; i++) { if (tableCache[i].orderNo === stoPreTabData[j].orderNo && tableCache[i].matnr === stoPreTabData[j].matnr && tableCache[i].locNo === stoPreTabData[j].locNo) { tableCache[i]['staNo'] = batchSta; arr.push(i); } } } stoPreTabIdx.reload({data: tableCache}); arr.forEach(item => { $('div[lay-id=stoPreTab] tr[data-index="' + item + '"] .order-sta-select').val(batchSta); }); layui.form.render('select'); arr.forEach(item => { $('div[lay-id=stoPreTab] tr[data-index="' + item + '"] .layui-select-title').find("input").css("color", "blue"); }); layer.close(loadIdx); layer.close(ddIndex); return false; }); // 弹窗不出现滚动条 $(layero).children('.layui-layer-content').css('overflow', 'visible'); layui.form.render('select'); }, }) } } ,yes: function(index, layero){ //按钮【退库】的回调 pakout(tableCache2, index); tableCache2 = [] } ,btn2: function(index, layero){ //按钮【稍后处理】的回调 layer.close(index) tableCache2 = [] //return false 开启该代码可禁止点击该按钮关闭 } }); } else if (res.code === 403){ top.location.href = baseUrl+"/"; } else { layer.msg(res.msg, {icon: 2}) } } }) // 复选框事件 table.on('checkbox(stoPreTab)', function(obj){ tableCache2.push(obj.data) }); } function pakout(tableCache, layerIndex) { // let loadIndex = layer.load(2); notice.msg('正在生成出库任务......', {icon: 4}); $.ajax({ url: baseUrl + "/out/refund/loc/auth", headers: {'token': localStorage.getItem('token')}, contentType: 'application/json;charset=UTF-8', data: JSON.stringify(tableCache), method: 'POST', success: function (res) { notice.destroy(); if (res.code === 200) { layer.close(layerIndex); layer.msg(res.msg, {icon: 1}); insTb.reload({where: null}); insTb2.reload({where: null, page: {curr: 1}}); } else if (res.code === 403) { top.location.href = baseUrl + "/"; } else { layer.msg(res.msg, {icon: 2}) } } }); } }); src/main/webapp/views/review/review.html
New file @@ -0,0 +1,389 @@ <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title></title> <meta name="renderer" content="webkit"> <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"> <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"> <link rel="stylesheet" href="../../static/css/originTable.css" media="all"> <!-- <link rel="stylesheet" href="../../static/css/common.css" media="all">--> <!--[if lt IE 9]> <script src="https://oss.maxcdn.com/html5shiv/3.7.3/html5shiv.min.js"></script> <script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script> <![endif]--> <style> .wrk-trace { color: green; cursor: pointer; margin-left: 6px; font-size: 18px; } .layui-timeline:first-child .layui-timeline-item { margin-top: 30px; } .btn-add { display: none; } .btn-edit { display: none; } .btn-complete { display: none; } .btn-delete { display: none; } </style> </head> <body> <!-- 正文开始 --> <div class="layui-fluid"> <div class="layui-card"> <div class="layui-card-body"> <!-- 表格顶部工具栏 --> <div class="layui-form toolbar"> <div class="layui-form-item"> <div class="layui-inline"> <div class="layui-input-inline mr0"> <input name="order_no" class="layui-input" type="text" placeholder="输入单据编号"/> </div> </div> <div class="layui-inline"> <div class="layui-input-inline mr0"> <input name="cstmr_name" class="layui-input" type="text" placeholder="请输入客户名称"/> </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" placeholder="起始时间 - 终止时间" autocomplete="off" style="width: 300px"> </div> </div> <div class="layui-inline"> <div class="layui-input-inline"> <select name="doc_type" id="docType-query"> </select> </div> </div> <div class="layui-inline"> <div class="layui-input-inline"> <select name="settle"> <option value="">选择状态</option> <option value="1">待处理</option> <option value="2">作业中</option> <option value="4">已完成</option> <option value="6">上报完成</option> </select> </div> </div> <div class="layui-inline"> <button class="layui-btn icon-btn" lay-filter="tbSearch" lay-submit> <i class="layui-icon"></i>搜索 </button> <!-- <button id="orderAddBtn" class="layui-btn icon-btn btn-add"><i class="layui-icon"></i>添加--> <!-- </button>--> <input type="file" id="fileInput" accept=".xlsx, .xls"> <button onclick="exportExc()">导入订单</button> </div> </div> </div> <table id="order" lay-filter="order"></table> </div> </div> <div class="layui-card"> <div class="layui-card-body"> <!-- 入库通知单:由ERP提供单据编号、类型、单据时间及物料明细,生成入库作业单,为维护系统高可用,用户可自行添加入库通知单数据,完成独立的入库作业。--> <!-- <span class="text-danger">手动添加时,请检查单据编号是否在ERP系统中已存在,避免发生数据错误问题。</span>--> <span class="text-danger">出库时,请检查单据编号是否在系统中已存在,避免发生数据错误问题。</span> </div> </div> </div> <script> function exportExc() { var fileInput = document.getElementById('fileInput'); var file = fileInput.files[0]; if (file === undefined) { alert('请先选择文件') return } var formData = new FormData(); formData.append('file', file); fetch(baseUrl+'/importOrder', { method: 'POST', headers: {'token': localStorage.getItem('token')}, body: formData }).then(response => { response.text().then(data => { var res = JSON.parse(data) alert(res.msg) }) }).catch(error => { alert('导入异常'); }); } </script> <div id="myModal" style="display: none"> <div style="padding: 10px"> <div class="layui-upload"> <button type="button" class="layui-btn layui-btn-normal" id="data-btn-file2">选择文件</button><input id="data-btn-upload" class="layui-upload-file" type="file" accept="" name="file" multiple=""> <div class="layui-upload-list" style="max-width: 1000px;height:400px;overflow: scroll"> <table class="layui-table"> <colgroup> <col> <col width="150"> <col width="260"> <col width="150"> </colgroup> <thead> <tr><th>文件名</th> <th>大小</th> <th>上传进度</th> <th>操作</th> </tr></thead> <tbody id="data-btn-file3"></tbody> </table> </div> <button type="button" class="layui-btn" id="testListAction">开始上传</button> </div> </div> </div> <!-- 表格操作列 --> <script type="text/html" id="operate"> {{# if (d.settle == 0 || d.settle == 1) { }} <!-- <a class="layui-btn layui-btn-primary layui-btn-xs btn-edit" lay-event="edit">修改</a>--> <a class="layui-btn layui-btn-danger layui-btn-xs btn-edit" lay-event="del">删除</a> <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-edit" lay-event="complete">完结</a> <!-- <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-complete" lay-event="labelUp">上传标签</a>--> {{# } }} {{# if (d.settle == 2) { }} <!-- <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-complete" lay-event="labelUp">上传标签</a>--> <a class="layui-btn layui-btn-primary layui-border-blue layui-btn-xs btn-edit" lay-event="complete">完结</a> {{# } }} {{# if (d.settle == 4 && d.tkType=='1') { }} <!-- <a class="layui-btn layui-btn-danger layui-btn-xs btn-delete" lay-event="refundLoc">退库</a>--> {{# } }} </script> <!-- 表格操作列 --> <script type="text/html" id="tbLook"> <span class="layui-text"> <a href="javascript:;" lay-event="look"> <i class="layui-icon" style="font-size: 12px;"></i> 查看单据明细 </a> </span> </script> <script type="text/html" id="orderNoTpl"> {{d.orderNo}} {{# if(d.settle > 1 && d.settle !== 3){ }} {{# } }} <i class="layui-icon layui-icon-about wrk-trace" lay-tips="查看任务追溯" lay-direction="2" lay-offset="-10px,0px" lay-event="wrkTrace"></i> </script> <!--<script type="text/html" id="settleTpl">--> <!-- <span name="settle" class="layui-badge layui-badge-gray">{{d.settle$}}</span>--> <!--</script>--> <script type="text/html" id="settleTpl"> <span name="settle" {{# if( d.settle === 1){ }} class="layui-badge layui-badge-red" {{# }else if(d.settle === 2){ }} class="layui-badge layui-badge-green" {{# }else if(d.settle === 3){ }} class="layui-badge layui-badge-gray" {{# }else if(d.settle === 4){ }} class="layui-badge layui-badge-blue" {{# }else if(d.settle === 5){ }} class="layui-badge layui-badge-gray" {{# }else if(d.settle === 6){ }} class="layui-badge layui-badge-gray" {{# } }} >{{d.settle$}}</span> </script> <!-- 表单弹窗 --> <script type="text/html" id="editDialog"> <form id="editForm" lay-filter="editForm" class="layui-form model-form"> <input name="id" type="hidden"/> <div class="layui-form-item"> <label class="layui-form-label">单据类型:</label> <div class="layui-input-block cool-auto-complete"> <input class="layui-input" name="docType" placeholder="请输入单据类型" style="display: none"> <input id="docType$" name="docType$" class="layui-input cool-auto-complete-div" onclick="autoShow(this.id)" type="text" placeholder="请输入单据类型" onfocus=this.blur() lay-verType="tips" lay-verify="required"> <div class="cool-auto-complete-window"> <input class="cool-auto-complete-window-input" data-key="docTypeQueryBydocType" onkeyup="autoLoad(this.getAttribute('data-key'))"> <select class="cool-auto-complete-window-select" data-key="docTypeQueryBydocTypeSelect" onchange="confirmed(this.getAttribute('data-key'))" multiple="multiple"> </select> </div> </div> </div> <div class="layui-form-item"> <label class="layui-form-label">单据编号:</label> <div class="layui-input-block"> <input id="orderNo" name="orderNo" placeholder="输入单据编号" type="text" class="layui-input" maxlength="20" lay-verType="tips" /> <!-- lay-verify="required"--> </div> </div> <div class="layui-form-item" style="position: relative;"> <label class="layui-form-label">单据明细:</label> <div class="layui-input-block"> <table id="formSSXMTable" lay-filter="formSSXMTable"></table> </div> <button class="layui-btn layui-btn-sm icon-btn" id="matAddBtnComment" style="position: absolute; left: 20px;top: 60px;padding: 0 5px;" type="button"> <i class="layui-icon"></i>添加明细 </button> </div> <div class="layui-form-item text-right"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="orderEditSubmit" lay-submit>保存</button> </div> </form> </script> <!-- 表格操作列 --> <script type="text/html" id="formSSXMTableBar"> <!-- <a class="layui-btn layui-btn-primary layui-btn-xs" lay-event="edit">修改</a>--> <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="del">删除</a> </script> <!-- 表单弹窗 --> <script type="text/html" id="matEditDialog"> <form id="matEditForm" lay-filter="matEditForm" class="layui-form model-form"> <input name="experimentId" type="hidden"/> <div class="layui-form-item" style="float: left"> <label class="layui-form-label">物料 - 多选</label> <div class="layui-input-block"> <div id="mat" name="mat"> </div> </div> </div> <div class="layui-form-item text-right" style="display: inline-block; margin-left: 35px"> <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button> <button class="layui-btn" lay-filter="matEditSubmit" lay-submit>保存</button> </div> </form> </script> <!-- 订单任务追溯 --> <script id="wrkTraceDialog" type="text/html" style="position: relative"> <div style="position: absolute; top: 0; left: 0;"> <div class="layui-card" style="overflow: hidden;"> <div class="layui-card-header" style="text-align: center;width: 80%;font-weight: inherit;font-size: 18px">{{ d.orderNo }}</div> <div class="layui-card-body"> <div id="wrkTraceCharts" style="height: 300px;width: 400px;transform: translateX(-10%);"></div> </div> </div> </div> <div class="layui-row" > <div class="layui-col-md5"> <h1 style="opacity: 0;">Hello World</h1> </div> <div class="layui-col-md7" style=""> {{# if(d.list.length > 0){ }} <ul class="layui-timeline" style="height: 400px; overflow: scroll;"> {{# layui.each(d.list, function(index, item){ }} <li class="layui-timeline-item"> <i class="layui-icon layui-timeline-axis"></i> <div class="layui-timeline-content layui-text"> <div class="layui-timeline-title"> <h3 class="inline-block"> {{ item.wrkNo }} {{# if(item.wrkMast.ioType < 100){ }} <span class="layui-badge layui-bg-blue" style="line-height: 20px;"> {{ item.wrkMast.ioType$ }} </span> {{# } }} {{# if(item.wrkMast.ioType > 100){ }} <span class="layui-badge layui-bg-orange" style="line-height: 20px;"> {{ item.wrkMast.ioType$ }} </span> {{# } }} {{# if(item.wrkMast.wrkSts < 14){ }} <span class="layui-badge layui-bg-red" style="line-height: 20px;"> {{ item.wrkMast.wrkSts$ }} </span> {{# } }} {{# if(item.wrkMast.wrkSts >= 14){ }} <span class="layui-badge layui-bg-green" style="line-height: 20px;"> {{ item.wrkMast.wrkSts$ }} </span> {{# } }} </h3>  {{ item.wrkMast.ioTime$ }} </div> <table class="layui-table" lay-skin="nob" style="width: 80%"> <thead> <tr style="background: none"> <td>No.</td> <td>规格</td> <!-- <td>规格</td>--> <td>箱号</td> <!-- <td>箱子类型</td>--> <td>是否确认</td> </tr> </thead> <tbody> {{# layui.each(item.wrkDetls, function(idx, wrkDetl){ }} <tr> <td><span class="layui-badge layui-bg-cyan">{{ idx+1 }}</span></td> <td>{{ wrkDetl.matnr }}</td> <!-- <td>{{ wrkDetl.specs }}</td>--> <td style="font-weight: bold">{{ wrkDetl.batch }}</td> <td style="font-weight: bold">{{ wrkDetl.source$ }}</td> </tr> {{# }); }} </tbody> </table> <hr class="layui-border-cyan" style="width: 90%; opacity: .6;"> </div> </li> {{# }); }} </ul> {{# } else { }} <div style="height: 350px;display: flex;justify-content: center;align-items: center;"> <h2 style="font-weight: bold;letter-spacing: 2px">暂无任务</h2> </div> {{# } }} </div> </div> </script> <script type="text/html" id="staBatchSelectDialog"> <form class="layui-form" style="padding: 25px 50px 30px 50px;text-align: center"> <select id="batchSelectStaBox" name="batchSta" lay-vertype="tips" lay-verify="required" required=""> </select> <button style="margin-top: 30px" class="layui-btn" lay-filter="staBatchSelectConfirm" lay-submit="">确定</button> </form> </script> <script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script> <script type="text/javascript" src="../../static/js/handlebars/handlebars-v4.5.3.js"></script> <script type="text/javascript" src="../../static/layui/layui.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/echarts/echarts.min.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/common.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/cool.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/orderTable.js" charset="utf-8"></script> <script type="text/javascript" src="../../static/js/review/review.js" charset="utf-8"></script> </body> </html>