Browse Source

add:增加出入库分配策略类

feature/forewarning_management
龚宝雄 1 month ago
parent
commit
ded74f9d73
  1. 4
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IStructattrService.java
  2. 180
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/StructattrVechielDto.java
  3. 6
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/mapper/StructattrMapper.java
  4. 36
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/mapper/StructattrMapper.xml
  5. 8
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java
  6. 36
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/Decisioner.java
  7. 203
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/AlleyAveRuleHandler.java
  8. 160
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/ClusterRuleHandler.java
  9. 148
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/FIFORuleHandler.java
  10. 136
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/LimitStorageRuleHandler.java
  11. 60
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/NearbyRuleHandler.java
  12. 140
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/WeightRuleHandler.java
  13. 20
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/出入库基础规则.md
  14. 16
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/ClassRuleHandler.java
  15. 138
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/DepthPriorityHandler.java
  16. 93
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/InventoryRuleHandler.java
  17. 69
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/PassRCLHandler.java
  18. 76
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/SameBlockNumRuleHandler.java
  19. 2
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/PmFormData.java
  20. 4
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/mapper/PmFormDataMapper.java
  21. 264
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/mapper/xml/PmFormDataMapper.xml
  22. 2
      nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dto/PmFormDataDto.java
  23. 6
      nladmin-system/nlsso-server/src/main/resources/db/migration/V1.0__schema.sql
  24. 137
      nladmin-ui/src/views/wms/pm_manage/form_data/index.vue

4
nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/IStructattrService.java

@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.IService;
import org.nl.common.domain.query.PageQuery;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
import org.nl.wms.warehouse_management.service.dao.IOStorInv;
import org.springframework.data.domain.Pageable;
@ -101,4 +102,7 @@ public interface IStructattrService extends IService<Structattr> {
* @return Structattr
*/
Structattr getByCode(String struct_code);
List<StructattrVechielDto> collectVechicle(Map query);
}

180
nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/StructattrVechielDto.java

@ -0,0 +1,180 @@
package org.nl.wms.basedata_manage.service.dao;
import lombok.Data;
import org.nl.wms.warehouse_management.service.dao.GroupPlate;
import java.math.BigDecimal;
/*
* @author ZZQ
* @Date 2023/5/4 19:49
*/
@Data
public class StructattrVechielDto extends MdPbStoragevehicleext {
private static final long serialVersionUID = 1L;
/**
* 仓位标识
*/
private String id;
/**
* 载具物料id
*/
private String vm_id;
/**
* 入库类型
*/
private String source_form_type;
/**
* 仓位编码
*/
private String struct_code;
/**
* 仓位名称
*/
private String struct_name;
/**
* 库区标识
*/
private String sect_code;
/**
* 仓库标识
*/
private String stor_code;
/**
* 容量
*/
private Integer capacity;
/**
* 宽度
*/
private Integer w;
/**
* 高度
*/
private Integer h;
/**
* 深度(长度)
*/
private Integer l;
/**
* 承受重量
*/
private Integer weight;
/**
* 起始X坐标
*/
private BigDecimal xqty;
/**
* 起始Y坐标
*/
private BigDecimal yqty;
/**
* 起始Z坐标
*/
private BigDecimal zqty;
/**
*
*/
private Integer row_num;
/**
*
*/
private Integer col_num;
/**
*
*/
private Integer layer_num;
/**
*
*/
private Integer block_num;
/**
* 超限货位关联的货位编号
*/
private String control_code;
/**
* 创建人
*/
private String create_id;
/**
* 创建人姓名
*/
private String create_name;
/**
* 创建时间
*/
private String create_time;
/**
* 是否临时仓位
*/
private Boolean is_temp;
/**
* 是否启用
*/
private Boolean is_used;
/**
* 锁定类型
*/
private String lock_type;
/**
* 是否判断高度
*/
private String is_zdepth;
/**
* 存储载具号
*/
private String vehicle_code;
/**
* 备注
*/
private String remark;
/**
* 背景图片
*/
private String back_ground_pic;
/**
* 前景色
*/
private String front_ground_color;
/**
* 背景色
*/
private String back_ground_color;
/**
* 字体显示方向
*/
private String font_direction_scode;
}

6
nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/mapper/StructattrMapper.java

@ -3,6 +3,10 @@ package org.nl.wms.basedata_manage.service.dao.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
import java.util.List;
import java.util.Map;
/**
* @author dsh
@ -11,4 +15,6 @@ import org.nl.wms.basedata_manage.service.dao.Structattr;
@Mapper
public interface StructattrMapper extends BaseMapper<Structattr>{
List<StructattrVechielDto> collectVehicle(Map query);
}

36
nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/dao/mapper/StructattrMapper.xml

@ -0,0 +1,36 @@
<?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="org.nl.wms.basedata_manage.service.dao.mapper.StructattrMapper">
<select id="collectVehicle" resultType="org.nl.wms.basedata_manage.service.dao.StructattrVechielDto">
SELECT
vm.canuse_qty,
vm.frozen_qty,
vm.update_time,
vm.material_id,
vm.pcsn,
vm.storagevehicleext_id AS vm_id,
ivt.*
FROM
st_ivt_structattr ivt
LEFT JOIN md_pb_storagevehicleext vm ON ivt.storagevehicle_code = vm.storagevehicle_code
WHERE
vm.material_id = #{material_id}
<if test="pcsn != null and pcsn != ''">
AND vm.pcsn = #{pcsn}
</if>
AND ivt.stor_code = #{stor_code}
<if test="vehicles != null and vehicles.size() > 0">
AND ivt.storagevehicle_code in
<foreach collection="vehicles" item="value" index="key" open="(" close=")" separator=",">
#{value}
</foreach>
</if>
<if test="is_lock != null and is_lock != ''">
and ivt.lock_type = '00'
and vm.frozen_qty = 0
</if>
<if test="order_by != null and order_by != ''">
order by ${order_by}
</if>
</select>
</mapper>

8
nladmin-system/nlsso-server/src/main/java/org/nl/wms/basedata_manage/service/impl/StructattrServiceImpl.java

@ -25,6 +25,7 @@ import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.BsrealStorattr;
import org.nl.wms.basedata_manage.service.dao.Sectattr;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
import org.nl.wms.basedata_manage.service.dao.mapper.StructattrMapper;
import org.nl.wms.warehouse_management.enums.IOSEnum;
import org.nl.wms.warehouse_management.service.dao.IOStorInv;
@ -300,4 +301,11 @@ public class StructattrServiceImpl extends ServiceImpl<StructattrMapper, Structa
return one;
}
@Override
public List<StructattrVechielDto> collectVechicle(Map query) {
List<StructattrVechielDto> collectVehicle = this.baseMapper.collectVehicle(query);
return collectVehicle;
}
}

36
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/Decisioner.java

@ -0,0 +1,36 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.nl.common.exception.BadRequestException;
import org.nl.config.SpringContextHolder;
import org.nl.wms.decision_manage.service.strategyConfig.IStStrategyConfigService;
import org.nl.wms.decision_manage.service.strategyConfig.dao.StStrategyConfig;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ResolvableType;
import java.util.List;
/*
* @author ZZQ
* @Date 2024/4/6 16:13
*/
public abstract class Decisioner<T,P> implements InitializingBean {
//每个策略的配置信息
public StStrategyConfig strategyConfig;
@Autowired
private IStStrategyConfigService iStStrategyConfigService;
@Autowired
private SpringContextHolder springContextHolder;
public abstract List<T> handler(List<T> list, P param);
@Override
public void afterPropertiesSet(){
String type = SpringContextHolder.getApplicationContext().getBeanNamesForType(ResolvableType.forClass(this.getClass()))[0];
this.strategyConfig =iStStrategyConfigService.getOne(new QueryWrapper<StStrategyConfig>().eq("strategy_code",type));
if (this.strategyConfig == null){
throw new BadRequestException("启动失败:当前策略"+type+"没有实例信息");
}
}
}

203
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/AlleyAveRuleHandler.java

@ -0,0 +1,203 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.common.utils.MapOf;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 巷道均衡策略XYZ: 排列层
*/
@Slf4j
@Service("alleyAve")
public class AlleyAveRuleHandler extends Decisioner<Structattr, JSONObject> {
@Autowired
private IStructattrService iStructattrService;
/**
* 巷道均衡策略
*
* @param list 仓位集合
* @param param出入库单明细物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
// 判断仓位是否为空
if (CollectionUtils.isEmpty(list)) {
throw new BadRequestException("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略无可用货位");
}
long startTime1 = System.currentTimeMillis();
if (ObjectUtils.isNotEmpty(list)) {
//扩展库不需要均衡策略
if ("LXBCP02".equals(list.get(0).getSect_code())) {
return list;
}
}
/**
* 根据XYZ进行均衡排序排层列
*/
String configParam = this.strategyConfig.getParam();
List<String> configList = JSONObject.parseArray(configParam, String.class);
list.sort((o1, o2) -> {
BigDecimal rowNum1 = o1.getRow_num();
BigDecimal colNum1 = o1.getCol_num();
BigDecimal layerNum1 = o1.getLayer_num();
BigDecimal rowNum2 = o2.getRow_num();
BigDecimal colNum2 = o2.getCol_num();
BigDecimal layerNum2 = o2.getLayer_num();
HashMap<String, Integer> of1 = MapOf.of("x", rowNum1, "y", colNum1, "z", layerNum1);
HashMap<String, Integer> of2 = MapOf.of("x", rowNum2, "y", colNum2, "z", layerNum2);
for (String sort : configList) {
if (of1.get(sort) > of2.get(sort)) {
return 1;
}
if (of1.get(sort) < of2.get(sort)) {
return -1;
}
}
return 0;
});
List<Structattr> subList = list.subList(0, Math.min(list.size(), 10));
Structattr result = iStructattrService.getOne(
new LambdaQueryWrapper<Structattr>()
.eq(Structattr::getStruct_code, subList.get(0).getStruct_code())
);
if (result.getStoragevehicle_code() != null || !"00".equals(result.getLock_type())) {
log.error("均衡策略分配异常,出现流程节点完成库存延迟锁定,载具号" + param.getString("vehicle_code") + "分配异常,仓位: " + result.getStruct_code() + ",该仓位被其他任务的载具锁定或其锁类型锁住");
subList = subList.stream().filter(r -> !r.getStruct_code().equals(result.getStruct_code())).collect(Collectors.toList());
}
log.info("均衡策略结果:载具号:" + param.getString("vehicle_code") + "分配结果: " + subList.stream().map(Structattr::getStruct_code).collect(Collectors.toList()));
log.info("均衡策略:载具号:" + param.getString("vehicle_code") + "获取仓位耗时:{}", System.currentTimeMillis() - startTime1);
if (subList.size() == 0) {
log.error("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略货位数量为0");
throw new BadRequestException("均衡策略结果:载具号:" + param.getString("vehicle_code") + "当前分配策略货位数量为0");
}
return subList;
}
// public static void main(String[] args) {
// List<Structattr> list = new ArrayList<>();
// for (int i =0;i<10;i++){
// Structattr structattr = new Structattr();
// structattr.setRow_num(new Random().nextInt(2)+1);
// structattr.setCol_num(new Random().nextInt(10)+1);
// structattr.setLayer_num(new Random().nextInt(2)+1);
// list.add(structattr);
// }
// System.out.println(list);
// ArrayList<String> of = ListOf.of("x", "z","y");
// list.sort((o1, o2) -> {
// Integer rowNum1 = o1.getRow_num();
// Integer colNum1 = o1.getCol_num();
// Integer layerNum1 = o1.getLayer_num();
// Integer rowNum2 = o2.getRow_num();
// Integer colNum2 = o2.getCol_num();
// Integer layerNum2 = o2.getLayer_num();
// HashMap<String,Integer> of1 = MapOf.of("x", rowNum1, "y", colNum1, "z", layerNum1);
// HashMap<String,Integer> of2 = MapOf.of("x", rowNum2, "y", colNum2, "z", layerNum2);
// for (String sort : of) {
// Integer in1 = of1.get(sort);
// Integer in2 = of2.get(sort);
// if (in1 > in2){
// return 1;
// }
// if (in1 < in2){
// return -1;
// }
// }
// return 0;
// });
// System.out.println(list.toString());
// }
/**
* 入库策略
*
* @param attrList 仓位集合
* @param jsonParammaterialId 物料标识此方法只根据物料进行匹配
* @return List<Structattr> 仓位集合
*/
// private List<Structattr> inHandler(List<Structattr> attrList, PmFormData jsonParam) {
// // in查询条件处理
// List<Integer> blockNumIn = attrList.stream()
// .map(Structattr::getBlock_num)
// .distinct()
// .collect(Collectors.toList());
// // 查询相同巷道货位相同物料
// List<Structattr> blockAttrList = null;
// iStructattrService.getByQuery(new StructattrQuery());
// // 如果为空说明这些巷道都没有相同物料的巷道,则返回所有仓位
// if (ObjectUtil.isEmpty(blockAttrList)) {
// return attrList;
// }
// // 计算每个巷道的相同物料
// Map<Integer, List<Structattr>> collectMap = blockAttrList.stream()
// .collect(Collectors.groupingBy(Structattr::getBlock_num));
// // 巷道
// int blockNum = blockAttrList.get(0).getBlock_num().intValue();
// // 集合数量
// int size = blockAttrList.size();
// for (Integer num : collectMap.keySet()) {
// int min = Math.min(size, collectMap.get(num).size());
// if (size > min) {
// // 返回最小的巷道
// blockNum = num.intValue();
// size = min;
// }
// }
// // 匹配相同巷道的集合并返回
// int finalBlockNum = blockNum;
// return attrList.stream()
// .filter(row -> row.getBlock_num().intValue() == finalBlockNum)
// .collect(Collectors.toList());
// }
/**
* 出库策略 - 查询物料最多的巷道
*
* @param attrList 仓位物料
* @return 巷道
*/
// private int getMaxMaterial(List<Structattr> attrList) {
// // 根据巷道分组
// Map<Integer, List<Structattr>> collectMap = attrList.stream()
// .collect(Collectors.groupingBy(Structattr::getBlock_num));
// // 找最大物料巷道
// // 巷道
// int blockNum = attrList.get(0).getBlock_num().intValue();
// // 集合数量
// int size = 0;
// for (Integer num : collectMap.keySet()) {
// int max = Math.max(size, collectMap.get(num).size());
// if (size < max) {
// // 返回最大的巷道
// blockNum = num.intValue();
// size = max;
// }
// }
// return blockNum;
// }
}

160
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/ClusterRuleHandler.java

@ -0,0 +1,160 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 同类型聚簇策略
*/
@Service("cluster")
public class ClusterRuleHandler extends Decisioner<Structattr, String> {
/**
* 仓位服务
*/
@Autowired
private IStructattrService iStructattrService;
/**
* 同类物品集中原则
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, String param) {
// 判断仓位是否为空
if (ObjectUtil.isEmpty(list)) {
throw new BadRequestException("仓位集合为空!");
}
// 判断策略类型
JSONObject jsonParam = JSONObject.parseObject(param, JSONObject.class);
List<Structattr> resultList = new ArrayList<>();
switch (jsonParam.getString("ioType")) {
case "1":
// 入库策略
resultList = inHandler(list, jsonParam);
break;
case "2":
// 出库策略
// resultList = outHandler(list,jsonParam);
break;
case "3":
// 通用策略
break;
default:
throw new BadRequestException("策略类型错误!");
}
return resultList;
}
/**
* 入库策略
*
* @param attrList 仓位集合
* @param jsonParammaterialId 物料标识此方法只根据物料排进行匹配
* @return List<Structattr> 仓位集合
*/
private List<Structattr> inHandler(List<Structattr> attrList, JSONObject jsonParam) {
// in查询条件处理
List<BigDecimal> rowNumIn = attrList.stream()
.map(Structattr::getRow_num)
.distinct()
.collect(Collectors.toList());
// 查询仓位中是否有相同的物料
List<Structattr> attrLikeList = new ArrayList<>();
// = iStructattrService.list(
// new QueryWrapper<Structattr>().lambda()
// .eq(Structattr::getMaterial_id, jsonParam.getString("materialId"))
// .in(Structattr::getRow_num, rowNumIn)
if (ObjectUtil.isEmpty(attrLikeList)) {
return attrList;
}
// 取其中一个排进行匹配并返回
return attrList.stream()
.filter(row -> row.getRow_num().intValue() == attrLikeList.get(0).getRow_num().intValue())
.collect(Collectors.toList());
}
/**
* 出库策略
* @param attrList 仓位物料信息
* @param jsonParamiostorinvdtlId 出入库明细标识此方法只根据明细物料匹配
* @return List<Structattr> 需出库仓位集合
*/
// private List<Structattr> outHandler(List<Structattr> attrList, JSONObject jsonParam) {
//
// // 查询对应的出入库明细
// StIvtIostorinvdtlIn dtlDao = iStIvtIostorinvdtlService.getById(jsonParam.getString("iostorinvdtlId"));
//
// // 查询传入仓位物料中的数量是否满足明细中的数量
// List<String> vehicleCodeIn = attrList.stream()
// .map(Structattr::getStoragevehicle_code)
// .distinct()
// .collect(Collectors.toList());
//
// List<MdPbStoragevehicleext> extList = iMdPbStoragevehicleextService.list(
// new QueryWrapper<MdPbStoragevehicleext>().lambda()
// .in(MdPbStoragevehicleext::getStoragevehicle_code, vehicleCodeIn)
// );
//
// double attrQty = extList.stream()
// .map(MdPbStoragevehicleext::getQty)
// .reduce(BigDecimal.ZERO, BigDecimal::add)
// .doubleValue();
//
// if (dtlDao.getUnassign_qty().doubleValue() > attrQty) {
// // 说明不满足所需重量则全部返回
// return attrList;
// }
//
// // 需返回仓位物料集合
// List<Structattr> resultList = new ArrayList<>();
// // 满足所需数量: 根据巷道进行平均分配
// double unAssingQty = dtlDao.getUnassign_qty().doubleValue();
//
// while (unAssingQty > 0) {
//
// // 添加需返回的仓位物料
// Structattr attrDao = attrList.get(0);
// resultList.add(attrDao);
//
// // 减去未分配重量
// MdPbStoragevehicleext extDao = extList.stream()
// .filter(row -> row.getStoragevehicle_code().equals(attrDao.getStoragevehicle_code()))
// .findFirst().orElse(null);
//
// if (ObjectUtil.isEmpty(extDao)) {
// throw new BadRequestException("未查询到载具对应的物料【"+attrDao.getStoragevehicle_code()+"】");
// }
//
// unAssingQty = NumberUtil.sub(unAssingQty,extDao.getQty().doubleValue());
//
// // 移出此仓位物料,方便下一轮进行匹配
// attrList.remove(attrDao);
// }
//
// return resultList;
// }
}

148
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/FIFORuleHandler.java

@ -0,0 +1,148 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.common.utils.MapOf;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.StructattrVechielDto;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 先进先出策略
*/
@Service("fifo")
@Slf4j
public class FIFORuleHandler extends Decisioner<StructattrVechielDto, JSONObject> {
/**
* 出入库明细服务
*/
@Autowired
private IStructattrService iStructattrService;
@Override
public List<StructattrVechielDto> handler(List<StructattrVechielDto> list, JSONObject param) {
//分配数量
int plan_qty = param.getInteger("qty");
int finalPlan_qty = plan_qty;
//当前条件只有id,批次
log.info("---------执行fifo出库分配规则---------");
List<StructattrVechielDto> vechielDtos = iStructattrService.collectVechicle(MapOf.of("material_id", param.getString("material_id")
, "pcsn", param.getString("pcsn")
, "stor_code", param.getString("stor_code")
, "plan_qty", plan_qty
, "is_lock", "false"
, "order_by", "md_pb_vehicleMater.pcsn asc")
);
if (ObjectUtils.isEmpty(vechielDtos)) {
throw new BadRequestException("当前出库策略:先进先出,库存分配失败,失败原因:库存不足!");
}
List<StructattrVechielDto> disList = new ArrayList<>();
Map<String, List<StructattrVechielDto>> groupedMap = vechielDtos.stream()
.collect(Collectors.groupingBy(
StructattrVechielDto::getPcsn,
Collectors.collectingAndThen(
Collectors.toList(),
r -> r.stream()
.sorted(Comparator.comparing(StructattrVechielDto::getPcsn))
.collect(Collectors.toList())
)
));
LinkedHashMap<String, List<StructattrVechielDto>> sortedGroupMap = groupedMap.entrySet().stream()
.sorted(Comparator.comparing(entry -> entry.getValue().get(0).getPcsn()))
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(r, s) -> r,
LinkedHashMap::new
));
for (Map.Entry<String, List<StructattrVechielDto>> entry : sortedGroupMap.entrySet()) {
List<StructattrVechielDto> sortedList = new ArrayList<>(entry.getValue());
for (StructattrVechielDto structattr : sortedList) {
BigDecimal qty = structattr.getCanuse_qty() != null ? structattr.getCanuse_qty() : BigDecimal.ZERO;
BigDecimal frozen = structattr.getFrozen_qty() != null ? structattr.getFrozen_qty() : BigDecimal.ZERO;
int available = qty.subtract(frozen).intValue();
if (available <= 0) {
continue;
}
if (finalPlan_qty <= available) {
structattr.setFrozen_qty(frozen.add(new BigDecimal(finalPlan_qty)));
disList.add(structattr);
finalPlan_qty = 0;
break;
} else {
structattr.setFrozen_qty(frozen.add(new BigDecimal(available)));
disList.add(structattr);
finalPlan_qty -= available;
}
}
if (finalPlan_qty <= 0) {
break;
}
}
return disList;
}
/**
* 巷道均衡策略
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
// @Override
// public List<StructattrVechielDto> handler1(List<StructattrVechielDto> list, JSONObject param) {
// // 判断仓位是否为空
//// if (ObjectUtil.isEmpty(list)) {
//// throw new BadRequestException("库存分配失败:库存不足!");
//// }
//// List<String> need = list.stream().map(StructattrVechielDto::getStoragevehicle_code).collect(Collectors.toList());
// //分配数量
// int plan_qty = param.getInteger("qty");
// //当前条件只有id,批次
// log.info("---------执行fifo出库分配规则---------");
// List<StructattrVechielDto> vechielDtos = iStructattrService.collectVechicle(MapOf.of("material_id", param.getString("material_id")
// , "pcsn", param.getString("pcsn")
// , "stor_code", param.getString("stor_code")
// , "plan_qty", plan_qty
// , "is_lock", "false"
//// , "order_by","block_num asc,ABS(qty-#{plan_qty}) asc,update_time asc")
// , "order_by","block_num asc,ABS(qty-#{plan_qty}) asc,update_time asc")
// );
// int finalPlan_qty = 0;
//// vechielDtos.sort(Comparator.comparingInt(o -> (o.getQty().intValue() - finalPlan_qty)));
// List<StructattrVechielDto> disList = new ArrayList<>();
// for (StructattrVechielDto structattr : vechielDtos) {
//// if (need.contains(structattr.getStoragevehicle_code()) && structattr.getFrozen_qty().intValue()==0){
// if (structattr.getFrozen_qty().intValue()==0){
// int cause_qty = structattr.getQty().subtract(structattr.getFrozen_qty()).intValue();
// int sub = plan_qty - cause_qty;
// finalPlan_qty = sub;
// disList.add(structattr);
// if (sub<=0){
// structattr.setFrozen_qty(new BigDecimal(plan_qty));
// break;
// }
// structattr.setFrozen_qty(new BigDecimal(cause_qty));
// plan_qty = sub;
// }
// }
// if (finalPlan_qty>0){
// throw new BadRequestException("库存不足:物料"+param.getString("material_id")+"当前库存可用数"+(param.getInteger("qty").intValue()-finalPlan_qty));
// }
// return disList;
// }
}

136
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/LimitStorageRuleHandler.java

@ -0,0 +1,136 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.IMdPbStoragevehicleinfoService;
import org.nl.wms.basedata_manage.service.dao.MdPbStoragevehicleinfo;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.function.Predicate;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 货位限位策略 限高限宽,限长限重
*/
@Service("limitStorage")
@Slf4j
public class LimitStorageRuleHandler extends Decisioner<Structattr, JSONObject> {
/**
* 载具扩展属性服务服务
*/
@Autowired
private IMdPbStoragevehicleinfoService bmVehicleInfoService;
/**
* 货位限位策略根据货位的长宽高
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
long startTime1 = System.currentTimeMillis();
// 判断仓位是否为空
// 判断策略类型
String vehicleCode = param.getString("vehicle_code");
MdPbStoragevehicleinfo vehileInfo = bmVehicleInfoService.getOne(new QueryWrapper<MdPbStoragevehicleinfo>().eq("storagevehicle_code", vehicleCode));
if (vehileInfo == null) {
throw new BadRequestException("限位策略,当前载具信息不存在:" + vehicleCode + "!");
}
//限位策略特殊处理
String start_point = param.getString("start_point");
String errorTask = param.getString("errorTask");
log.info("限位策略:起点为" + start_point + ",载具号:" + vehicleCode + "执行策略前仓位位数为:" + list.size() + ",第一个仓位为:" + list.get(0).getStruct_code());
if ((StringUtils.isNotBlank(start_point) || StringUtils.isNotBlank(errorTask))) {
list = list.stream().filter(struct -> struct.getCol_num().intValue() > 2).collect(Collectors.toList());
if ("1109".equals(start_point)) {
log.info("限位策略:起点为1109,载具号:" + vehicleCode + "排除小于3排的仓位成功!");
}
if (StringUtils.isNotBlank(errorTask)) {
log.info("限位策略:任务类型为入满或出阻挡任务,载具号:" + vehicleCode + "排除小于3排的仓位成功!");
}
}
List<Structattr> result = inHandler(list, vehileInfo);
if (CollectionUtils.isEmpty(result)) {
log.error("限位策略:载具号:" + vehicleCode + "获取仓位失败,该高度等级对应库位数量为0!");
throw new BadRequestException("限位策略:载具号:" + vehicleCode + "获取仓位失败,该高度等级对应库位数量为0!");
}
log.info("限位策略:起点为" + start_point + ",载具号:" + vehicleCode + "执行策略后仓位位数为:" + result.size() + ",第一个仓位为:" + result.get(0).getStruct_code());
log.info("限位策略:载具号:" + vehicleCode + "获取仓位耗时:{}", System.currentTimeMillis() - startTime1);
return result;
}
/**
* 入库策略判断货位的长宽高
*
* @param attrList 仓位集合
* @param vehicle 物料标识width: 宽度 height高度zdepth深度
* @return List<Structattr> 仓位集合
*/
private List<Structattr> inHandler(List<Structattr> attrList, MdPbStoragevehicleinfo vehicle) {
//限制条件:限制哪些
List<String> limits = JSONArray.parseArray(strategyConfig.getParam(), String.class);
Predicate<Structattr> eqLimt = Structattr -> {
Boolean result = Boolean.TRUE;
if (limits.contains("h")) {
result = result && Structattr.getHeight().equals(vehicle.getVehicle_height());
}
if (limits.contains("w")) {
result = result && Structattr.getWidth().equals(vehicle.getVehicle_width());
}
if (limits.contains("l")) {
result = result && Structattr.getZdepth().equals(vehicle.getVehicle_long());
}
if (limits.contains("weight")) {
result = result && Structattr.getWeight().equals(vehicle.getWeigth());
}
return result;
};
// 判断长宽高是否符合要求
List<Structattr> eqLimitCollect = attrList.stream()
.filter(eqLimt)
.collect(Collectors.toList());
if (!CollectionUtils.isEmpty(eqLimitCollect)) {
return eqLimitCollect;
}
Predicate<Structattr> ltLimt = Structattr -> {
Boolean result = Boolean.TRUE;
if (limits.contains("h")) {
result = result && Structattr.getHeight().compareTo(vehicle.getVehicle_height()) > 0;
}
if (limits.contains("w")) {
result = result && Structattr.getWidth().compareTo(vehicle.getVehicle_width()) > 0;
}
if (limits.contains("l")) {
result = result && Structattr.getZdepth().compareTo(vehicle.getVehicle_long()) > 0;
}
if (limits.contains("weight")) {
result = result && Structattr.getWeight().compareTo(vehicle.getWeigth()) > 0;
}
return result;
};
// 判断长宽高是否符合要求
List<Structattr> ltLimtCollect = attrList.stream()
.filter(ltLimt)
.collect(Collectors.toList());
return ltLimtCollect;
}
}

60
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/NearbyRuleHandler.java

@ -0,0 +1,60 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 就近放置策略根据物料ABC类区分
*/
@Service("nearby")
@Slf4j
public class NearbyRuleHandler extends Decisioner<Structattr, JSONObject> {
//每个策略的配置信息
/**
* 出入库明细服务
*/
@Autowired
private IStructattrService iStructattrService;
/**
* 载具扩展属性服务服务
*/
/**
* 就近放置策略根据出入库顺序进行判断
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
if (CollectionUtils.isEmpty(list)) {
throw new BadRequestException("当前分配策略无可用货位");
}
List<Structattr> before = list.subList(0, list.size() > 10 ? 10 : list.size());
log.info("就近分配前:" + before.stream().map(Structattr::getStruct_code).collect(Collectors.joining(",")));
list.sort(Comparator.comparingInt(i -> i.getRow_num().add(i.getCol_num()).add(i.getLayer_num()).intValue()));
//就近分配区分出库还是入库策略
List<Structattr> subList = list.subList(0, list.size() > 10 ? 10 : list.size());
log.info("就近分配结果:" + subList.stream().map(Structattr::getStruct_code).collect(Collectors.joining(",")));
return subList;
}
}

140
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/WeightRuleHandler.java

@ -0,0 +1,140 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.base;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 轻上重下策略
*/
@Service("weight")
public class WeightRuleHandler extends Decisioner<Structattr, String> {
/**
* 轻上重下策略根据物品的重量
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, String param) {
// 判断仓位是否为空
if (ObjectUtil.isEmpty(list)) {
throw new BadRequestException("仓位集合为空!");
}
// 判断策略类型
JSONObject jsonParam = JSONObject.parseObject(param, JSONObject.class);
List<Structattr> resultList = new ArrayList<>();
switch (jsonParam.getString("ioType")) {
case "1":
// 入库策略
resultList = inHandler(list, jsonParam);
break;
case "2":
// 出库策略
// resultList = outHandler(list,jsonParam);
break;
case "3":
// 通用策略
break;
default:
throw new BadRequestException("策略类型错误!");
}
return resultList;
}
/**
* 入库策略根据重量找对应的货位
*
* @param attrList 仓位集合
* @param jsonParammaterialId 物料标识weight: 重量
* @return List<Structattr> 仓位集合
*/
private List<Structattr> inHandler(List<Structattr> attrList, JSONObject jsonParam) {
// 过滤对应的货位
return attrList.stream()
.filter(row -> row.getWeight().doubleValue() <= jsonParam.getDoubleValue("weight"))
.sorted(Comparator.comparing(Structattr::getWeight))
.collect(Collectors.toList());
}
/**
* 出库策略默认出库
* @param attrList 仓位物料信息
* @param jsonParamiostorinvdtlId 出入库明细标识此方法只根据时间匹配
* @return List<Structattr> 需出库仓位集合
*/
// private List<Structattr> outHandler(List<Structattr> attrList, JSONObject jsonParam) {
//
// // 查询对应的出入库明细
// StIvtIostorinvdtlIn dtlDao = iStIvtIostorinvdtlService.getById(jsonParam.getString("iostorinvdtlId"));
//
// // 查询传入仓位物料中的数量是否满足明细中的数量
// List<String> vehicleCodeIn = attrList.stream()
// .map(Structattr::getStoragevehicle_code)
// .distinct()
// .collect(Collectors.toList());
//
// // 查询对应的载具物料
// List<MdPbStoragevehicleext> extList = iMdPbStoragevehicleextService.list(
// new QueryWrapper<MdPbStoragevehicleext>().lambda()
// .in(MdPbStoragevehicleext::getStoragevehicle_code, vehicleCodeIn)
// );
//
// double attrQty = extList.stream()
// .map(MdPbStoragevehicleext::getQty)
// .reduce(BigDecimal.ZERO, BigDecimal::add)
// .doubleValue();
//
// if (dtlDao.getUnassign_qty().doubleValue() > attrQty) {
// // 说明不满足所需重量则全部返回
// return attrList;
// }
//
// // 需返回仓位物料集合
// List<Structattr> resultList = new ArrayList<>();
// // 满足所需数量: 根据巷道进行平均分配
// double unAssingQty = dtlDao.getUnassign_qty().doubleValue();
//
// while (unAssingQty > 0) {
//
// // 添加需返回的仓位物料
// Structattr attrDao = attrList.get(0);
// resultList.add(attrDao);
//
// // 减去未分配重量
// MdPbStoragevehicleext extDao = extList.stream()
// .filter(row -> row.getStoragevehicle_code().equals(attrDao.getStoragevehicle_code()))
// .findFirst().orElse(null);
//
// if (ObjectUtil.isEmpty(extDao)) {
// throw new BadRequestException("未查询到载具对应的物料【"+attrDao.getStoragevehicle_code()+"】");
// }
//
// unAssingQty = NumberUtil.sub(unAssingQty,extDao.getQty().doubleValue());
//
// // 移出此仓位物料,方便下一轮进行匹配
// attrList.remove(attrDao);
// }
//
// return resultList;
// }
}

20
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/base/出入库基础规则.md

@ -0,0 +1,20 @@
##货位分配原则 出入库
###1、上轻下重原则
根据货物重量选择摆放位置。把重的东西放在下层,把轻放在货架上层。需要人工搬运的大型货物以腰部的高度摆放。这样提高效率、保证安全。
###2、优先靠近出入口原则
根据出入库频率选定位置。出入库频率高的货物应放在靠近出入口,易于作业的地方;流动性差的货物放在离出入口较远的地方;季节性物品按季节特性来选定场所摆放。
###3、先进先出原则
一般企业为了加快周转,先入先出一同种物料出库时,先入库的物资,需要先提取出库,以加快物料周转,从而避免因物料长期积压产生锈蚀、变形、变质及其他损坏造成的损失。因此在货位分配时要方便先进物品优先出库。
###4、同类物品集中原则
同一品种同一地方保管。为提高作业效率和保管效率同一物品或类似物品应在同一地方保管,提高仓储工作效率。
###5、多巷道分布原则
货位分配是应提高可靠性,分巷道存放一仓库有多个巷道时,同种物品分散在不同的巷道进行存放。以防止因某巷道堵塞影响某种物料的出库,造成生产中断。
###6.超限分配原则:
对于货位超限:横向/纵向暂用多个货位.高度超限
##规则处理方式:责任链模式
list->5
1->list->2->list->3->list list.get(0)
class
List<> handler(List<货位集合>,入库物料信息)

16
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/ClassRuleHandler.java

@ -0,0 +1,16 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import java.util.List;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 自定义类处理器
*/
public class ClassRuleHandler extends Decisioner<String,String> {
@Override
public List<String> handler(List<String> list, String param) {
System.out.println("迭代器使用中"+this.toString());
return null;
}
}

138
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/DepthPriorityHandler.java

@ -0,0 +1,138 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.config.SpringContextHolder;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.nl.wms.sch_manage.enums.StatusEnum;
import org.springframework.stereotype.Service;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/*
*深位优先
* @author ZZQ
* @Date 2024/7/31 15:19
*/
@Service("depthPriority")
@Slf4j
public class DepthPriorityHandler extends Decisioner<Structattr, JSONObject> {
public DepthPriorityHandler() {
}
//现场1/4排深位
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
if (CollectionUtils.isNotEmpty(list)) {
//托盘库和扩展库不需要深位判断
if (list.get(0).getStor_code().equals(StatusEnum.STOCK_INFO.code("托盘库")) || "LXBCP02".equals(list.get(0).getSect_code())) {
return list;
}
}
long startTime1 = System.currentTimeMillis();
List<Structattr> returnResult = new ArrayList<>();
// 深货位
List<Structattr> depCollect = list.stream()
.filter(a -> a.getRow_num().intValue() == 1 || a.getRow_num().intValue() == 4)
.collect(Collectors.toList());
// 浅货位
List<Structattr> shallowCollect = list.stream()
.filter(a -> a.getRow_num().intValue() == 2 || a.getRow_num().intValue() == 3)
.collect(Collectors.toList());
for (Structattr r : depCollect) {
for (Structattr s : shallowCollect) {
String depCode = r.getCol_num() + "-" + r.getLayer_num();
String shallowCode = s.getCol_num() + "-" + s.getLayer_num();
if ((r.getRow_num().intValue() == 1 && s.getRow_num().intValue() == 2) ||
(r.getRow_num().intValue() == 4 && s.getRow_num().intValue() == 3)) {
if (depCode.equals(shallowCode)) {
returnResult.add(r);
}
}
}
}
if (returnResult.size() > 0) {
if (returnResult.size() < 3) {
return getOtherStructattr(list, param, startTime1, depCollect);
} else {
log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 存在深位并对应浅位无货的库位,分配仓位:" + returnResult.get(0).getStruct_code());
log.info("深位优先策略:载具号:"+param.getString("vehicle_code")+"获取深货位且浅货位无货仓位耗时:{}", System.currentTimeMillis() - startTime1);
return returnResult;
}
} else {
return getOtherStructattr(list, param, startTime1, depCollect);
}
}
private static List<Structattr> getOtherStructattr(List<Structattr> list, JSONObject param, long startTime1, List<Structattr> depCollect) {
// if (!depCollect.isEmpty()) {
// log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 存在深位无货但对应浅位有货的库位,需要移库,分配仓位:" + depCollect.get(0).getStruct_code());
// log.info("深位优先策略:获取深货位无货且浅货位有货仓位耗时:{}", System.currentTimeMillis() - startTime1);
// return depCollect;
// }
//浅货位,则需要判断对应
IStructattrService iStructattrService = SpringContextHolder.getBean(IStructattrService.class);
if (list.get(0).getStor_code().equals(StatusEnum.STOCK_INFO.code("料箱库"))) {
List<Structattr> list1 = iStructattrService.list(new LambdaUpdateWrapper<Structattr>()
.in(Structattr::getRow_num, Arrays.asList(1, 4))
.eq(Structattr::getStor_code, StatusEnum.STOCK_INFO.code("料箱库"))
.eq(Structattr::getIs_used, 1)
.eq(Structattr::getLock_type, StatusEnum.LOCK.code("无锁")));
//先找2排的再找3排的
if (!list1.isEmpty()) {
List<Structattr> combinedResult = new ArrayList<>();
//1排
List<Structattr> deepCollect1 = list1.stream()
.filter(a -> a.getRow_num().intValue() == 1)
.collect(Collectors.toList());
List<Structattr> shallowCollect1 = list.stream()
.filter(a -> a.getRow_num().intValue() == 2)
.collect(Collectors.toList());
Set<String> deepCollect1Set = deepCollect1.stream()
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
.collect(Collectors.toSet());
List<Structattr> intersection1 = shallowCollect1.stream()
.filter(r ->deepCollect1Set.contains(r.getCol_num() + "_" + r.getLayer_num()))
.collect(Collectors.toList());
if (!intersection1.isEmpty()) {
combinedResult.addAll(intersection1);
} else {
//4排
List<Structattr> deepCollect2 = list1.stream()
.filter(a -> a.getRow_num().intValue() == 4)
.collect(Collectors.toList());
List<Structattr> shallowCollect2 = list.stream()
.filter(a -> a.getRow_num().intValue() == 3)
.collect(Collectors.toList());
Set<String> deepCollect2Set = deepCollect2.stream()
.map(r -> r.getCol_num() + "_" + r.getLayer_num())
.collect(Collectors.toSet());
List<Structattr> intersection2 = shallowCollect2.stream()
.filter(r -> deepCollect2Set.contains(r.getCol_num() + "_" + r.getLayer_num()))
.collect(Collectors.toList());
combinedResult.addAll(intersection2);
}
if (CollectionUtils.isEmpty(combinedResult)) {
log.error("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位数量为0!");
throw new BadRequestException("深位优先策略:获取深货位有货且浅货位无货仓位:载具号:" + param.getString("vehicle_code") + "获取仓位失败,该策略对应库位数量为0!");
}
log.info("深位优先策略:载具号:" + param.getString("vehicle_code") + "分配结果: 深货位有货且浅货位无货仓位,无需移库,分配仓位:" + combinedResult.get(0).getStruct_code());
log.info("深位优先策略:获取深货位有货且浅货位无货仓位耗时:{}", System.currentTimeMillis() - startTime1);
return combinedResult;
}
return list;
} else {
return list;
}
}
}

93
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/InventoryRuleHandler.java

@ -0,0 +1,93 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.apache.commons.lang3.StringUtils;
import org.nl.common.exception.BadRequestException;
import org.nl.common.utils.MapOf;
import org.nl.wms.basedata_manage.service.IStructattrService;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.nl.wms.sch_manage.enums.StatusEnum;
import org.nl.wms.sch_manage.service.ISchBaseTaskService;
import org.nl.wms.sch_manage.service.dao.SchBaseTask;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.stream.Collectors;
/*
* @author ZZQ
* @Date 2024/4/6 16:18
* 入库双叉分配测策略
*/
@Service("inventory")
public class InventoryRuleHandler extends Decisioner<Structattr, JSONObject> {
private static final Map<String, String> LINK_POINT = MapOf.of("1109", "1110", "1110", "1109");
//每个策略的配置信息
/**
* 出入库明细服务
*/
@Autowired
private IStructattrService iStructattrService;
@Autowired
private ISchBaseTaskService taskService;
@Autowired
private IStructattrService StructattrService;
/**
* 载具扩展属性服务服务
*/
/**
* 就近放置策略根据出入库顺序进行判断
*
* @param list 仓位集合
* @param param物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
if (CollectionUtils.isEmpty(list)) {
throw new BadRequestException("当前分配策略无可用货位");
}
String start_point = param.getString("start_point");
String target = LINK_POINT.get(start_point);
if (StringUtils.isNotEmpty(target)){
LambdaQueryWrapper<SchBaseTask> lqw = new LambdaQueryWrapper<>();
lqw.eq(SchBaseTask::getPoint_code1, target)
.lt(SchBaseTask::getTask_status, StatusEnum.FORM_STATUS.code("执行中"));
List<SchBaseTask> tasks = taskService.list(lqw);
for (SchBaseTask task : tasks) {
String point_code2 = task.getPoint_code2();
List new_list = getInventory(list, point_code2);
if (!CollectionUtils.isEmpty(new_list)) {
return new_list;
}
}
}
return list;
}
private List<Structattr> getInventory(List<Structattr> list, String point_code2) {
Structattr structattr = StructattrService.getOne(new LambdaQueryWrapper<Structattr>().eq(Structattr::getStruct_code, point_code2).eq(Structattr::getIs_used, true));
return Optional.ofNullable(list)
.orElse(new CopyOnWriteArrayList<>())
.stream()
.filter(stru -> stru.getRow_num().equals(structattr.getRow_num()) && stru.getLayer_num().equals(structattr.getLayer_num()))
.filter(stru -> (stru.getCol_num().intValue() / 4 == structattr.getCol_num().intValue() / 4) && (((stru.getCol_num().intValue() % 4) + (structattr.getCol_num().intValue() % 4) == 2) || (stru.getCol_num().intValue() % 4) + (structattr.getCol_num().intValue() % 4) == 4))
.collect(Collectors.toList());
}
}

69
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/PassRCLHandler.java

@ -0,0 +1,69 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* 手动过滤XYZ排信息
* {"y":[1,2,3,104,103,102]}
*/
@Service("passRCL")
@Slf4j
public class PassRCLHandler extends Decisioner<Structattr, JSONObject> {
//现场1/4排深位
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
String configParam = this.strategyConfig.getParam();
JSONObject jsonP = JSONObject.parseObject(configParam);
List x = jsonP.getObject("x", List.class);
List y = jsonP.getObject("y", List.class);
List z = jsonP.getObject("z", List.class);
Stream<Structattr> stream = list.stream();
if (!CollectionUtils.isEmpty(x)){
stream = stream.filter(Structattr -> !x.contains(Structattr.getRow_num()));
}
if (!CollectionUtils.isEmpty(y)){
stream = stream.filter(Structattr -> !y.contains(Structattr.getCol_num()));
}
if (!CollectionUtils.isEmpty(z)){
stream = stream.filter(Structattr -> !z.contains(Structattr.getLayer_num()));
}
List<Structattr> collect = stream.collect(Collectors.toList());
log.info("手动过滤XYZ排信息策略过滤数量:"+(list.size()-collect.size()));
return collect;
}
// public static void main(String[] args) {
// List<Structattr> list = new ArrayList<>();
// for (int i =0;i<10;i++){
// Structattr structattr = new Structattr();
// structattr.setRow_num(new Random().nextInt(2)+1);
// structattr.setCol_num(new Random().nextInt(10)+1);
// structattr.setLayer_num(new Random().nextInt(2)+1);
// list.add(structattr);
// }
// System.out.println(list);
// String configParam = "{\"z\":[2]}";
// JSONObject jsonP = JSONObject.parseObject(configParam);
// List x = jsonP.getObject("x", List.class);
// List y = jsonP.getObject("y", List.class);
// List z = jsonP.getObject("z", List.class);
// Stream<Structattr2> stream = list.stream();
// if (!CollectionUtils.isEmpty(x)){
// stream = stream.filter(Structattr -> !x.contains(Structattr.getRow_num()));
// }
// if (!CollectionUtils.isEmpty(y)){
// stream = stream.filter(Structattr -> !y.contains(Structattr.getCol_num()));
// }
// if (!CollectionUtils.isEmpty(z)){
// stream = stream.filter(Structattr -> !z.contains(Structattr.getLayer_num()));
// }
// List<Structattr2> collect = stream.collect(Collectors.toList());
// System.out.println(collect);
// }
}

76
nladmin-system/nlsso-server/src/main/java/org/nl/wms/decision_manage/service/strategyConfig/decisioner/impl/diy/SameBlockNumRuleHandler.java

@ -0,0 +1,76 @@
package org.nl.wms.decision_manage.service.strategyConfig.decisioner.impl.diy;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.nl.common.exception.BadRequestException;
import org.nl.wms.basedata_manage.service.dao.Structattr;
import org.nl.wms.decision_manage.service.strategyConfig.decisioner.Decisioner;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
/*
* @author GBX
* @Date 2025/2/1 16:18
* 相同巷道自下而上分配,左右相邻
*/
@Service("sameBlockNum")
@Slf4j
public class SameBlockNumRuleHandler extends Decisioner<Structattr, JSONObject> {
/**
* 相同巷道自下而上分配提高CTU放货效率
*
* @param list 仓位集合
* @param param出入库单明细物料相关信息出入类型{ ioType: 出入类型
* materialId: 物料标识
* ...
* }
* @return List<Structattr> 仓位集合
*/
@Override
public List<Structattr> handler(List<Structattr> list, JSONObject param) {
// 判断仓位是否为空
if (CollectionUtils.isEmpty(list)) {
throw new BadRequestException("当前分配策略sameBlockNum无可用货位");
}
// 1. 找出最小巷道号
BigDecimal minBlockNum = list.stream()
.map(Structattr::getBlock_num)
.min(BigDecimal::compareTo)
.orElseThrow(() -> new BadRequestException("未找到可用的巷道"));
// 2. 筛选出这个巷道的所有结构,按列 -> 层排序
List<Structattr> blockList = list.stream()
.filter(item -> item.getBlock_num().compareTo(minBlockNum) == 0)
.sorted(Comparator
.comparing(Structattr::getCol_num)
.thenComparing(Structattr::getLayer_num))
.collect(Collectors.toList());
List<Structattr> result = new ArrayList<>();
// 3. 找出所有层号(去重 + 升序)
Set<BigDecimal> allLayers = blockList.stream()
.map(Structattr::getLayer_num)
.collect(Collectors.toCollection(TreeSet::new)); // 自动排序
// 4. 从小层号开始,尝试找同一列的货位
for (BigDecimal layer : allLayers) {
List<Structattr> currentLayer = blockList.stream()
.filter(item -> item.getLayer_num().compareTo(layer) == 0)
.collect(Collectors.toList());
if (!currentLayer.isEmpty()) {
result.addAll(currentLayer);
break; // 找到一层就跳出
}
}
// 5. 如果没找到符合的,就用全部 blockList
if (result.isEmpty()) {
result.addAll(blockList);
}
return result;
}
}

2
nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/PmFormData.java

@ -192,7 +192,7 @@ public class PmFormData implements Serializable {
* 单重
*/
@TableField(exist = false)
private String single_weight;
private String net_weight;
/**

4
nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/mapper/PmFormDataMapper.java

@ -27,7 +27,6 @@ public interface PmFormDataMapper extends BaseMapper<PmFormData> {
List<PmFormDataDto> queryTree2(@Param("query") FormDataQuery query);
List<PmFormDataDto> queryCtuOrderList(@Param("query") FormDataQuery query);
List<PmFormDataDto> selectChilds(List<String> parents);
@ -36,9 +35,6 @@ public interface PmFormDataMapper extends BaseMapper<PmFormData> {
void dynamicSql(@Param("sql") String sql);
Set<String> existFormDataList(@Param("form_type") String form_type);
Set<String> existFormCodeDataList();
BigDecimal queryTreeCounts(@Param("query") FormDataQuery query);

264
nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dao/mapper/xml/PmFormDataMapper.xml

@ -1,30 +1,246 @@
<?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="org.nl.wms.pm_manage.form_data.service.dao.PmFormDataDao">
<mapper namespace="org.nl.wms.pm_manage.form_data.service.dao.mapper.PmFormDataMapper">
<resultMap id="BaseResultMap" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData">
<!--
WARNING - This element is automatically generated by MyBatis Generator !
Do not modify this file directly, any changes will be overwritten.
-->
<id column="id" property="id" jdbcType="BIGINT"/>
<result property="form_id" column="form_id" jdbcType="BIGINT"/>
<result property="form_type" column="form_type" jdbcType="VARCHAR"/>
<result property="status" column="status" jdbcType="VARCHAR"/>
<result property="create_name" column="create_name" jdbcType="VARCHAR"/>
<result property="create_time" column="create_time" jdbcType="TIMESTAMP"/>
<result property="material_id" column="material_id" jdbcType="BIGINT"/>
<result property="qty" column="qty" jdbcType="DECIMAL"/>
<result property="pcsn" column="pcsn" jdbcType="VARCHAR"/>
<result property="vehicle_code" column="vehicle_code" jdbcType="VARCHAR"/>
<result property="parent_id" column="parent_id" jdbcType="BIGINT"/>
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
<result property="unit_id" column="unit_id" jdbcType="BIGINT"/>
<result property="id" column="id"/>
<result property="code" column="code"/>
<result property="proc_inst_id" column="proc_inst_id"/>
<result property="source_form_type" column="source_form_type"/>
<result property="source_form_id" column="source_form_id"/>
<result property="source_form_date" column="source_form_date"/>
<result property="form_type" column="form_type"/>
<result property="status" column="status"/>
<result property="create_name" column="create_name"/>
<result property="create_time" column="create_time"/>
<result property="material_id" column="material_id"/>
<result property="qty" column="qty"/>
<result property="pcsn" column="pcsn"/>
<result property="vehicle_code" column="vehicle_code"/>
<result property="parent_id" column="parent_id"/>
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
<result property="unit_id" column="unit_id"/>
</resultMap>
<resultMap id="ResultMapWithBLOBs" type="org.nl.wms.pm_manage.form_data.service.dao.PmFormData" extends="BaseResultMap">
<!--
WARNING - This element is automatically generated by MyBatis Generator !
Do not modify this file directly, any changes will be overwritten.
-->
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
<resultMap id="dataDetail" type="org.nl.wms.pm_manage.form_data.service.dto.PmFormDataDto" >
<result property="id" column="id"/>
<result property="code" column="code"/>
<result property="proc_inst_id" column="proc_inst_id"/>
<result property="source_form_type" column="source_form_type"/>
<result property="source_form_id" column="source_form_id"/>
<result property="source_form_type" column="source_form_type"/>
<result property="form_type" column="form_type"/>
<result property="status" column="status"/>
<result property="remark" column="remark"/>
<result property="create_name" column="create_name"/>
<result property="create_time" column="create_time"/>
<result property="material_id" column="material_id"/>
<result property="qty" column="qty"/>
<result property="assign_qty" column="assign_qty"/>
<result property="plan_qty" column="plan_qty"/>
<result property="pcsn" column="pcsn"/>
<result property="material_code" column="material_code"/>
<result property="material_name" column="material_name"/>
<result property="material_spec" column="material_spec"/>
<result property="net_weight" column="net_weight"/>
<result property="vehicle_code" column="vehicle_code"/>
<result property="vehicle_id" column="vehicle_id"/>
<result property="parent_id" column="parent_id"/>
<result property="form_data" column="form_data" typeHandler="org.nl.common.domain.handler.FastjsonSortTypeHandler"/>
<result property="unit_id" column="unit_id"/>
<result property="unit_name" column="unit_name"/>
<!-- <result property="HasChildren" column="HasChildren"/>-->
</resultMap>
<select id="query" resultMap="BaseResultMap">
SELECT
child.*
FROM
pm_form_data child
<where>
<if test="query.form_type != null and query.form_type != ''">
and form_type = #{query.form_type}
</if>
<if test="query.form_query != null and query.form_query.size() > 0">
<foreach collection="query.form_query" item="value" index="key" >
<if test="value != null and value != ''">
and JSON_CONTAINS(child.form_data, '{"${key}":"${value}"}')
</if>
</foreach>
</if>
</where>
</select>
<select id="queryTree" resultMap="dataDetail">
SELECT
pm_form_data.*,
md_me_materialbase.material_code,
md_me_materialbase.material_name,
md_me_materialbase.material_spec,
md_me_materialbase.net_weight
FROM
pm_form_data
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
<where>
<if test="query.form_type != null and query.form_type != ''">
and form_type = #{query.form_type}
</if>
<if test="query.status != null and query.status != ''">
and pm_form_data.status IN
<foreach collection="query.status" item="status" separator="," open="(" close=")">
#{status}
</foreach>
</if>
<if test="query.parent_id != null and query.parent_id != ''">
and parent_id = #{query.parent_id}
</if>
<if test="query.form_query != null and query.form_query.size() > 0">
<foreach collection="query.form_query" item="value" index="key" >
<if test="value != null and value != ''">
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
</if>
</foreach>
</if>
</where>
ORDER BY create_time DESC
</select>
<select id="queryTree2" resultMap="dataDetail">
SELECT
pm_form_data.*,
md_me_materialbase.material_code,
md_me_materialbase.material_name,
md_me_materialbase.material_spec,
md_me_materialbase.net_weight
FROM
pm_form_data
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
<where>
<if test="query.search != null and query.search != ''">
and form_data LIKE '%${query.search}%'
</if>
<if test="query.form_type != null and query.form_type != ''">
and form_type = #{query.form_type}
</if>
<if test="query.pcsn != null and query.pcsn != ''">
and pcsn = #{query.pcsn}
</if>
<if test="query.code != null and query.code != ''">
and code LIKE '%${query.code}'
</if>
<if test="query.bill_code != null and query.bill_code != ''">
and source_form_date = #{query.bill_code}
</if>
<if test="query.mater != null and query.mater != ''">
and md_me_materialbase.material_code like '%${query.mater}%'
</if>
<if test="query.start_time != null and query.start_time != ''">
and pm_form_data.create_time >= #{query.start_time}
</if>
<if test="query.end_time != null and query.end_time != ''">
and #{query.end_time} >= pm_form_data.create_time
</if>
<if test="query.status != null and query.status != ''">
and pm_form_data.status IN
<foreach collection="query.status" item="status" separator="," open="(" close=")">
#{status}
</foreach>
</if>
<if test="query.parent_id != null and query.parent_id != ''">
and parent_id = #{query.parent_id}
</if>
<if test="query.form_query != null and query.form_query.size() > 0">
<foreach collection="query.form_query" item="value" index="key">
<if test="value != null and value != ''">
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
</if>
</foreach>
</if>
</where>
ORDER BY create_time DESC
</select>
<select id="queryTreeCounts" resultType="java.math.BigDecimal">
SELECT
SUM(pm_form_data.qty) as counts
FROM
pm_form_data
left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
<where>
<if test="query.search != null and query.search != ''">
and form_data LIKE '%${query.search}%'
</if>
<if test="query.form_type != null and query.form_type != ''">
and form_type = #{query.form_type}
</if>
<if test="query.pcsn != null and query.pcsn != ''">
and pcsn = #{query.pcsn}
</if>
<if test="query.code != null and query.code != ''">
and code LIKE '%${query.code}'
</if>
<if test="query.bill_code != null and query.bill_code != ''">
and source_form_date = #{query.bill_code}
</if>
<if test="query.mater != null and query.mater != ''">
and md_me_materialbase.material_code like '%${query.mater}%'
</if>
<if test="query.start_time != null and query.start_time != ''">
and pm_form_data.create_time >= #{query.start_time}
</if>
<if test="query.end_time != null and query.end_time != ''">
and #{query.end_time} >= pm_form_data.create_time
</if>
<if test="query.status != null and query.status != ''">
and pm_form_data.status IN
<foreach collection="query.status" item="status" separator="," open="(" close=")">
#{status}
</foreach>
</if>
<if test="query.parent_id != null and query.parent_id != ''">
and parent_id = #{query.parent_id}
</if>
<if test="query.form_query != null and query.form_query.size() > 0">
<foreach collection="query.form_query" item="value" index="key">
<if test="value != null and value != ''">
and JSON_CONTAINS(form_data, '{"${key}":"${value}"}')
</if>
</foreach>
</if>
</where>
ORDER BY create_time DESC
</select>
<select id="selectChild" resultMap="dataDetail">
select
pm_form_data.*,
md_me_materialbase.material_code,
md_me_materialbase.material_name,
md_me_materialbase.material_spec,
md_me_materialbase.net_weight
from pm_form_data left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
where parent_id = #{id}
</select>
<select id="selectChilds" resultMap="dataDetail">
select
pm_form_data.*,
md_me_materialbase.material_code,
md_me_materialbase.material_name,
md_me_materialbase.material_spec,
md_me_materialbase.net_weight,
md_pb_measureunit.unit_name
from pm_form_data left join md_me_materialbase on pm_form_data.material_id = md_me_materialbase.material_id
left join md_pb_measureunit on pm_form_data.unit_id = md_pb_measureunit.measure_unit_id
where parent_id in
<foreach collection="parents" open="(" close=")" item="parent_id" separator=",">
#{parent_id}
</foreach>
</select>
<select id="existFormDataList" resultType="java.lang.String">
SELECT id
FROM pm_form_data
WHERE form_type LIKE CONCAT('%', #{form_type}, '%')
</select>
<select id="existFormCodeDataList" resultType="java.lang.String">
SELECT code
FROM pm_form_data
WHERE DATE(create_time) = CURDATE()
</select>
</mapper>

2
nladmin-system/nlsso-server/src/main/java/org/nl/wms/pm_manage/form_data/service/dto/PmFormDataDto.java

@ -102,7 +102,7 @@ public class PmFormDataDto implements Serializable {
/**
* 物料单重
*/
private String single_weight;
private String net_weight;
/**
* 单据编号
*/

6
nladmin-system/nlsso-server/src/main/resources/db/migration/V1.0__schema.sql

@ -278,7 +278,7 @@ CREATE TABLE `md_base_material` (
`material_name` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NOT NULL COMMENT '物料名称 ',
`material_spec` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '物料规格',
`material_model` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '物料型号',
`single_weight` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '单重 / 吨',
`net_weight` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT '单重 / 吨',
`a_long_side` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'A长边',
`b_short_side` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'B短边',
`h_height` varchar(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL COMMENT 'H高度',
@ -303,8 +303,8 @@ CREATE TABLE `md_base_material` (
`matsize` varchar(50) CHARACTER SET utf8mb3 COLLATE utf8mb3_bin NULL DEFAULT NULL,
`standing_time_lower` decimal(5, 0) NULL DEFAULT NULL,
`standing_time_upper` decimal(5, 0) NULL DEFAULT NULL,
`single_weight_upper` decimal(5, 0) NULL DEFAULT NULL,
`single_weight_lower` decimal(5, 0) NULL DEFAULT NULL,
`net_weight_upper` decimal(5, 0) NULL DEFAULT NULL,
`net_weight_lower` decimal(5, 0) NULL DEFAULT NULL,
`standard_size_height1` decimal(5, 0) NULL DEFAULT NULL,
`standard_size_height1_lower` decimal(5, 0) NULL DEFAULT NULL,
`standard_size_height1_upper` decimal(5, 0) NULL DEFAULT NULL,

137
nladmin-ui/src/views/wms/pm_manage/form_data/index.vue

@ -2,7 +2,7 @@
<div class="app-container">
<!--工具栏-->
<div class="head-container">
<div v-if="crud.props.searchToggle">
<div>
<!-- 搜索 -->
<el-form
:inline="true"
@ -13,7 +13,7 @@
>
<el-form-item label="单据类型">
<el-select
v-model="query.form_type"
v-model="query.bill_type"
filterable
size="mini"
placeholder="请选择/搜索"
@ -22,46 +22,78 @@
@change="crud.toQuery()"
>
<el-option
v-for="item in fromTypes"
v-for="item in dict.INANDOUT_BILL_TYPE"
:key="item.value"
:label="item.label"
:value="item.value"
:label="item.lable"
/>
</el-select>
</el-form-item>
<el-form-item label="单据编码">
<el-input
v-model="query.code"
clearable
size="mini"
placeholder="编码"
@keyup.enter.native="crud.toQuery"
/>
</el-form-item>
<el-form-item label="单据状态">
<el-select
v-model="query.status"
clearable
size="mini"
placeholder="单据状态"
class="filter-item"
clearable
@change="crud.toQuery()"
@change="crud.toQuery"
>
<el-option
v-for="item in statusEnum.FORM_STATUS"
v-for="item in dict.io_bill_status"
:key="item.value"
:label="item.label"
:value="item.value"
/>
</el-select>
</el-form-item>
<template v-for="(col,index) in cols" v-if="hideShowDialog">
<el-form-item label="col.lable">
<label slot="label">{{ col.lable }}:</label>
<el-input v-model="query.form_query[col.value]" :value="col.value" clearable style="width: 210px" />
</el-form-item>
</template>
<el-form-item label="单据编码">
<el-input
v-model="query.code"
clearable
size="mini"
placeholder="编码"
@keyup.enter.native="crud.toQuery"
/>
</el-form-item>
<el-form-item label="物料编码">
<el-input
v-model="query.mater"
clearable
style="width: 250px"
size="mini"
placeholder="请输入物料编码"
prefix-icon="el-icon-search"
class="filter-item"
/>
</el-form-item>
<el-form-item label="批次">
<el-input
v-model="query.pcsn"
clearable
size="mini"
placeholder="请输入批次"
prefix-icon="el-icon-search"
class="filter-item"
/>
</el-form-item>
<el-form-item label="单据日期" prop="analyseData">
<el-date-picker
v-model="query.datepick"
type="daterange"
value-format="yyyy-MM-dd"
range-separator="至"
start-placeholder="开始日期"
end-placeholder="结束日期"
/>
</el-form-item>
<!-- <template v-for="(col,index) in cols" v-if="hideShowDialog">-->
<!-- <el-form-item label="col.lable">-->
<!-- <label slot="label">{{ col.lable }}:</label>-->
<!-- <el-input v-model="query.form_query[col.value]" :value="col.value" clearable style="width: 210px" />-->
<!-- </el-form-item>-->
<!-- </template>-->
<rrOperation :crud="crud" />
</el-form>
</div>
@ -189,6 +221,7 @@ import ViewDialog from './ViewDialog'
const defaultForm = {
id: null,
code: null,
bill_type: null,
proc_inst_id: null,
biz_id: null,
boz_code: null,
@ -204,12 +237,12 @@ const defaultForm = {
from_data: null,
parent_id: null
}
export default {
name: 'FormData',
dicts: ['base_data'],
dicts: ['base_data', 'ST_INV_IN_TYPE', 'INANDOUT_BILL_TYPE', 'io_bill_status'],
components: { pagination, crudOperation, rrOperation, udOperation, ViewDialog },
mixins: [presenter(), header(), form(defaultForm), crud()],
statusEnums: ['FORM_STATUS'],
cruds() {
return CRUD({
title: '表单数据',
@ -231,7 +264,7 @@ export default {
cols: [],
classes: [],
uploadShow: false,
fromTypes: [],
// fromTypes: [],
permission: {},
rules: {},
hideShowDialog: false,
@ -257,39 +290,39 @@ export default {
},
created() {
//
this.getFromTypes()
// this.getFromTypes()
},
mounted() {
},
methods: {
[CRUD.HOOK.beforeRefresh]() {
if (this.fromTypes.length > 0) {
// formstruc.getHeader(this.query.form_type).then(res => {
// this.cols = res
// res.forEach(a => {
// this.form.form_data[a.value, '']
// this.$set(this.query, 'form_query', {})
// })
// })
// return true
}
return false
},
getFromTypes() {
crudFormData.getParentFormTypes().then((res) => { //
this.fromTypes = res
if (this.fromTypes.length > 0) {
this.$set(this.query, 'form_type', this.fromTypes[0].value)
this.crud.toQuery()
}
})
},
hideShow() {
if (this.hideShowDialog) {
// this.$set(this.query, 'form_query', {})
}
this.hideShowDialog = !this.hideShowDialog
// if (this.fromTypes.length > 0) {
// // formstruc.getHeader(this.query.form_type).then(res => {
// // this.cols = res
// // res.forEach(a => {
// // this.form.form_data[a.value, '']
// // this.$set(this.query, 'form_query', {})
// // })
// // })
// // return true
// }
// return false
},
// getFromTypes() {
// crudFormData.getParentFormTypes().then((res) => { //
// this.fromTypes = res
// if (this.fromTypes.length > 0) {
// this.$set(this.query, 'form_type', this.fromTypes[0].value)
// this.crud.toQuery()
// }
// })
// },
// hideShow() {
// if (this.hideShowDialog) {
// // this.$set(this.query, 'form_query', {})
// }
// this.hideShowDialog = !this.hideShowDialog
// },
toView(row) {
if (row !== null) {
this.$refs.viewDialog.setForm(row)

Loading…
Cancel
Save