自动化立体仓库 - WMS系统
tqs
2022-09-12 fdd8b1d79a9c899a0ad6dde6c17bef0a8488e6b0
Merge remote-tracking branch 'gitbit/hylyasrs' into hylyasrs
12个文件已添加
11个文件已修改
2166 ■■■■■ 已修改文件
src/main/java/com/zy/asrs/controller/ManLocDetlController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/NodeController.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/InitPakoutParam.java 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/MatnrDto.java 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/param/PakinParam.java 19 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/entity/result/Pakin.java 331 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/mapper/ManLocDetlMapper.java 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/ManLocDetlService.java 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/NodeService.java 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/ManLocDetlServiceImpl.java 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/service/impl/NodeServiceImpl.java 92 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/utils/VersionUtils.java 20 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/application.yml 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/ManLocDetlMapper.xml 29 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/resources/mapper/NodeMapper.xml 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/common.js 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/ioWorks/matQuery.js 397 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/ioWorks/stockIn.js 274 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/static/js/ioWorks/stockOut.js 180 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ioWorks/locDetlQuery.html 228 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ioWorks/matQuery.html 194 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ioWorks/stockIn.html 145 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/webapp/views/ioWorks/stockOut.html 125 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
src/main/java/com/zy/asrs/controller/ManLocDetlController.java
@@ -1,5 +1,6 @@
package com.zy.asrs.controller;
import com.baomidou.mybatisplus.plugins.Page;
import com.core.annotations.ManagerAuth;
import com.core.common.Cools;
import com.core.common.DateUtils;
@@ -52,4 +53,18 @@
        }
        return R.ok(manLocDetlService.getPage(toPage(curr, limit, param, ManLocDetl.class)));
    }
    @RequestMapping("/manLocDetl/list")
    public R outList(@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){
        Page<ManLocDetl> manLocDetlPage = toPage(curr, limit, param, ManLocDetl.class);
        Page<ManLocDetl> outPage = manLocDetlService.getOutPage(manLocDetlPage);
//        Page<ManLocDetl> page = manLocDetlService.getPage(manLocDetlPage);
        return R.ok(outPage);
    }
}
src/main/java/com/zy/asrs/controller/NodeController.java
@@ -15,6 +15,8 @@
import com.core.exception.CoolException;
import com.zy.asrs.entity.ManLocDetl;
import com.zy.asrs.entity.Node;
import com.zy.asrs.entity.param.InitPakoutParam;
import com.zy.asrs.entity.param.PakinParam;
import com.zy.asrs.mapper.ManLocDetlMapper;
import com.zy.asrs.service.NodeService;
import com.zy.common.entity.NodeExcel;
@@ -295,4 +297,17 @@
        return R.ok("成功同步"+listener.getTotal()+"个货位");
    }
    /*************************************** 入库出相关 ***********************************************/
    @RequestMapping("/work/stock/pakin")
    @ManagerAuth(memo = "入库")
    public R stockPakin(@RequestBody PakinParam number) {
        return nodeService.stockPakin(number, getUserId(), getHostId());
    }
    @RequestMapping("/work/stock/pakout")
    @ManagerAuth(memo = "生成拣货单")
    public R initPakout(@RequestBody List<InitPakoutParam> params) {
        return nodeService.initPakout(params, getUserId(), getHostId());
    }
}
src/main/java/com/zy/asrs/entity/param/InitPakoutParam.java
New file
@@ -0,0 +1,17 @@
package com.zy.asrs.entity.param;
import lombok.Data;
/**
 * Created by vincent on 2021/3/10
 */
@Data
public class InitPakoutParam {
    private Long nodeId;
    private String matnr;
    private Double count;
}
src/main/java/com/zy/asrs/entity/param/MatnrDto.java
New file
@@ -0,0 +1,15 @@
package com.zy.asrs.entity.param;
import lombok.Data;
/**
 * Created by vincent on 2021/3/31
 */
@Data
public class MatnrDto {
    private String matnr;
    private Double count;
}
src/main/java/com/zy/asrs/entity/param/PakinParam.java
New file
@@ -0,0 +1,19 @@
package com.zy.asrs.entity.param;
import lombok.Data;
import java.util.List;
/**
 * Created by vincent on 2021/3/26
 */
@Data
public class PakinParam {
    private String nodeId;
    private List<MatnrDto> mats;
    private Integer docType;
}
src/main/java/com/zy/asrs/entity/result/Pakin.java
New file
@@ -0,0 +1,331 @@
package com.zy.asrs.entity.result;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import com.baomidou.mybatisplus.annotations.TableField;
import com.baomidou.mybatisplus.annotations.TableName;
import com.core.common.Cools;
import com.core.common.SpringUtils;
import com.zy.system.entity.Host;
import com.zy.system.entity.User;
import com.zy.system.service.HostService;
import com.zy.system.service.UserService;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import java.io.Serializable;
import java.text.SimpleDateFormat;
import java.util.Date;
@Data
@ExcelIgnoreUnannotated
@TableName("man_pakin")
public class Pakin implements Serializable {
    private static final long serialVersionUID = 1L;
    /**
     * 所属项目
     */
    @ApiModelProperty(value= "所属项目")
    @TableField("host_id")
    private Long hostId;
    /**
     * 任务号
     */
    @ApiModelProperty(value= "任务号")
    @TableField("wrk_no")
    private String wrkNo;
    /**
     * 工作状态
     */
    @ApiModelProperty(value= "工作状态")
    @TableField("wrk_sts")
    private Long wrkSts;
    /**
     * 托盘号
     */
    @ApiModelProperty(value= "托盘号")
    private String zpallet;
    /**
     * 入库数量
     */
    @ApiModelProperty(value= "入库数量")
    @ExcelProperty(value = "入库总量")
    private Double anfme;
    /**
     * 关联货位
     */
    @ApiModelProperty(value= "关联货位")
    @TableField("node_id")
    private Long nodeId;
    /**
     * 货位
     */
    @ApiModelProperty(value= "货位")
    @TableField("loc_no")
    private String locNo;
    /**
     * 商品编码
     */
    @ApiModelProperty(value= "商品编码")
    @ExcelProperty(value = "商品编码")
    private String matnr;
    /**
     * 商品名称
     */
    @ApiModelProperty(value= "商品名称")
    @ExcelProperty(value = "商品名称")
    private String maktx;
    /**
     * 名称
     */
    @ApiModelProperty(value= "名称")
    private String name;
    /**
     * 规格
     */
    @ApiModelProperty(value= "规格")
    @ExcelProperty(value = "规格")
    private String specs;
    /**
     * 型号
     */
    @ApiModelProperty(value= "型号")
    private String model;
    /**
     * 批号
     */
    @ApiModelProperty(value= "批号")
    private String batch;
    /**
     * 单位
     */
    @ApiModelProperty(value= "单位")
    @ExcelProperty(value = "单位")
    private String unit;
    /**
     * SKC
     */
    @ApiModelProperty(value= "SKC")
    @ExcelProperty(value = "SKC")
    private String barcode;
    /**
     * 单据类型
     */
    @ApiModelProperty(value= "单据类型")
    @TableField("doc_id")
    private Long docId;
    /**
     * 单据编号
     */
    @ApiModelProperty(value= "单据编号")
    @TableField("doc_num")
    private String docNum;
    /**
     * 客户名称
     */
    @ApiModelProperty(value= "客户名称")
    @TableField("cust_name")
    private String custName;
    /**
     * 品项数
     */
    @ApiModelProperty(value= "品项数")
    @TableField("item_num")
    private Integer itemNum;
    /**
     * 数量
     */
    @ApiModelProperty(value= "数量")
    private Integer count;
    /**
     * 单价
     */
    @ApiModelProperty(value= "单价")
    private Double price;
    /**
     * 重量
     */
    @ApiModelProperty(value= "重量")
    private Double weight;
    /**
     * 状态 1: 正常  0: 禁用
     */
    @ApiModelProperty(value= "状态 1: 正常  0: 禁用  ")
    private Integer status;
    /**
     * 添加人员
     */
    @ApiModelProperty(value= "添加人员")
    @TableField("create_by")
    private Long createBy;
    /**
     * 添加时间
     */
    @ApiModelProperty(value= "添加时间")
    @TableField("create_time")
    private Date createTime;
    /**
     * 修改人员
     */
    @ApiModelProperty(value= "修改人员")
    @TableField("update_by")
    private Long updateBy;
    /**
     * 修改时间
     */
    @ApiModelProperty(value= "修改时间")
    @TableField("update_time")
    private Date updateTime;
    /**
     * 备注
     */
    @ApiModelProperty(value= "备注")
    private String memo;
    public Pakin() {}
    public Pakin(Long hostId, String wrkNo, Long wrkSts, String zpallet, Double anfme, Long nodeId, String locNo, String matnr, String maktx, String name, String specs, String model, String batch, String unit, String barcode, Long docId, String docNum, String custName, Integer itemNum, Integer count, Double weight, Integer status, Long createBy, Date createTime, Long updateBy, Date updateTime, String memo) {
        this.hostId = hostId;
        this.wrkNo = wrkNo;
        this.wrkSts = wrkSts;
        this.zpallet = zpallet;
        this.anfme = anfme;
        this.nodeId = nodeId;
        this.locNo = locNo;
        this.matnr = matnr;
        this.maktx = maktx;
        this.name = name;
        this.specs = specs;
        this.model = model;
        this.batch = batch;
        this.unit = unit;
        this.barcode = barcode;
        this.docId = docId;
        this.docNum = docNum;
        this.custName = custName;
        this.itemNum = itemNum;
        this.count = count;
        this.weight = weight;
        this.status = status;
        this.createBy = createBy;
        this.createTime = createTime;
        this.updateBy = updateBy;
        this.updateTime = updateTime;
        this.memo = memo;
    }
//    Pakin pakin = new Pakin(
//            null,    // 任务号[非空]
//            null,    // 工作状态
//            null,    // 托盘号
//            null,    // 入库数量
//            null,    // 关联货位[非空]
//            null,    // 货位[非空]
//            null,    // 商品编码[非空]
//            null,    // 商品名称
//            null,    // 名称
//            null,    // 规格
//            null,    // 型号
//            null,    // 批号
//            null,    // 单位
//            null,    // SKC
//            null,    // 单据类型
//            null,    // 单据编号
//            null,    // 客户名称
//            null,    // 品项数
//            null,    // 数量
//            null,    // 重量
//            null,    // 状态
//            null,    // 添加人员
//            null,    // 添加时间
//            null,    // 修改人员
//            null,    // 修改时间
//            null    // 备注
//    );
    public String getHostId$(){
        HostService service = SpringUtils.getBean(HostService.class);
        Host host = service.selectById(this.hostId);
        if (!Cools.isEmpty(host)){
            return String.valueOf(host.getName());
        }
        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.getNickname());
        }
        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.getNickname());
        }
        return null;
    }
    public String getUpdateTime$(){
        if (Cools.isEmpty(this.updateTime)){
            return "";
        }
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(this.updateTime);
    }
}
src/main/java/com/zy/asrs/mapper/ManLocDetlMapper.java
@@ -75,4 +75,8 @@
    int deleteLocNo0(String locNo, String matnr);
    int updateAnfme0(double anfme, Long nodeId);
    List<ManLocDetl> listByOutPage(Map<String, Object> condition);
    long listByOutPageCount(Map<String, Object> condition);
}
src/main/java/com/zy/asrs/service/ManLocDetlService.java
@@ -53,4 +53,9 @@
    List<ManLocDetl> unreason();
    Double getLocDetlSumQty(String locNo);
    Page<ManLocDetl> getOutPage(Page<ManLocDetl> manLocDetlPage);
}
src/main/java/com/zy/asrs/service/NodeService.java
@@ -1,7 +1,12 @@
package com.zy.asrs.service;
import com.baomidou.mybatisplus.service.IService;
import com.core.common.R;
import com.zy.asrs.entity.Node;
import com.zy.asrs.entity.param.InitPakoutParam;
import com.zy.asrs.entity.param.PakinParam;
import java.util.List;
public interface NodeService extends IService<Node> {
@@ -14,4 +19,8 @@
        Node selectByUuid(String uuid, Long hostId, Integer type);
        Node selectByUuid(String uuid, Long hostId, Integer type, Long parentId);
    R stockPakin(PakinParam number, Long userId, Long hostId);
        R initPakout(List<InitPakoutParam> params, Long userId, Long hostId);
}
src/main/java/com/zy/asrs/service/impl/ManLocDetlServiceImpl.java
@@ -9,6 +9,7 @@
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Set;
@Service("manLocDetlService")
@@ -18,7 +19,9 @@
        @Override
        public Page<ManLocDetl> getPage(Page<ManLocDetl> page) {
            page.setRecords(baseMapper.listByPage(page.getCondition()));
            Map<String, Object> condition = page.getCondition();
            List<ManLocDetl> manLocDetls = baseMapper.listByPage(condition);
            page.setRecords(manLocDetls);
            page.setTotal(baseMapper.listByPageCount(page.getCondition()));
            return page;
        }
@@ -119,4 +122,13 @@
            return this.baseMapper.selectLocDetlSumQty(locNo);
        }
    @Override
    public Page<ManLocDetl> getOutPage(Page<ManLocDetl> manLocDetlPage) {
        Map<String, Object> condition = manLocDetlPage.getCondition();
        List<ManLocDetl> manLocDetls = baseMapper.listByOutPage(condition);
        manLocDetlPage.setRecords(manLocDetls);
        manLocDetlPage.setTotal(baseMapper.listByOutPageCount(manLocDetlPage.getCondition()));
        return manLocDetlPage;
    }
}
src/main/java/com/zy/asrs/service/impl/NodeServiceImpl.java
@@ -2,16 +2,40 @@
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.service.impl.ServiceImpl;
import com.core.common.Cools;
import com.core.common.R;
import com.core.common.SnowflakeIdWorker;
import com.core.exception.CoolException;
import com.zy.asrs.entity.ManLocDetl;
import com.zy.asrs.entity.Mat;
import com.zy.asrs.entity.Node;
import com.zy.asrs.entity.param.InitPakoutParam;
import com.zy.asrs.entity.param.MatnrDto;
import com.zy.asrs.entity.param.PakinParam;
import com.zy.asrs.entity.result.Pakin;
import com.zy.asrs.mapper.NodeMapper;
import com.zy.asrs.service.ManLocDetlService;
import com.zy.asrs.service.MatService;
import com.zy.asrs.service.NodeService;
import com.zy.asrs.utils.VersionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.beans.Transient;
import java.util.Date;
import java.util.List;
@Service("nodeService")
public class NodeServiceImpl extends ServiceImpl<NodeMapper, Node> implements NodeService {
    @Autowired
    private NodeService nodeService;
    @Autowired
    private MatService matService;
    @Autowired
    private SnowflakeIdWorker snowflakeIdWorker;
    @Autowired
    private ManLocDetlService manLocDetlService;
    @Override
    public Node getTop() {
        Node top = this.selectOne(new EntityWrapper<Node>().eq("type", 0).eq("level", 0));
@@ -52,4 +76,72 @@
    public Node selectByUuid(String uuid, Long hostId, Integer type, Long parentId) {
        return selectOne(new EntityWrapper<Node>().eq("host_id", hostId).eq("uuid", uuid).eq("type", type).eq("parent_id", parentId));
    }
    @Override
    public R stockPakin(PakinParam param, Long userId, Long hostId) {
        Node node = nodeService.selectByUuid(param.getNodeId(), hostId);
        if (node == null) {
            node = nodeService.selectById(param.getNodeId());
        }
        if (node == null) {
            return R.error("货位不存在");
        }
        if (Cools.isEmpty(param.getMats())) {
            return R.error("入库物料不能为空");
        }
        Date now = new Date();
        for (MatnrDto dto : param.getMats()) {
            Mat mat = matService.selectByMatnr(dto.getMatnr());
            if (mat == null) {
                throw new CoolException("物料数据错误,请联系管理员");
            }
            ManLocDetl manLocDetl = new ManLocDetl();
            manLocDetl.setLocNo(node.getUuid());
            manLocDetl.setNodeId(node.getId());
            manLocDetl.setZpallet(mat.getBarcode());
            manLocDetl.setAnfme(dto.getCount());
            manLocDetl.setMatnr(mat.getMatnr());
            manLocDetl.setMaktx(mat.getMaktx());
            manLocDetl.setName(mat.getName());
            manLocDetl.setSpecs(mat.getSpecs());
            manLocDetl.setModel(mat.getModel());
            manLocDetl.setBatch(mat.getBeBatch() + "");
            manLocDetl.setCreateTime(now);
            manLocDetl.setModiTime(now);
            manLocDetl.setCreateBy(userId);
            manLocDetlService.insert(manLocDetl);
        }
        return R.ok("入库成功");
    }
    @Transactional
    @Override
    public R initPakout(List<InitPakoutParam> params, Long userId, Long hostId) {
        if (!Cools.isEmpty(params)) {
            Date now = new Date();
            for (InitPakoutParam param : params) {
                ManLocDetl manLocDetl = manLocDetlService.selectOne(new EntityWrapper<ManLocDetl>()
                        .eq("node_id", param.getNodeId())
                        .eq("matnr", param.getMatnr()));
                Node node = nodeService.selectOne(new EntityWrapper<Node>()
                        .eq("id", param.getNodeId()));
                if (node == null) {
                    return R.error("找不到该库位,请联系管理员:" + param.getNodeId() );
                }
                if (manLocDetl == null) {
                    return R.error("物料:"+ param.getMatnr() + " 在库位中不存在");
                }
                if (manLocDetl.getAnfme() - param.getCount() < 0) {
                    return R.error("物料:"+ param.getMatnr() + " 在库位中数量不足");
                }else {
                    manLocDetl.setAnfme(manLocDetl.getAnfme() - param.getCount());
                    manLocDetlService.update(manLocDetl,new EntityWrapper<ManLocDetl>()
                            .eq("loc_no",node.getUuid())
                            .eq("matnr",param.getMatnr()));
                }
            }
        }
        return R.ok("出库成功");
    }
}
src/main/java/com/zy/asrs/utils/VersionUtils.java
@@ -1,6 +1,8 @@
package com.zy.asrs.utils;
import com.zy.asrs.entity.LocMast;
import com.zy.asrs.entity.Mat;
import com.zy.asrs.entity.result.Pakin;
import com.zy.common.model.LocTypeDto;
/**
@@ -11,7 +13,7 @@
    // 业务 ----------------------------------------------------------------------
//    public static void setWrkDetl(WrkDetl wrkDetl, Mat mat) {
    //    public static void setWrkDetl(WrkDetl wrkDetl, Mat mat) {
//        wrkDetl.setMatnr(matCode.getMatNo()); // 物料编号
//        wrkDetl.setMaktx(matCode.getMatName()); // 物料描述
//        wrkDetl.setLgnum(matCode.getStr2()); // 规格
@@ -110,12 +112,24 @@
//        wrkDetl.setSupplier(orderDetl.getSupplier()); // 序列码
//        wrkDetl.setAltme(orderDetl.getUnit()); // 单位
//    }
    public static void setPakin(Pakin pakin, Mat mat) {
        pakin.setMatnr(mat.getMatnr());
        pakin.setMaktx(mat.getMaktx());
        pakin.setName(mat.getName());
        pakin.setSpecs(mat.getSpecs());
        pakin.setModel(mat.getModel());
        pakin.setUnit(mat.getUnit());
        pakin.setBarcode(mat.getBarcode());
        pakin.setItemNum(Integer.valueOf(mat.getItemNum()));
        pakin.setPrice(mat.getPrice());
        pakin.setWeight(mat.getWeight());
    }
    /**
     *  库位移转时类型检测
     * 库位移转时类型检测
     **/
    public static boolean locMoveCheckLocType(LocMast loc, LocTypeDto dto){
    public static boolean locMoveCheckLocType(LocMast loc, LocTypeDto dto) {
        // 如果源库位是高库位,目标库位是低库位
        if (dto.getLocType1() == 2 && loc.getLocType1() == 1) {
            return false;
src/main/resources/application.yml
@@ -26,7 +26,7 @@
      maxRequestSize: 100MB
mybatis-plus:
  mapper-locations: classpath:mapper/*.xml
  mapper-locations: classpath:mapper/*.xml
#  global-config:
#    field-strategy: 0
#  configuration:
src/main/resources/mapper/ManLocDetlMapper.xml
@@ -62,8 +62,8 @@
        LEFT JOIN man_mat mm ON mld.matnr = mm.matnr
        LEFT JOIN man_tag mt ON mm.tag_id = mt.id
        WHERE 1=1
        AND (CHARINDEX(','+#{node_id}+',', ','+mn.path+',') > 0 OR mn.id = #{node_id})
        AND (CHARINDEX(','+#{tag_id}+',', ','+mt.path+',') > 0 OR mt.id = #{tag_id})
         AND (CHARINDEX(','+#{node_id}+',', ','+mn.path+',') > 0 OR mn.id = #{node_id})
         AND (CHARINDEX(','+#{tag_id}+',', ','+mt.path+',') > 0 OR mt.id = #{tag_id})
        <include refid="locDetlCondition"></include>
        ) t where t.row between ((#{pageNumber}-1)*#{pageSize}+1) and (#{pageNumber}*#{pageSize})
    </select>
@@ -230,6 +230,31 @@
        and matnr = #{matnr}
    </select>
    <select id="listByOutPage" resultMap="BaseResultMap">
        select * from
        (
        SELECT
        ROW_NUMBER() over (order by mld.create_time desc) as row,
        mld.*
        FROM man_loc_detl mld
        LEFT JOIN man_node mn ON mld.node_id = mn.id
        LEFT JOIN man_mat mm ON mld.matnr = mm.matnr
        LEFT JOIN man_tag mt ON mm.tag_id = mt.id
        WHERE 1=1
        <include refid="locDetlCondition"></include>
        ) t where t.row between ((#{pageNumber}-1)*#{pageSize}+1) and (#{pageNumber}*#{pageSize})
    </select>
    <select id="listByOutPageCount" resultType="java.lang.Long">
        select
        count(1)
        FROM man_loc_detl mld
        LEFT JOIN man_node mn ON mld.node_id = mn.id
        LEFT JOIN man_mat mm ON mld.matnr = mm.matnr
        LEFT JOIN man_tag mt ON mm.tag_id = mt.id
        WHERE 1=1
        <include refid="locDetlCondition"></include>
    </select>
    <update id="updateLocNo0">
        update man_loc_detl set loc_no = #{locNo}
src/main/resources/mapper/NodeMapper.xml
New file
@@ -0,0 +1,34 @@
<?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.NodeMapper">
    <!-- 通用查询映射结果 -->
    <resultMap id="BaseResultMap" type="com.zy.asrs.entity.Node">
        <id column="id" property="id" />
        <result column="host_id" property="hostId" />
        <result column="uuid" property="uuid" />
        <result column="name" property="name" />
        <result column="parent_id" property="parentId" />
        <result column="parent_name" property="parentName" />
        <result column="type" property="type" />
        <result column="path" property="path" />
        <result column="name_path" property="namePath" />
        <result column="level" property="level" />
        <result column="leading" property="leading" />
        <result column="sort" property="sort" />
        <result column="barcode" property="barcode" />
        <result column="major" property="major" />
        <result column="status" property="status" />
        <result column="create_time" property="createTime" />
        <result column="create_by" property="createBy" />
        <result column="update_time" property="updateTime" />
        <result column="update_by" property="updateBy" />
        <result column="memo" property="memo" />
    </resultMap>
    <select id="selectByUuid" resultMap="BaseResultMap">
        select * from man_node where 1=1 and uuid=#{uuid} and host_id = #{hostId} and status = 1
    </select>
</mapper>
src/main/webapp/static/js/common.js
@@ -224,7 +224,7 @@
var detlCols = [
    {field: 'matnr', align: 'center',title: '商品编号', sort:true}
    ,{field: 'maktx', align: 'center',title: '商品名称', sort:true}
    ,{field: 'orderNo', align: 'center',title: '单据编号', hide: false}
    ,{field: 'orderNo', align: 'center',title: '单据编号', hide: true}
    ,{field: 'batch', align: 'center',title: '批号', sort:true}
    ,{field: 'anfme', align: 'center',title: '数量'}
    ,{field: 'zpallet', align: 'center',title: '托盘条码'}
src/main/webapp/static/js/ioWorks/matQuery.js
New file
@@ -0,0 +1,397 @@
var matData = [];
var cstmrVal;
var itemVal;
function getCol() {
    var cols = [
        {field: 'count', align: 'center',title: '出库数量', edit:'text', width: 130,  style:'color: blue;font-weight: bold'}
    ];
    arrRemove(matCols,  'field', 'anfme');
    cols.push.apply(cols, matCols);
    cols.push(
            {field: 'stock', align: 'center',title: '库存余量', style: 'font-weight: bold'},
            {fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width:65}
        )
    return cols;
}
layui.config({
    base: baseUrl + "/static/layui/lay/modules/"
}).extend({
    notice: 'notice/notice',
}).use(['table','laydate', 'form', 'admin', 'notice', 'xmSelect'], function() {
    var table = layui.table;
    var $ = layui.jquery;
    var layer = layui.layer;
    var form = layui.form;
    var notice = layui.notice;
    var layDate = layui.laydate;
    var admin = layui.admin;
    var xmSelect = layui.xmSelect;
    tableIns = table.render({
        elem: '#chooseData',
        headers: {token: localStorage.getItem('token')},
        data: [],
        limit: 100,
        even: true,
        toolbar: '#toolbar',
        cellMinWidth: 50,
        cols: [getCol()],
        done: function(res, curr, count) {
            limit();
        }
    });
    // 页面修改
    table.on('edit(chooseData)', function (obj) {
        updateMatData(obj.data.locNo, obj.data.matnr, Number(obj.value));
    });
    // 监听头工具栏事件
    table.on('toolbar(chooseData)', function (obj) {
        var data = matData;
        switch (obj.event) {
            case 'createDoc':
                if (data.length === 0){
                    notice.error({
                        title: '消息通知',
                        message: '请添加物料'
                    });
                } else {
                    var success = true;
                    for (var i=0;i<matData.length;i++) {
                        if (matData[i].count <= 0) {
                            notice.error({
                                title: '消息通知',
                                message: matData[i].matnr + '物料数量必须大于零!'
                            });
                            success = false;
                            return false;
                        }
                    }
                    var index = layer.load(1, {shade: [0.1,'#000']});
                    // 单据类型
                    var docTypeData;
                    $.ajax({
                        url: baseUrl+"/work/docType/all/get",
                        headers: {'token': localStorage.getItem('token')},
                        method: 'POST',
                        async: false,
                        success: function (res) {
                            if (res.code === 200){
                                docTypeData = res;
                            } else {
                                layer.msg(res.msg, {icon: 2})
                            }
                        }
                    });
                    var tpl1 = $('#docTypeSelectTpl').html();
                    var template1 = Handlebars.compile(tpl1);
                    var html1 = template1(docTypeData);
                    $("#docType").html(html1);
                    // 客户
                    var cstmrData;
                    // $.ajax({
                    //     url: baseUrl+"/work/cstmr/all/get",
                    //     headers: {'token': localStorage.getItem('token')},
                    //     method: 'POST',
                    //     async: false,
                    //     success: function (res) {
                    //         if (res.code === 200){
                    //             cstmrData = res;
                    //         } else {
                    //             layer.msg(res.msg, {icon: 2})
                    //         }
                    //     }
                    // });
                    // var tpl2 = $('#cstmrSelectTpl').html();
                    // var template2 = Handlebars.compile(tpl2);
                    // var html2 = template2(cstmrData);
                    // $("#cstmr").html(html2);
                    // 单选
                    $.ajax({
                        url: baseUrl+"/work/cstmr/all/get/kv",
                        headers: {'token': localStorage.getItem('token')},
                        method: 'POST',
                        async: false,
                        success: function (res) {
                            if (res.code === 200){
                                cstmrData = res.data;
                            } else {
                                layer.msg(res.msg, {icon: 2})
                            }
                        }
                    });
                    cstmrVal = xmSelect.render({
                        el: '#cstmr',
                        radio: true,
                        clickClose: true,
                        filterable: true,
                        create: function(val, arr){
                            if(arr.length === 0){
                                return {
                                    name:  val,
                                    value: val
                                }
                            }
                        },
                        model: {
                            icon: 'hidden',
                            label: {
                                type: 'text',
                            }
                        },
                        data: cstmrData
                    })
                    // 项目
                    var itemData;
                    // $.ajax({
                    //     url: baseUrl+"/work/item/all/get",
                    //     headers: {'token': localStorage.getItem('token')},
                    //     method: 'POST',
                    //     async: false,
                    //     success: function (res) {
                    //         if (res.code === 200){
                    //             itemData = res;
                    //         } else {
                    //             layer.msg(res.msg, {icon: 2});
                    //         }
                    //     }
                    // });
                    // var tpl3 = $('#itemSelectTpl').html();
                    // var template3 = Handlebars.compile(tpl3);
                    // var html3 = template3(itemData);
                    // $("#item").html(html3);
                    $.ajax({
                        url: baseUrl+"/work/item/all/get/kv",
                        headers: {'token': localStorage.getItem('token')},
                        method: 'POST',
                        async: false,
                        success: function (res) {
                            if (res.code === 200){
                                itemData = res.data;
                            } else {
                                layer.msg(res.msg, {icon: 2});
                            }
                        }
                    });
                    itemVal = xmSelect.render({
                        el: '#item',
                        radio: true,
                        clickClose: true,
                        filterable: true,
                        create: function(val, arr){
                            if(arr.length === 0){
                                return {
                                    name:  val,
                                    value: val
                                }
                            }
                        },
                        model: {
                            icon: 'hidden',
                            label: {
                                type: 'text',
                            }
                        },
                        data: itemData
                    })
                    // 弹窗
                    layer.close(index);
                    if (success) {
                        admin.open({
                            type: 1,
                            title: '单据填充',
                            offset: '100px',
                            area: ['360px'],
                            shade: 0.3,
                            content: $('#getOrderNo'),
                            success: function(layero, index){
                                layer.iframeAuto(index);
                                $(layero).children('.layui-layer-content').css('overflow', 'visible');
                                layui.form.render('select');
                            },
                            cancel: function () {
                                $('#orderNo').val('');
                            }
                        });
                    }
                }
                break;
        }
    });
    // // 多选
    // var demo1 = xmSelect.render({
    //     el: '#demo1',
    //     filterable: true,
    //     create: function(val, arr){
    //         if(arr.length === 0){
    //             return {
    //                 name:  val,
    //                 value: val
    //             }
    //         }
    //     },
    //     data: [
    //         {name: '张三', value: 1, selected: true},
    //         {name: '李四', value: 2},
    //         {name: '王五', value: 3, disabled: true},
    //     ]
    // })
    // 监听行工具事件
    table.on('tool(chooseData)', function(obj){
        var data = obj.data;
        switch (obj.event) {
            case 'remove':
                for (var i = matData.length - 1; i >= 0; i--) {
                    if (matData[i].matnr === data.matnr) {
                        matData.splice(i, 1);
                    }
                }
                tableIns.reload({data: matData,done:function (res) {
                    limit();
                }});
                break;
        }
    });
    // 开始生成拣货单
    form.on('submit(confirm)', function (data) {
        var matDetls = [];
        matData.forEach(function(elem) {
            matDetls.push({
                matnr: elem.matnr
                , count: elem.count
            });
        });
        var req = JSON.stringify({
            docType: data.field.docType
            , orderNo: data.field.orderNo
            , orderTime: data.field.orderTime
            , item: itemVal.getValue()[0] ? itemVal.getValue()[0].name : null
            , cstmr: cstmrVal.getValue()[0] ? cstmrVal.getValue()[0].name : null
            , list: matDetls
        })
        $.ajax({
            url: baseUrl+"/work/order/init",
            headers: {'token': localStorage.getItem('token')},
            data: req,
            contentType:'application/json;charset=UTF-8',
            method: 'POST',
            success: function (res) {
                if (res.code === 200){
                    notice.success({
                        title: '消息通知',
                        message: res.msg
                    });
                    top.layui.layer.close(top.popupRight);
                } else if (res.code === 403){
                    top.location.href = baseUrl+"/";
                } else {
                    notice.error({
                        title: '消息通知',
                        message: res.msg
                    });
                }
            }
        });
    })
    function updateMatData(locNo, matnr, count) {
        if (isNaN(count)) {
            notice.error({
                title: '消息通知',
                message: '请输入数字'
            });
        } else {
            if (count > 0) {
                for (var i=0;i<matData.length;i++){
                    if (matData[i]["matnr"] === matnr){
                        matData[i]["count"] = count;
                        break;
                    }
                }
            } else {
                notice.error({
                    title: '消息通知',
                    message: '数量必须大于零'
                });
            }
        }
        tableIns.reload({data: matData,done:function (res) {
            limit();
        }});
    }
    layDate.render({
        elem: '#orderTime',
        trigger: 'click',
        type: 'date'
    });
})
// 提取物料
var matDetlLayerIdx;
function getMatDetl() {
    matDetlLayerIdx = layer.open({
        type: 2,
        title: '提取出库物料',
        maxmin: true,
        area: [top.detailWidth, top.detailHeight],
        shadeClose: true,
        content: 'matQueryBox.html',
        success: function(layero, index){
        }
    });
}
// 添加表格数据
function addTableData(data) {
    for (var i=0;i<data.length;i++){
        let pass = false;
        for (var j=0;j<matData.length;j++){
            if (data[i].matnr === matData[j].matnr) {
                pass = true;
                break;
            }
        }
        if (pass) {
            data.splice(i--, 1);
        } else {
            data[i]["count"] = 0;
        }
    }
    matData.push.apply(matData, data);
    tableIns.reload({data: matData});
    layer.close(matDetlLayerIdx);
}
function initOrderNo() {
    $.ajax({
        url: baseUrl+"/work/orderNo/init",
        headers: {'token': localStorage.getItem('token')},
        async: false,
        method: 'GET',
        success: function (res) {
            if (res.code === 200){
                $('#orderNo').val(res.data)
            } else if (res.code === 403){
                top.location.href = baseUrl+"/";
            } else {
                notice.error({
                    title: '消息通知',
                    message: res.msg
                });
            }
        }
    });
}
src/main/webapp/static/js/ioWorks/stockIn.js
New file
@@ -0,0 +1,274 @@
var initCountVal = 0;
var matCodeData = [];
function getCol() {
    var cols = [
        {fixed: 'left', field: 'count', title: '数量(必填)', align: 'center', edit:'text', width: 120,  style:'color: blue;font-weight: bold'}
    ];
    cols.push.apply(cols, matCols);
    cols.push({fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width:80})
    return cols;
}
layui.config({
    base: baseUrl + "/static/layui/lay/modules/"
}).use(['table','laydate', 'form', 'admin', 'xmSelect', 'treeTable'], function() {
    var table = layui.table;
    var $ = layui.jquery;
    var layer = layui.layer;
    var layDate = layui.laydate;
    var form = layui.form;
    var admin = layui.admin;
    var xmSelect = layui.xmSelect;
    var treeTable = layui.treeTable;
    tableIns = table.render({
        elem: '#chooseData',
        data: [],
        even: true,
        limit: 500,
        cellMinWidth: 50,
        toolbar: '#toolbar',
        cols: [getCol()],
        done: function (res, curr, count) {
            $('td[data-field=count] div').html(initCountVal);
            setMatCodeData(res.data);
            limit();
        }
    });
    // 页面修改
    table.on('edit(chooseData)', function (obj) {
        updateMatCodeData(obj.data.matnr, Number(obj.value));
    });
    // 监听头工具栏事件
    table.on('toolbar(chooseData)', function (obj) {
        var checkStatus = table.checkStatus(obj.config.id);
        var data = checkStatus.data;
        switch(obj.event) {
            case 'confirm':
                // 判断是否存在物料
                if (matCodeData.length === 0) {
                    layer.msg("请先添加物料");
                    return;
                }
                // 判断物料数量是否存在异常
                for (var i=0;i<matCodeData.length;i++){
                    if (isNaN(matCodeData[i].count)) {
                        layer.msg("请输入数字");
                        return;
                    }
                    if (matCodeData[i].count === 0){
                        layer.msg("数量不能为零");
                        return;
                    }
                }
                showNodeSelect();
                // $.ajax({
                //     url: baseUrl+"/full/store/put/start",
                //     headers: {'token': localStorage.getItem('token')},
                //     data: JSON.stringify({
                //         devpNo: Number($('#putSiteSelect').val()),
                //         list: matCodeData
                //     }),
                //     contentType:'application/json;charset=UTF-8',
                //     method: 'POST',
                //     async: false,
                //     success: function (res) {
                //         if (res.code === 200){
                //             layer.msg("入库启动成功,目标库位:" + res.data);
                //             matCodeData = [];
                //             tableIns.reload({data: matCodeData,done:function (res) { limit();}});
                //         } else if (res.code === 403){
                //             top.location.href = baseUrl+"/";
                //         }else {
                //             layer.msg(res.msg)
                //         }
                //     }
                // })
                // break;
        }
    });
    // 监听行工具事件
    table.on('tool(chooseData)', function(obj){
        var data = obj.data;
        switch (obj.event) {
            case 'remove':
                for (var i = matCodeData.length - 1; i >= 0; i--) {
                    if (matCodeData[i].matnr === data.matnr) {
                        matCodeData.splice(i, 1);
                    }
                }
                tableIns.reload({data: matCodeData,done:function (res) {
                        limit();
                        // 覆盖render方法的done
                    }});
                break;
        }
    });
    function setMatCodeData(data) {
        matCodeData = data;
        for (var i=0;i<matCodeData.length;i++){
            matCodeData[i]["count"] = initCountVal;
        }
    }
    function updateMatCodeData(matnr, count) {
        if (isNaN(count)) {
            layer.msg("请输入数字");
        } else {
            if (count > 0) {
                for (var i=0;i<matCodeData.length;i++){
                    if (matCodeData[i]["matnr"] === matnr){
                        matCodeData[i]["count"] = count;
                    }
                }
            } else {
                layer.msg("数量必须大于零");
            }
        }
        tableIns.reload({data: matCodeData,done:function (res) {
                limit();
                // 覆盖render方法的done
            }});
    }
    /* 显示表单弹窗 */
    function showNodeSelect() {
        admin.open({
            type: 1,
            area: '400px',
            title: '选择入库货位',
            content: $('#nodeSelect').html(),
            success: function (layero, dIndex) {
                // 表单提交事件
                form.on('submit(pakin)', function (data) {
                    data.field.nodeSel = insXmSel.getValue('valueStr');
                    var loadIndex = layer.load(2);
                    $.ajax({
                        url: baseUrl+"/work/stock/pakin",
                        headers: {'token': localStorage.getItem('token')},
                        data: JSON.stringify({
                            nodeId: data.field.nodeSel,
                            mats: matCodeData
                        }),
                        contentType:'application/json;charset=UTF-8',
                        method: 'POST',
                        success: function (res) {
                            layer.close(loadIndex);
                            if (res.code === 200){
                                layer.close(dIndex);
                                matCodeData = [];
                                tableIns.reload({data: matCodeData});
                                limit();
                                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 insXmSel = xmSelect.render({
                    el: '#nodeSel',
                    height: '250px',
                    data: insTb.options.data,
                    initValue: [],
                    model: {label: {type: 'text'}},
                    prop: {
                        name: 'name',
                        value: 'id'
                    },
                    radio: true,
                    clickClose: true,
                    tree: {
                        show: true,
                        indent: 15,
                        strict: false,
                        expandedKeys: true
                    }
                });
                // 弹窗不出现滚动条
                $(layero).children('.layui-layer-content').css('overflow', 'visible');
                layui.form.render('select');
            }
        });
    }
    var insTb = treeTable.render({
        elem: '#node',
        url: baseUrl+'/node/tree/auth',
        headers: {token: localStorage.getItem('token')},
        height: 'full-200',
        tree: {
            iconIndex: 2,           // 折叠图标显示在第几列
            isPidData: true,        // 是否是id、pid形式数据
            idName: 'id',           // id字段名称
            pidName: 'parentId'     // pid字段名称
        },
        cols: [[
            {type: 'checkbox'}
            ,{type: 'numbers'}
            ,{field: 'name', align: 'left',title: '名称', minWidth: 150}
            ,{field: 'type$', align: 'center',title: '类型'}
            ,{field: 'leading', align: 'center',title: '负责人'}
            ,{field: 'sort', align: 'center',title: '排序', hide: true}
            ,{field: 'status$', align: 'center',title: '状态'}
            ,{field: 'updateTime$', align: 'center',title: '修改时间'}
            ,{field: 'updateBy$', align: 'center',title: '修改人员', hide: true}
            ,{field: 'memo', align: 'center',title: '备注', hide: true}
            ,{fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width:150}
        ]],
        done: function (data) {
            $('.ew-tree-table-box').css('height', '100%');
            insTb.expandAll();
        }
    });
});
// 提取物料
var matCodeLayerIdx;
function getMat() {
    matCodeLayerIdx = layer.open({
        type: 2,
        title: '提取物料',
        maxmin: true,
        area: [top.detailWidth, top.detailHeight],
        shadeClose: true,
        content: 'matQuery.html',
        success: function(layero, index){
        }
    });
}
// 添加表格数据
function addTableData(data) {
    for (var i=0;i<data.length;i++){
        let pass = false;
        for (var j=0;j<matCodeData.length;j++){
            if (data[i].matnr === matCodeData[j].matnr) {
                pass = true;
                break;
            }
        }
        if (pass) {
            data.splice(i--, 1);
        } else {
            data[i]["count"] = initCountVal;
        }
    }
    matCodeData.push.apply(matCodeData, data);
    tableIns.reload({data: matCodeData});
    layer.close(matCodeLayerIdx);
}
src/main/webapp/static/js/ioWorks/stockOut.js
New file
@@ -0,0 +1,180 @@
var locDetlData = [];
function getCol() {
    var cols = [
        {field: 'count', align: 'center',title: '出库数量', edit:'text', width: 130,  style:'color: blue;font-weight: bold'}
        ,{field: 'anfme', align: 'center',title: '原数量'}
        ,{field: 'locNo', align: 'center',title: '库位号'}
    ];
    arrRemove(detlCols,  'field', 'anfme');
    cols.push.apply(cols, detlCols);
    cols.push({fixed: 'right', title:'操作', align: 'center', toolbar: '#operate', width:80})
    return cols;
}
layui.use(['table','laydate', 'form'], function() {
    var table = layui.table;
    var $ = layui.jquery;
    var layer = layui.layer;
    var form = layui.form;
    tableIns = table.render({
        elem: '#chooseData',
        headers: {token: localStorage.getItem('token')},
        data: [],
        even: true,
        toolbar: '#toolbar',
        cellMinWidth: 50,
        cols: [getCol()],
        done: function(res, curr, count) {
            limit();
            // getOutBound();
        }
    });
    // 页面修改
    table.on('edit(chooseData)', function (obj) {
        updateLocDetlData(obj.data.locNo, obj.data.matnr, Number(obj.value));
    });
    // 监听头工具栏事件
    table.on('toolbar(chooseData)', function (obj) {
        var data = locDetlData;
        switch (obj.event) {
            case 'outbound':
                if (data.length === 0){
                    layer.msg('请先添加库位物料');
                } else {
                    var locDetls = [];
                    data.forEach(function(elem) {
                        locDetls.push({nodeId: elem.nodeId, matnr: elem.matnr, count: elem.count});
                    });
                    $.ajax({
                        url: baseUrl+"/work/stock/pakout",
                        headers: {'token': localStorage.getItem('token')},
                        data: JSON.stringify(locDetls),
                        contentType:'application/json;charset=UTF-8',
                        method: 'POST',
                        success: function (res) {
                            if (res.code === 200){
                                locDetlData = [];
                                tableIns.reload({data: locDetlData,done:function (res) {
                                    limit();
                                    // getOutBound();
                                }});
                                layer.msg(res.msg, {icon: 1});
                            } else if (res.code === 403){
                                top.location.href = baseUrl+"/";
                            } else {
                                layer.msg(res.msg)
                            }
                        }
                    });
                }
                break;
        }
    });
    // 监听行工具事件
    table.on('tool(chooseData)', function(obj){
        var data = obj.data;
        switch (obj.event) {
            case 'remove':
                for (var i = locDetlData.length - 1; i >= 0; i--) {
                    if (locDetlData[i].locNo === data.locNo && locDetlData[i].matnr === data.matnr) {
                        locDetlData.splice(i, 1);
                    }
                }
                tableIns.reload({data: locDetlData,done:function (res) {
                    limit();
                    // getOutBound();
                }});
                break;
        }
    });
    function updateLocDetlData(locNo, matnr, count) {
        if (isNaN(count)) {
            layer.msg("请输入数字");
        } else {
            if (count > 0) {
                for (var i=0;i<locDetlData.length;i++){
                    if (locDetlData[i]["locNo"] === locNo && locDetlData[i]["matnr"] === matnr){
                        if (count > locDetlData[i]["anfme"]) {
                            layer.msg("不能超过原数量");
                        } else {
                            locDetlData[i]["count"] = count;
                        }
                        break;
                    }
                }
            } else {
                layer.msg("数量必须大于零");
            }
        }
        tableIns.reload({data: locDetlData,done:function (res) {
            limit();
            // getOutBound();
        }});
    }
    // 获取出库口
    function getOutBound(){
        $.ajax({
            url: baseUrl+"/available/take/site",
            headers: {'token': localStorage.getItem('token')},
            method: 'POST',
            async: false,
            success: function (res) {
                if (res.code === 200){
                    var tpl = $("#takeSiteSelectTemplate").html();
                    var template = Handlebars.compile(tpl);
                    var html = template(res);
                    $('#staNoSelect').append(html);
                    form.render('select');
                } else if (res.code === 403){
                    top.location.href = baseUrl+"/";
                }else {
                    layer.msg(res.msg)
                }
            }
        })
    }
})
// 提取物料
var locDetlLayerIdx;
function getLocDetl() {
    locDetlLayerIdx = layer.open({
        type: 2,
        title: '提取出货内容',
        maxmin: true,
        area: [top.detailWidth, top.detailHeight],
        shadeClose: true,
        content: 'locDetlQuery.html',
        success: function(layero, index){
        }
    });
}
// 添加表格数据
function addTableData(data) {
    for (var i=0;i<data.length;i++){
        let pass = false;
        for (var j=0;j<locDetlData.length;j++){
            if (data[i].matnr === locDetlData[j].matnr && data[i].locNo === locDetlData[j].locNo) {
                pass = true;
                break;
            }
        }
        if (pass) {
            data.splice(i--, 1);
        } else {
            data[i]["count"] = data[i]["anfme"];
        }
    }
    locDetlData.push.apply(locDetlData, data);
    tableIns.reload({data: locDetlData});
    layer.close(locDetlLayerIdx);
}
src/main/webapp/views/ioWorks/locDetlQuery.html
New file
@@ -0,0 +1,228 @@
<!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/common.css" media="all">
    <style>
        body {
            padding: 0 20px;
        }
        .layui-table-box {
            border-right: 1px solid #9F9F9F;
            border-left: 1px solid #9F9F9F;
        }
        #search-box {
            padding: 30px 0 20px 0;
        }
        #search-box .layui-inline:first-child {
            margin-left: 30px;
        }
        #search-box .layui-inline {
            margin-right: 5px;
        }
        #data-search-btn {
            margin-left: 10px;
            display: inline-block;
        }
        #data-search-btn.layui-btn-container .layui-btn {
            margin-right: 20px;
        }
    </style>
</head>
<body>
<!-- 搜索栏 -->
<fieldset class="layui-elem-field site-demo-button" style="margin: 20px;">
    <legend>搜索栏</legend>
    <!-- 搜索栏 -->
    <div id="search-box" class="layui-form layui-card-header">
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="loc_no" placeholder="货位" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="matnr" placeholder="商品编号"  autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="maktx" placeholder="商品名称" autocomplete="off">
            </div>
        </div>
        <!-- 日期范围 -->
<!--        <div class="layui-inline" style="width: 300px">-->
<!--            <div class="layui-input-inline">-->
<!--                <input class="layui-input layui-laydate-range" name="update_time" type="text" placeholder="起始时间 - 终止时间" autocomplete="off" style="width: 300px">-->
<!--            </div>-->
<!--        </div>-->
        <!-- 待添加 -->
        <div id="data-search-btn" class="layui-btn-container layui-form-item" style="display: inline-block">
            <button id="search" class="layui-btn layui-btn-primary layui-btn-radius" lay-submit lay-filter="search">搜索</button>
            <button id="reset" class="layui-btn layui-btn-primary layui-btn-radius" lay-submit lay-filter="reset">重置</button>
        </div>
    </div>
</fieldset>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn" id="btn-confirm" lay-event="confirm" style="">提取</button>
    </div>
</script>
<div class="layui-form">
    <table class="layui-hide" id="stockOut" lay-filter="stockOut"></table>
</div>
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../../static/layui/layui.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/handlebars/handlebars-v4.5.3.js"></script>
</body>
<script>
    var pageCurr;
    function getCol() {
        var cols = [
            {type: 'checkbox'}
            ,{field: 'locNo', align: 'center',title: '货位'}
        ];
        cols.push.apply(cols, detlCols);
        cols.push({field: 'updateBy$', align: 'center',title: '修改人员', hide: true}
            ,{field: 'updateTime$', align: 'center',title: '修改时间'})
        return cols;
    }
    layui.use(['table','laydate', 'form'], function() {
        var table = layui.table;
        var $ = layui.jquery;
        var layer = layui.layer;
        var layDate = layui.laydate;
        var form = layui.form;
        // 数据渲染
        locDetlTableIns = table.render({
            elem: '#stockOut',
            headers: {token: localStorage.getItem('token')},
            url: baseUrl+'/manLocDetl/list',
            page: true,
            limit: 10,
            even: true,
            toolbar: '#toolbar',
            cellMinWidth: 50,
            cols: [getCol()],
            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) {
                if (res.code === 403) {
                    top.location.href = baseUrl+"/";
                }
                pageCurr=curr;
                // $('.layui-form-checkbox').css("pointer-events", "none");
                // $('td[data-field="0').css("cursor", "pointer")
            }
        });
        // 监听头工具栏事件
        table.on('toolbar(stockOut)', function (obj) {
            var checkStatus = table.checkStatus(obj.config.id);
            var data = checkStatus.data;
            switch(obj.event) {
                case 'confirm':
                    if (data.length === 0){
                        layer.msg("请选择数据");
                        return;
                    }
                    parent.addTableData(data);
                    break;
            }
        });
        // 搜索栏搜索事件
        form.on('submit(search)', function (data) {
            pageCurr = 1;
            tableReload();
        });
        // 搜索栏重置事件
        form.on('submit(reset)', function (data) {
            pageCurr = 1;
            clearFormVal($('#search-box'));
            tableReload();
        });
        layDate.render({
            elem: '.layui-laydate-range'
            ,type: 'datetime'
            ,range: true
        });
    })
    // var b = true;
    // $(function(){
    //     $(document.body).on('click','td[data-field="0"]',function(){
    //         var locNo = $(this).next().children("div").html();
    //         if (b) {
    //             b = false;
    //             $("tr td[data-field=locNo\\$] div:contains("+ locNo +")").parent().prev().children().children("div").click();
    //             setTimeout(function () {
    //                 b = true;
    //             }, 200)
    //         }
    //     });
    // })
    function tableReload(child) {
        var searchData = {};
        $.each($('#search-box [name]').serializeArray(), function() {
            searchData[this.name] = this.value;
        });
        locDetlTableIns.reload({
            where: searchData,
            page: {
                curr: pageCurr
            },
            done: function (res, curr, count) {
                if (res.code === 403) {
                    top.location.href = baseUrl+"/";
                }
                pageCurr=curr;
                // $('.layui-form-checkbox').css("pointer-events", "none");
                // $('td[data-field="0').css("cursor", "pointer")
            }
        });
    }
    function clearFormVal(el) {
        $(':input', el)
            .val('')
            .removeAttr('checked')
            .removeAttr('selected');
    }
</script>
</html>
src/main/webapp/views/ioWorks/matQuery.html
New file
@@ -0,0 +1,194 @@
<!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/common.css" media="all">
    <style>
        body {
            padding: 0 20px;
        }
        .layui-table-box {
            border-right: 1px solid #9F9F9F;
            border-left: 1px solid #9F9F9F;
        }
    </style>
</head>
<body>
<!-- 搜索栏 -->
<fieldset class="layui-elem-field site-demo-button" style="margin: 20px;">
    <legend>搜索栏</legend>
    <div id="search-box" class="layui-form layui-card-header">
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="matnr" placeholder="商品编码" autocomplete="off">
            </div>
        </div>
        <div class="layui-inline">
            <div class="layui-input-inline">
                <input class="layui-input" type="text" name="maktx" placeholder="商品名称" autocomplete="off">
            </div>
        </div>
        <!-- 日期范围 -->
        <div class="layui-inline" style="width: 300px">
            <div class="layui-input-inline">
                <input class="layui-input layui-laydate-range" name="update_time" type="text" placeholder="起始时间 - 终止时间" autocomplete="off" style="width: 300px">
            </div>
        </div>
        <!-- 待添加 -->
        <div id="data-search-btn" class="layui-btn-container layui-form-item" style="display: inline-block">
            <button id="search" class="layui-btn layui-btn-primary layui-btn-radius" lay-submit lay-filter="search">搜索</button>
            <button id="reset" class="layui-btn layui-btn-primary layui-btn-radius" lay-submit lay-filter="reset">重置</button>
        </div>
    </div>
</fieldset>
<script type="text/html" id="toolbar">
    <div class="layui-btn-container">
        <button class="layui-btn" id="btn-confirm" lay-event="confirm" style="">提取</button>
    </div>
</script>
<div class="layui-form">
    <table class="layui-hide" id="matCode" lay-filter="matCode"></table>
</div>
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../../static/layui/layui.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/handlebars/handlebars-v4.5.3.js"></script>
</body>
<script>
    function getCol() {
        var cols = [
            {type: 'checkbox', fixed: 'left'}
        ];
        cols.push.apply(cols, matCols);
        cols.push(
            {field: 'updateBy$', align: 'center',title: '修改人员', hide: true},
            {field: 'updateTime$', align: 'center',title: '修改时间'}
        )
        return cols;
    }
    var pageCurr;
    layui.use(['table','laydate', 'form'], function() {
        var table = layui.table;
        var $ = layui.jquery;
        var layer = layui.layer;
        var layDate = layui.laydate;
        var form = layui.form;
        // 物料查询数据表
        matQueryTable = table.render({
            elem: '#matCode',
            headers: {token: localStorage.getItem('token')},
            url: baseUrl + '/mat/list/auth',
            page: true,
            limit: 7,
            limits: [7, 10, 30,50,100],
            even: true,
            cellMinWidth: 50,
            toolbar: '#toolbar',
            cols: [getCol()],
            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) {
                if (res.code === 403) {
                    top.location.href = baseUrl + "/";
                }
            }
        });
        // 监听头工具栏事件
        table.on('toolbar(matCode)', function (obj) {
            var checkStatus = table.checkStatus(obj.config.id);
            var data = checkStatus.data;
            switch(obj.event) {
                case 'confirm':
                    if (data.length === 0){
                        layer.msg("请选择数据");
                        return;
                    }
                    parent.addTableData(data);
                    break;
            }
        });
        // 搜索栏搜索事件
        form.on('submit(search)', function (data) {
            pageCurr = 1;
            tableReload(false);
        });
        // 搜索栏重置事件
        form.on('submit(reset)', function (data) {
            pageCurr = 1;
            clearFormVal($('#search-box'));
            tableReload();
        });
        layDate.render({
            elem: '.layui-laydate-range'
            ,type: 'datetime'
            ,range: true
        });
    })
    function tableReload(child) {
        var searchData = {};
        $.each($('#search-box [name]').serializeArray(), function() {
            searchData[this.name] = this.value;
        });
        matQueryTable.reload({
            where: searchData,
            page: {
                curr: pageCurr
            },
            done: function (res, curr, count) {
                if (res.code === 403) {
                    top.location.href = baseUrl+"/";
                }
                pageCurr=curr;
                if (res.data.length === 0 && count !== 0) {
                    tableIns.reload({
                        where: searchData,
                        page: {
                            curr: pageCurr-1
                        }
                    });
                    pageCurr -= 1;
                }
            }
        });
    }
    function clearFormVal(el) {
        $(':input', el)
            .val('')
            .removeAttr('checked')
            .removeAttr('selected');
    }
</script>
</html>
src/main/webapp/views/ioWorks/stockIn.html
New file
@@ -0,0 +1,145 @@
<!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/common.css" media="all">
    <style>
        html {
            height: 100%;
            padding: 10px;
            background-color: #f1f1f1;
        }
        body {
            background-color: #fff;
            border-radius: 5px;
            box-shadow: 0 0 3px rgba(0,0,0,.3);
        }
        .function-area {
            padding: 20px 50px;
        }
        .function-btn {
            font-size: 16px;
            padding: 1px 1px 1px 1px;
            width: 100px;
            height: 50px;
            border-color: #2b425b;
            border-radius: 4px;
            border-width: 2px;
            background: none;
            border-style: solid;
            transition: 0.4s;
            cursor: pointer;
            letter-spacing: 3px;
        }
        .function-btn:hover {
            background-color: #2b425b;
            color: #fff;
        }
        .layui-layer-page .layui-layer-content {
            position: relative;
            overflow: visible !important;
        }
        #mat-query {
            /*display: none;*/
        }
        #staNoSpan {
            text-align: center;
            display: inline-block;
            width: 100px;
            font-size: 13px;
        }
        .layui-btn-container .layui-form-select {
            display: inline-block;
            width: 150px;
            height: 30px;
        }
        .layui-btn-container .layui-form-select.layui-form-selected {
            display: inline-block;
            width: 150px;
        }
        .layui-btn-container .layui-select-title input {
            font-size: 13px;
        }
        .layui-btn-container .layui-anim.layui-anim-upbit dd {
            font-size: 13px;
        }
        #btn-inbound {
            margin-left: 20px;
            /*display: none;*/
        }
        #detail {
            margin: 0;
            padding: 25px 30px 0 0;
        }
    </style>
</head>
<body>
<!-- 功能区 -->
<div class="function-area">
    <button id="mat-query" class="function-btn" onclick="getMat()">新增</button>
</div>
<hr>
<!-- 表格 -->
<div style="padding-bottom: 5px; margin-bottom: 45px">
    <!-- 头部 -->
    <script type="text/html" id="toolbar">
        <div class="layui-form">
            <div class="layui-btn-container">
                <!-- 启动出库 -->
                <button class="layui-btn layui-btn-lg" id="btn-inbound" lay-event="confirm" style="">确认入库</button>
            </div>
        </div>
    </script>
    <!-- 行 -->
    <script type="text/html" id="operate">
        <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="remove">移除</a>
    </script>
    <table class="layui-table" id="chooseData" lay-filter="chooseData"></table>
</div>
<!--<table id="node" style="display: none"></table>-->
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../../static/layui/layui.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/handlebars/handlebars-v4.5.3.js"></script>
<script type="text/javascript" src="../../static/js/ioWorks/stockIn.js" charset="utf-8"></script>
<script type="text/template" id="putSiteSelectTemplate">
    {{#each data}}
        <option value="{{this}}">{{this}}</option>
    {{/each}}
</script>
<script type="text/html" id="nodeSelect">
    <form id="detail" lay-filter="detail" class="layui-form">
        <div class="layui-form-item">
            <label class="layui-form-label">上架货位</label>
            <div class="layui-input-block">
                <div id="nodeSel" class="ew-xmselect-tree"></div>
            </div>
        </div>
        <div class="layui-form-item text-right">
            <button class="layui-btn" lay-filter="pakin" lay-submit="">确认入库</button>
            <button class="layui-btn layui-btn-primary" type="button" ew-event="closeDialog">取消</button>
        </div>
    </form>
</script>
</body>
</html>
src/main/webapp/views/ioWorks/stockOut.html
New file
@@ -0,0 +1,125 @@
<!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/common.css" media="all">
    <style>
        html {
            height: 100%;
            padding: 10px;
            background-color: #f1f1f1;
        }
        body {
            background-color: #fff;
            border-radius: 5px;
            box-shadow: 0 0 3px rgba(0,0,0,.3);
            padding-bottom: 20px;
        }
        #staNoSpan {
            text-align: center;
            display: inline-block;
            width: 100px;
            font-size: 13px;
        }
        .layui-btn-container .layui-form-select {
            display: inline-block;
            width: 150px;
            height: 30px;
        }
        .layui-btn-container .layui-form-select.layui-form-selected {
            display: inline-block;
            width: 150px;
        }
        .layui-btn-container .layui-select-title input {
            font-size: 13px;
        }
        .layui-btn-container .layui-anim.layui-anim-upbit dd {
            font-size: 13px;
        }
        #btn-outbound {
            margin-left: 20px;
            /*display: none;*/
        }
        /*----------------------------------*/
        .function-area {
            padding: 20px 50px;
        }
        .function-btn {
            font-size: 16px;
            padding: 1px 1px 1px 1px;
            width: 100px;
            height: 50px;
            border-color: #2b425b;
            border-radius: 4px;
            border-width: 2px;
            background: none;
            border-style: solid;
            transition: 0.4s;
            cursor: pointer;
            letter-spacing: 3px;
        }
        .function-btn:hover {
            background-color: #2b425b;
            color: #fff;
        }
        #mat-query {
            /*display: none;*/
        }
    </style>
</head>
<body>
<!-- 功能区 -->
<div class="function-area">
    <button id="mat-query" class="function-btn" onclick="getLocDetl()">新增</button>
</div>
<hr>
<!-- 表格 -->
<div style="padding-bottom: 5px; margin-bottom: 45px">
    <!-- 头部 -->
    <script type="text/html" id="toolbar">
        <div class="layui-form">
            <div class="layui-btn-container">
                <!-- 启动出库 -->
                <button class="layui-btn layui-btn-lg layui-btn-normal" id="btn-outbound" lay-event="outbound">确认出库</button>
            </div>
        </div>
    </script>
    <!-- 行 -->
    <script type="text/html" id="operate">
        <a class="layui-btn layui-btn-danger layui-btn-xs" lay-event="remove">移除</a>
    </script>
    <table class="layui-table" id="chooseData" lay-filter="chooseData"></table>
</div>
<script type="text/javascript" src="../../static/js/jquery/jquery-3.3.1.min.js"></script>
<script type="text/javascript" src="../../static/layui/layui.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/handlebars/handlebars-v4.5.3.js"></script>
<script type="text/javascript" src="../../static/js/ioWorks/stockOut.js" charset="utf-8"></script>
<script type="text/template" id="takeSiteSelectTemplate">
    {{#each data}}
    <option value="{{siteId}}">{{desc}}</option>
    {{/each}}
</script>
</body>
</html>