Compare commits
10 Commits
2b7e91e918
...
14944d2a99
| Author | SHA1 | Date | |
|---|---|---|---|
| 14944d2a99 | |||
| a82797c475 | |||
| f8600107ec | |||
| 79807279c1 | |||
| e4f617fc99 | |||
| 1a565dba0d | |||
| c3731b8b31 | |||
| 5d227b7b6b | |||
| f3d993b33a | |||
| 048d52b449 |
1
pom.xml
1
pom.xml
@@ -15,7 +15,6 @@
|
|||||||
<packaging>jar</packaging>
|
<packaging>jar</packaging>
|
||||||
|
|
||||||
<name>zg</name>
|
<name>zg</name>
|
||||||
<url>http://www.zg.vip</url>
|
|
||||||
<description>智慧实物管理系统</description>
|
<description>智慧实物管理系统</description>
|
||||||
|
|
||||||
<!-- ======================= -->
|
<!-- ======================= -->
|
||||||
|
|||||||
@@ -1116,6 +1116,9 @@ public class ExcelUtil<T>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 添加单元格
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* 添加单元格
|
* 添加单元格
|
||||||
*/
|
*/
|
||||||
@@ -1126,11 +1129,13 @@ public class ExcelUtil<T>
|
|||||||
{
|
{
|
||||||
// 设置行高
|
// 设置行高
|
||||||
row.setHeight(maxHeight);
|
row.setHeight(maxHeight);
|
||||||
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
|
|
||||||
|
// 根据Excel中设置情况决定是否导出
|
||||||
if (attr.isExport())
|
if (attr.isExport())
|
||||||
{
|
{
|
||||||
// 创建cell
|
// 创建cell
|
||||||
cell = row.createCell(column);
|
cell = row.createCell(column);
|
||||||
|
|
||||||
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
|
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
|
||||||
{
|
{
|
||||||
if (subMergedLastRowNum >= subMergedFirstRowNum)
|
if (subMergedLastRowNum >= subMergedFirstRowNum)
|
||||||
@@ -1138,14 +1143,45 @@ public class ExcelUtil<T>
|
|||||||
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
|
sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
|
cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
|
||||||
|
|
||||||
// 用于读取对象中的属性
|
// 用于读取对象中的属性
|
||||||
Object value = getTargetValue(vo, field, attr);
|
Object value = getTargetValue(vo, field, attr);
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// ✅ BigDecimal:按“实际几位显示几位”,去掉末尾0(核心修改点)
|
||||||
|
// =========================
|
||||||
|
if (value instanceof BigDecimal)
|
||||||
|
{
|
||||||
|
BigDecimal bd = (BigDecimal) value;
|
||||||
|
|
||||||
|
if (-1 != attr.scale())
|
||||||
|
{
|
||||||
|
bd = bd.setScale(attr.scale(), attr.roundingMode());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 去掉末尾0:1.000000 -> 1,1.2300 -> 1.23
|
||||||
|
String text = bd.stripTrailingZeros().toPlainString();
|
||||||
|
|
||||||
|
// 强制按字符串写入,避免 Excel 数值格式导致显示成固定小数位
|
||||||
|
cell.setCellType(CellType.STRING);
|
||||||
|
cell.setCellValue(StringUtils.isEmpty(text) ? attr.defaultValue() : text + attr.suffix());
|
||||||
|
|
||||||
|
// 统计
|
||||||
|
addStatisticsData(column, text, attr);
|
||||||
|
|
||||||
|
return cell;
|
||||||
|
}
|
||||||
|
|
||||||
|
// =========================
|
||||||
|
// 原有逻辑(非 BigDecimal)保持不变
|
||||||
|
// =========================
|
||||||
String dateFormat = attr.dateFormat();
|
String dateFormat = attr.dateFormat();
|
||||||
String readConverterExp = attr.readConverterExp();
|
String readConverterExp = attr.readConverterExp();
|
||||||
String separator = attr.separator();
|
String separator = attr.separator();
|
||||||
String dictType = attr.dictType();
|
String dictType = attr.dictType();
|
||||||
|
|
||||||
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
|
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
|
||||||
{
|
{
|
||||||
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
|
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
|
||||||
@@ -1164,10 +1200,6 @@ public class ExcelUtil<T>
|
|||||||
}
|
}
|
||||||
cell.setCellValue(sysDictMap.get(dictType + value));
|
cell.setCellValue(sysDictMap.get(dictType + value));
|
||||||
}
|
}
|
||||||
else if (value instanceof BigDecimal && -1 != attr.scale())
|
|
||||||
{
|
|
||||||
cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
|
|
||||||
}
|
|
||||||
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
|
else if (!attr.handler().equals(ExcelHandlerAdapter.class))
|
||||||
{
|
{
|
||||||
cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
|
cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
|
||||||
@@ -1177,6 +1209,7 @@ public class ExcelUtil<T>
|
|||||||
// 设置列类型
|
// 设置列类型
|
||||||
setCellVo(value, attr, cell);
|
setCellVo(value, attr, cell);
|
||||||
}
|
}
|
||||||
|
|
||||||
addStatisticsData(column, Convert.toStr(value), attr);
|
addStatisticsData(column, Convert.toStr(value), attr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,16 +18,16 @@ import java.util.concurrent.ThreadPoolExecutor;
|
|||||||
public class ThreadPoolConfig
|
public class ThreadPoolConfig
|
||||||
{
|
{
|
||||||
// 核心线程池大小
|
// 核心线程池大小
|
||||||
private int corePoolSize = 50;
|
private int corePoolSize = 16;
|
||||||
|
|
||||||
// 最大可创建的线程数
|
// 最大可创建的线程数
|
||||||
private int maxPoolSize = 200;
|
private int maxPoolSize = 32;
|
||||||
|
|
||||||
// 队列最大长度
|
// 队列最大长度
|
||||||
private int queueCapacity = 1000;
|
private int queueCapacity = 1000;
|
||||||
|
|
||||||
// 线程池维护线程所允许的空闲时间
|
// 线程池维护线程所允许的空闲时间
|
||||||
private int keepAliveSeconds = 300;
|
private int keepAliveSeconds = 120;
|
||||||
|
|
||||||
@Bean(name = "threadPoolTaskExecutor")
|
@Bean(name = "threadPoolTaskExecutor")
|
||||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ public class ConstructionTeamController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入施工队数据(全部新增,不校验重复)
|
* 导入施工队数据(全部新增)
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('information:construction:import')")
|
@PreAuthorize("@ss.hasPermi('information:construction:import')")
|
||||||
@Log(title = "施工队信息", businessType = BusinessType.IMPORT)
|
@Log(title = "施工队信息", businessType = BusinessType.IMPORT)
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public class PcdeDetailController extends BaseController
|
|||||||
public TableDataInfo list(PcdeDetail pcdeDetail)
|
public TableDataInfo list(PcdeDetail pcdeDetail)
|
||||||
{
|
{
|
||||||
startPage();
|
startPage();
|
||||||
|
System.out.printf("111111");
|
||||||
List<PcdeDetail> list = pcdeDetailService.selectPcdeDetailList(pcdeDetail);
|
List<PcdeDetail> list = pcdeDetailService.selectPcdeDetailList(pcdeDetail);
|
||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ public class Mtd extends BaseEntity
|
|||||||
private Long Id;
|
private Long Id;
|
||||||
|
|
||||||
/** 物料号 */
|
/** 物料号 */
|
||||||
@Excel(name = "物料号")
|
@Excel(name = "物料编号")
|
||||||
private String mid;
|
private String mid;
|
||||||
|
|
||||||
/** 物料描述 */
|
/** 物料描述 */
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.zg.project.information.mapper;
|
|||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import com.zg.project.information.domain.ConstructionTeam;
|
import com.zg.project.information.domain.ConstructionTeam;
|
||||||
|
import io.lettuce.core.dynamic.annotation.Param;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 施工队信息Mapper接口
|
* 施工队信息Mapper接口
|
||||||
@@ -35,6 +36,12 @@ public interface ConstructionTeamMapper
|
|||||||
*/
|
*/
|
||||||
public int insertConstructionTeam(ConstructionTeam constructionTeam);
|
public int insertConstructionTeam(ConstructionTeam constructionTeam);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询当前最大施工队编号
|
||||||
|
*/
|
||||||
|
String selectMaxTeamCode();
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改施工队信息
|
* 修改施工队信息
|
||||||
*
|
*
|
||||||
@@ -58,4 +65,8 @@ public interface ConstructionTeamMapper
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
public int deleteConstructionTeamByIds(Long[] ids);
|
public int deleteConstructionTeamByIds(Long[] ids);
|
||||||
|
|
||||||
|
ConstructionTeam selectByTeamCode(@Param("teamCode") String teamCode);
|
||||||
|
|
||||||
|
ConstructionTeam selectByTeamName(@Param("teamName") String teamName);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -89,4 +89,7 @@ public interface PcdeDetailMapper
|
|||||||
|
|
||||||
String selectWarehouseCodeByPcode(String pcode);
|
String selectWarehouseCodeByPcode(String pcode);
|
||||||
|
|
||||||
|
String selectEncodedIdByPcodeAndWarehouse(@Param("pcode") String pcode,
|
||||||
|
@Param("warehouseCode") String warehouseCode);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,9 @@
|
|||||||
package com.zg.project.information.service.impl;
|
package com.zg.project.information.service.impl;
|
||||||
|
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import com.zg.common.exception.ServiceException;
|
import com.zg.common.exception.ServiceException;
|
||||||
import com.zg.common.utils.StringUtils;
|
import com.zg.common.utils.StringUtils;
|
||||||
@@ -11,6 +13,8 @@ import com.zg.project.information.mapper.ConstructionTeamMapper;
|
|||||||
import com.zg.project.information.domain.ConstructionTeam;
|
import com.zg.project.information.domain.ConstructionTeam;
|
||||||
import com.zg.project.information.service.IConstructionTeamService;
|
import com.zg.project.information.service.IConstructionTeamService;
|
||||||
|
|
||||||
|
import static com.zg.common.utils.SecurityUtils.getUsername;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 施工队信息Service业务层处理
|
* 施工队信息Service业务层处理
|
||||||
*
|
*
|
||||||
@@ -56,9 +60,36 @@ public class ConstructionTeamServiceImpl implements IConstructionTeamService
|
|||||||
@Override
|
@Override
|
||||||
public int insertConstructionTeam(ConstructionTeam constructionTeam)
|
public int insertConstructionTeam(ConstructionTeam constructionTeam)
|
||||||
{
|
{
|
||||||
|
// 1️⃣ 自动生成施工队编号(6 位)
|
||||||
|
String teamCode = generateTeamCode();
|
||||||
|
constructionTeam.setTeamCode(teamCode);
|
||||||
|
|
||||||
|
// 2️⃣ 补充若依通用字段(如果你没用 BaseEntity 自动处理)
|
||||||
|
constructionTeam.setCreatedBy(getUsername());
|
||||||
|
constructionTeam.setCreatedAt(new Date());
|
||||||
|
constructionTeam.setIsDelete("0");
|
||||||
|
|
||||||
return constructionTeamMapper.insertConstructionTeam(constructionTeam);
|
return constructionTeamMapper.insertConstructionTeam(constructionTeam);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成施工队编号(CT + 6位数字)
|
||||||
|
* 示例:CT000001
|
||||||
|
*/
|
||||||
|
private String generateTeamCode() {
|
||||||
|
String maxCode = constructionTeamMapper.selectMaxTeamCode();
|
||||||
|
|
||||||
|
if (maxCode == null) {
|
||||||
|
return "CT000001";
|
||||||
|
}
|
||||||
|
|
||||||
|
// 取数字部分
|
||||||
|
int num = Integer.parseInt(maxCode.substring(2));
|
||||||
|
num++;
|
||||||
|
|
||||||
|
return String.format("CT%06d", num);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改施工队信息
|
* 修改施工队信息
|
||||||
*
|
*
|
||||||
@@ -96,7 +127,7 @@ public class ConstructionTeamServiceImpl implements IConstructionTeamService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导入施工队信息列表
|
* 导入施工队信息列表(名称 / 编号 去重)
|
||||||
*
|
*
|
||||||
* @param teamList 导入的施工队信息列表
|
* @param teamList 导入的施工队信息列表
|
||||||
* @param operName 操作人员
|
* @param operName 操作人员
|
||||||
@@ -113,54 +144,106 @@ public class ConstructionTeamServiceImpl implements IConstructionTeamService
|
|||||||
int successNum = 0;
|
int successNum = 0;
|
||||||
int failureNum = 0;
|
int failureNum = 0;
|
||||||
StringBuilder failureMsg = new StringBuilder();
|
StringBuilder failureMsg = new StringBuilder();
|
||||||
|
|
||||||
Date now = new Date();
|
Date now = new Date();
|
||||||
|
|
||||||
|
// ===== ① Excel 内去重 =====
|
||||||
|
Set<String> teamCodeSet = new HashSet<>();
|
||||||
|
Set<String> teamNameSet = new HashSet<>();
|
||||||
|
|
||||||
for (ConstructionTeam team : teamList)
|
for (ConstructionTeam team : teamList)
|
||||||
{
|
{
|
||||||
try
|
String teamCode = team.getTeamCode();
|
||||||
{
|
String teamName = team.getTeamName();
|
||||||
// 可选:最低限度必填校验(建议保留,不然空行也会入库)
|
|
||||||
if (StringUtils.isBlank(team.getTeamName()) || StringUtils.isBlank(team.getTeamCode()))
|
if (StringUtils.isBlank(teamCode) || StringUtils.isBlank(teamName))
|
||||||
{
|
{
|
||||||
failureNum++;
|
failureNum++;
|
||||||
failureMsg.append("<br/>施工队名称/编号不能为空,已跳过。");
|
failureMsg.append("<br/>施工队名称/编号不能为空,已跳过。");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 按你供应计划逻辑:不校验重复,全部新增
|
if (!teamCodeSet.add(teamCode))
|
||||||
|
{
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>施工队编号重复(Excel 内):").append(teamCode);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!teamNameSet.add(teamName))
|
||||||
|
{
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>施工队名称重复(Excel 内):").append(teamName);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== ② 数据库内去重 =====
|
||||||
|
for (ConstructionTeam team : teamList)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// 跳过前面校验失败的数据
|
||||||
|
if (StringUtils.isBlank(team.getTeamCode()) || StringUtils.isBlank(team.getTeamName()))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按编号查
|
||||||
|
ConstructionTeam existByCode =
|
||||||
|
constructionTeamMapper.selectByTeamCode(team.getTeamCode());
|
||||||
|
if (existByCode != null)
|
||||||
|
{
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>施工队编号已存在:").append(team.getTeamCode());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 按名称查
|
||||||
|
ConstructionTeam existByName =
|
||||||
|
constructionTeamMapper.selectByTeamName(team.getTeamName());
|
||||||
|
if (existByName != null)
|
||||||
|
{
|
||||||
|
failureNum++;
|
||||||
|
failureMsg.append("<br/>施工队名称已存在:").append(team.getTeamName());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ===== 新增 =====
|
||||||
team.setCreatedBy(operName);
|
team.setCreatedBy(operName);
|
||||||
team.setCreatedAt(now);
|
team.setCreatedAt(now);
|
||||||
team.setUpdatedBy(operName);
|
team.setUpdatedBy(operName);
|
||||||
team.setUpdatedAt(now);
|
team.setUpdatedAt(now);
|
||||||
|
|
||||||
// isDelete 默认 0
|
|
||||||
if (StringUtils.isBlank(team.getIsDelete()))
|
if (StringUtils.isBlank(team.getIsDelete()))
|
||||||
{
|
{
|
||||||
team.setIsDelete("0");
|
team.setIsDelete("0");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 走你现有 insert(Mapper/XML 已存在)
|
constructionTeamMapper.insertConstructionTeam(team);
|
||||||
insertConstructionTeam(team);
|
|
||||||
|
|
||||||
successNum++;
|
successNum++;
|
||||||
|
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
failureNum++;
|
failureNum++;
|
||||||
failureMsg.append("<br/>施工队编号:").append(team.getTeamCode())
|
failureMsg.append("<br/>施工队编号:")
|
||||||
.append(",施工队名称:").append(team.getTeamName())
|
.append(team.getTeamCode())
|
||||||
.append(" 导入失败:").append(e.getMessage());
|
.append(",施工队名称:")
|
||||||
|
.append(team.getTeamName())
|
||||||
|
.append(" 导入失败:")
|
||||||
|
.append(e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failureNum > 0)
|
if (failureNum > 0)
|
||||||
{
|
{
|
||||||
failureMsg.insert(0, "导入完成,但有 " + failureNum + " 条记录失败:");
|
failureMsg.insert(0,
|
||||||
|
"导入完成,成功 " + successNum + " 条,失败 " + failureNum + " 条:");
|
||||||
throw new ServiceException(failureMsg.toString());
|
throw new ServiceException(failureMsg.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
return "导入成功,共 " + successNum + " 条数据";
|
return "导入成功,共 " + successNum + " 条数据";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
|||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
|
|
||||||
import com.zg.common.exception.ServiceException;
|
import com.zg.common.exception.ServiceException;
|
||||||
|
import com.zg.common.utils.StringUtils;
|
||||||
|
import com.zg.project.wisdom.domain.GysJh;
|
||||||
import com.zg.project.wisdom.domain.vo.PlanToMtdVO;
|
import com.zg.project.wisdom.domain.vo.PlanToMtdVO;
|
||||||
import com.zg.project.wisdom.mapper.GysJhMapper;
|
import com.zg.project.wisdom.mapper.GysJhMapper;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -67,9 +69,37 @@ public class MtdServiceImpl implements IMtdService
|
|||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int insertMtd(Mtd mtd)
|
public int insertMtd(Mtd mtd)
|
||||||
{
|
{
|
||||||
return mtdMapper.insertMtd(mtd);
|
if (mtd == null || StringUtils.isBlank(mtd.getMid())) {
|
||||||
|
throw new ServiceException("物料号不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1️⃣ 先新增物料字典
|
||||||
|
int rows = mtdMapper.insertMtd(mtd);
|
||||||
|
|
||||||
|
// 2️⃣ 新增成功后,开始“反查供应计划”
|
||||||
|
if (rows > 0 && StringUtils.isNotBlank(mtd.getUnt())) {
|
||||||
|
|
||||||
|
String wlNo = mtd.getMid().trim();
|
||||||
|
String dw = mtd.getUnt().trim();
|
||||||
|
|
||||||
|
// 3️⃣ 根据物料号查询供应计划(可能多条)
|
||||||
|
List<GysJh> jhList = gysJhMapper.selectByWlNo(wlNo);
|
||||||
|
|
||||||
|
if (jhList != null && !jhList.isEmpty()) {
|
||||||
|
for (GysJh jh : jhList) {
|
||||||
|
|
||||||
|
// 4️⃣ 只处理「供应计划中单位为空」的记录
|
||||||
|
if (StringUtils.isBlank(jh.getDw())) {
|
||||||
|
gysJhMapper.updateDwById(jh.getId(), dw);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -1,182 +0,0 @@
|
|||||||
package com.zg.project.wisdom.config;
|
|
||||||
|
|
||||||
import com.zg.project.wisdom.mqtt.dispatcher.MqttMessageDispatcher;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.eclipse.paho.client.mqttv3.*;
|
|
||||||
import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import javax.annotation.PreDestroy;
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT 客户端初始化配置类
|
|
||||||
*
|
|
||||||
* 作用说明:
|
|
||||||
* 1. Spring Boot 启动时自动创建 MQTT 客户端
|
|
||||||
* 2. 连接 EMQX Broker
|
|
||||||
* 3. 订阅 application.yml 中配置的 Topic(支持通配符)
|
|
||||||
* 4. 接收传感器上报的数据
|
|
||||||
*
|
|
||||||
* 说明:
|
|
||||||
* - 同一个 MQTT Client 同时支持「订阅(接收)」和「发布(下发指令)」
|
|
||||||
* - 后端一般只需要一个 Client
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Configuration
|
|
||||||
public class MqttClientConfig {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT 客户端实例
|
|
||||||
* 由本配置类统一维护
|
|
||||||
*/
|
|
||||||
private MqttClient mqttClient;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private MqttMessageDispatcher mqttMessageDispatcher;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 创建 MQTT Client Bean
|
|
||||||
*
|
|
||||||
* @param props MQTT 配置(来自 application.yml)
|
|
||||||
*/
|
|
||||||
@Bean
|
|
||||||
public MqttClient mqttClient(MqttProperties props) throws MqttException {
|
|
||||||
|
|
||||||
// 如果未开启 MQTT 功能,直接不初始化
|
|
||||||
// 注意:此时 mqttClient Bean 为 null
|
|
||||||
if (!props.isEnabled()) {
|
|
||||||
log.warn("[MQTT] mqtt.enabled=false,MQTT 功能未启用");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 创建 MQTT 客户端
|
|
||||||
mqttClient = new MqttClient(
|
|
||||||
props.getBroker(),
|
|
||||||
props.getClientId(),
|
|
||||||
new MemoryPersistence()
|
|
||||||
);
|
|
||||||
|
|
||||||
// 2. MQTT 连接参数
|
|
||||||
MqttConnectOptions options = new MqttConnectOptions();
|
|
||||||
|
|
||||||
// 是否清除会话:
|
|
||||||
// true - 断开后清除订阅(推荐后端使用)
|
|
||||||
// false - 保留会话(多用于设备端)
|
|
||||||
options.setCleanSession(props.isCleanSession());
|
|
||||||
|
|
||||||
// 心跳时间(秒)
|
|
||||||
options.setKeepAliveInterval(props.getKeepAlive());
|
|
||||||
|
|
||||||
// 连接超时时间(秒)
|
|
||||||
options.setConnectionTimeout(props.getTimeout());
|
|
||||||
|
|
||||||
// 自动重连(非常重要,防止网络抖动)
|
|
||||||
options.setAutomaticReconnect(true);
|
|
||||||
|
|
||||||
// 设置用户名密码(如果配置了)
|
|
||||||
if (props.getUsername() != null && !props.getUsername().trim().isEmpty()) {
|
|
||||||
options.setUserName(props.getUsername().trim());
|
|
||||||
}
|
|
||||||
if (props.getPassword() != null && !props.getPassword().trim().isEmpty()) {
|
|
||||||
options.setPassword(props.getPassword().toCharArray());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. 设置 MQTT 回调
|
|
||||||
mqttClient.setCallback(new MqttCallbackExtended() {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 连接成功(或重连成功)回调
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void connectComplete(boolean reconnect, String serverURI) {
|
|
||||||
log.info("[MQTT] 连接成功 reconnect={}, serverURI={}", reconnect, serverURI);
|
|
||||||
// 连接成功后订阅 Topic
|
|
||||||
subscribe(props);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 连接丢失回调
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void connectionLost(Throwable cause) {
|
|
||||||
log.warn("[MQTT] 连接断开", cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 接收到消息回调
|
|
||||||
*
|
|
||||||
* @param topic 消息主题(用于区分设备、类型)
|
|
||||||
* @param message 消息内容
|
|
||||||
*/
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void messageArrived(String topic, MqttMessage message) {
|
|
||||||
String payload = new String(message.getPayload(), StandardCharsets.UTF_8);
|
|
||||||
mqttMessageDispatcher.dispatch(topic, payload);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 消息发送完成回调(发布消息后触发)
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void deliveryComplete(IMqttDeliveryToken token) {
|
|
||||||
// 后端下发指令时可用于确认发送完成
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 4. 连接 Broker
|
|
||||||
log.info("[MQTT] 正在连接 Broker:{}", props.getBroker());
|
|
||||||
mqttClient.connect(options);
|
|
||||||
log.info("[MQTT] MQTT 已连接");
|
|
||||||
|
|
||||||
// 5. 启动时先订阅一次(防止 connectComplete 未触发)
|
|
||||||
subscribe(props);
|
|
||||||
|
|
||||||
return mqttClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 订阅 Topic(支持通配符)
|
|
||||||
*/
|
|
||||||
private void subscribe(MqttProperties props) {
|
|
||||||
if (mqttClient == null || !mqttClient.isConnected()) {
|
|
||||||
log.warn("[MQTT] 订阅失败:客户端未连接");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (props.getTopics() == null || props.getTopics().isEmpty()) {
|
|
||||||
log.warn("[MQTT] 未配置订阅 Topic");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
for (String topic : props.getTopics()) {
|
|
||||||
if (topic == null || topic.trim().isEmpty()) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
mqttClient.subscribe(topic.trim(), props.getQos());
|
|
||||||
log.info("[MQTT] 已订阅 Topic:{},QoS={}", topic.trim(), props.getQos());
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("[MQTT] 订阅 Topic 失败", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Spring 容器关闭时,优雅断开 MQTT 连接
|
|
||||||
*/
|
|
||||||
@PreDestroy
|
|
||||||
public void destroy() {
|
|
||||||
try {
|
|
||||||
if (mqttClient != null) {
|
|
||||||
if (mqttClient.isConnected()) {
|
|
||||||
mqttClient.disconnect();
|
|
||||||
}
|
|
||||||
mqttClient.close();
|
|
||||||
}
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package com.zg.project.wisdom.config;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT 配置属性(对应 application.yml 中 mqtt.*)
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
@Component
|
|
||||||
@ConfigurationProperties(prefix = "mqtt")
|
|
||||||
public class MqttProperties {
|
|
||||||
|
|
||||||
/** 是否启用 MQTT */
|
|
||||||
private boolean enabled;
|
|
||||||
|
|
||||||
/** Broker 地址:tcp://192.168.1.29:1883 */
|
|
||||||
private String broker;
|
|
||||||
|
|
||||||
/** 客户端ID(在 EMQX 中唯一) */
|
|
||||||
private String clientId;
|
|
||||||
|
|
||||||
/** 账号 */
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
/** 密码 */
|
|
||||||
private String password;
|
|
||||||
|
|
||||||
/** 是否清除会话 */
|
|
||||||
private boolean cleanSession = true;
|
|
||||||
|
|
||||||
/** 心跳时间(秒) */
|
|
||||||
private int keepAlive = 30;
|
|
||||||
|
|
||||||
/** 连接超时时间(秒) */
|
|
||||||
private int timeout = 10;
|
|
||||||
|
|
||||||
/** 默认 QoS */
|
|
||||||
private int qos = 1;
|
|
||||||
|
|
||||||
/** 订阅 Topic 列表(支持通配符) */
|
|
||||||
private List<String> topics;
|
|
||||||
}
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
package com.zg.project.wisdom.config;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttClient;
|
|
||||||
import org.eclipse.paho.client.mqttv3.MqttMessage;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT 消息发布客户端
|
|
||||||
*
|
|
||||||
* 作用说明:
|
|
||||||
* - 专门用于向指定设备下发控制指令
|
|
||||||
* - 例如:开启 / 关闭 / 重启 传感器
|
|
||||||
*
|
|
||||||
* 说明:
|
|
||||||
* - 依赖同一个 MqttClient
|
|
||||||
* - 发布消息时使用“精确 Topic”(不能使用通配符)
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class MqttPublishClient {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT 客户端(由 Spring 注入)
|
|
||||||
*/
|
|
||||||
private final MqttClient mqttClient;
|
|
||||||
|
|
||||||
public MqttPublishClient(MqttClient mqttClient) {
|
|
||||||
this.mqttClient = mqttClient;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布 MQTT 消息(默认 QoS=1,不保留消息)
|
|
||||||
*
|
|
||||||
* @param topic 目标 Topic(必须是具体设备的 Topic)
|
|
||||||
* @param payload 消息内容(JSON 字符串)
|
|
||||||
*/
|
|
||||||
public void publish(String topic, String payload) {
|
|
||||||
publish(topic, payload, 1, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 发布 MQTT 消息(自定义参数)
|
|
||||||
*/
|
|
||||||
public void publish(String topic, String payload, int qos, boolean retained) {
|
|
||||||
|
|
||||||
// 如果 MQTT 未启用或未初始化
|
|
||||||
if (mqttClient == null) {
|
|
||||||
throw new IllegalStateException("MQTT 客户端未初始化(mqtt.enabled=false)");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果 MQTT 尚未连接
|
|
||||||
if (!mqttClient.isConnected()) {
|
|
||||||
throw new IllegalStateException("MQTT 客户端未连接到 Broker");
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
MqttMessage msg = new MqttMessage(payload.getBytes(StandardCharsets.UTF_8));
|
|
||||||
msg.setQos(qos);
|
|
||||||
msg.setRetained(retained);
|
|
||||||
|
|
||||||
mqttClient.publish(topic, msg);
|
|
||||||
|
|
||||||
log.info("[MQTT] 指令已发送 topic={}, qos={}, retained={}, payload={}",
|
|
||||||
topic, qos, retained, payload);
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("[MQTT] 指令发送失败 topic=" + topic, e);
|
|
||||||
throw new RuntimeException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -80,11 +80,13 @@ public class AgvTaskResultController extends BaseController {
|
|||||||
*/
|
*/
|
||||||
@PostMapping("/upGoods")
|
@PostMapping("/upGoods")
|
||||||
public AjaxResult upGoods(@RequestBody OutGoodsDTO dto) {
|
public AjaxResult upGoods(@RequestBody OutGoodsDTO dto) {
|
||||||
|
|
||||||
if (StringUtils.isBlank(dto.getTaskNo())) {
|
if (StringUtils.isBlank(dto.getTaskNo())) {
|
||||||
throw new ServiceException("taskNo 不能为空");
|
throw new ServiceException("taskNo 不能为空");
|
||||||
}
|
}
|
||||||
// 返回 taskId
|
// 返回 taskId
|
||||||
String taskId = agvTaskResultService.handleUpGoods(dto.getTaskNo(), dto.getMaterialStatus());
|
String taskId = agvTaskResultService.handleUpGoods(dto.getTaskNo(), dto.getMaterialStatus());
|
||||||
|
|
||||||
return AjaxResult.success("上架任务已提交至WCS").put("taskId", taskId);
|
return AjaxResult.success("上架任务已提交至WCS").put("taskId", taskId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
|||||||
* @author zg
|
* @author zg
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping("/wisdom/task")
|
@RequestMapping("/wisdom/dispatch")
|
||||||
public class DdTaskController extends BaseController {
|
public class DdTaskController extends BaseController {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ public class GysJhController extends BaseController
|
|||||||
@Autowired
|
@Autowired
|
||||||
private IGysJhService gysJhService;
|
private IGysJhService gysJhService;
|
||||||
|
|
||||||
/**A
|
/**
|
||||||
* 查询供应计划列表
|
* 查询供应计划列表
|
||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
@PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
||||||
@@ -52,10 +52,8 @@ public class GysJhController extends BaseController
|
|||||||
*/
|
*/
|
||||||
// @PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
// @PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
||||||
@GetMapping("/getBySapNo")
|
@GetMapping("/getBySapNo")
|
||||||
public AjaxResult getBySapNo(String sapNo)
|
public AjaxResult getBySapNo(@RequestParam String sapNo) {
|
||||||
{
|
return gysJhService.getBySapNo(sapNo);
|
||||||
List<GysJh> list = gysJhService.getBySapNo(sapNo);
|
|
||||||
return success(list);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -6,11 +6,11 @@ import java.util.Map;
|
|||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
|
||||||
import com.github.pagehelper.PageHelper;
|
import com.github.pagehelper.PageHelper;
|
||||||
|
import com.zg.common.utils.StringUtils;
|
||||||
import com.zg.project.wisdom.domain.dto.*;
|
import com.zg.project.wisdom.domain.dto.*;
|
||||||
import com.zg.project.wisdom.domain.vo.DeliveryBillVO;
|
import com.zg.project.wisdom.domain.vo.DeliveryBillVO;
|
||||||
import com.zg.project.wisdom.domain.vo.PcodeQtyVO;
|
|
||||||
import com.zg.project.wisdom.service.QwenOcrRemoteService;
|
import com.zg.project.wisdom.service.QwenOcrRemoteService;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||||
import org.springframework.security.access.prepost.PreAuthorize;
|
import org.springframework.security.access.prepost.PreAuthorize;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
@@ -67,17 +67,21 @@ public class RkInfoController extends BaseController
|
|||||||
return getDataTable(list);
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存查询
|
||||||
|
* @param dto
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
@PostMapping("/pageStatistics")
|
@PostMapping("/pageStatistics")
|
||||||
public Map<String, Object> pageStatistics(@RequestBody RkInfoQueryDTO dto) {
|
public Map<String, Object> pageStatistics(@RequestBody RkInfoQueryDTO dto) {
|
||||||
|
|
||||||
// 使用 PageHelper 分页
|
|
||||||
PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
|
PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
|
||||||
List<RkInfo> list = rkInfoService.selectAllRkInfo(dto);
|
|
||||||
Map<String,Object> dataInfo = new HashMap<>();
|
|
||||||
dataInfo.put("dataList",getDataTable(list));
|
|
||||||
return dataInfo;
|
|
||||||
|
|
||||||
|
List<RkInfo> list = rkInfoService.selectAllRkInfo(dto);
|
||||||
|
|
||||||
|
Map<String, Object> dataInfo = new HashMap<>();
|
||||||
|
dataInfo.put("dataList", getDataTable(list));
|
||||||
|
return dataInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -97,14 +101,51 @@ public class RkInfoController extends BaseController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// @PreAuthorize("@ss.hasPermi('wisdom:stock:list')")
|
// @PreAuthorize("@ss.hasPermi('wisdom:stock:list')")
|
||||||
@PostMapping("/bill/groups")
|
// @PostMapping("/bill/groups")
|
||||||
public TableDataInfo billGroups(@RequestBody RkInfoQueryDTO query) {
|
// public TableDataInfo billGroups(@RequestBody RkInfoQueryDTO query) {
|
||||||
// 分页
|
// // 分页
|
||||||
PageHelper.startPage(query.getPageNum(), query.getPageSize());
|
// PageHelper.startPage(query.getPageNum(), query.getPageSize());
|
||||||
// 查询
|
// // 查询
|
||||||
List<RkInfo> rows = rkInfoService.selectGroupedByBill(query);
|
// List<RkInfo> rows = rkInfoService.selectGroupedByBill(query);
|
||||||
|
//
|
||||||
|
// return getDataTable(rows);
|
||||||
|
// }
|
||||||
|
|
||||||
return getDataTable(rows);
|
/**
|
||||||
|
* 获取单据列表(轻量级:仅返回单据头公共信息,不聚合明细字段)
|
||||||
|
*/
|
||||||
|
@PostMapping("/bill/groups")
|
||||||
|
public TableDataInfo billHeaderList(@RequestBody RkInfoQueryDTO query) {
|
||||||
|
// 1. 分页
|
||||||
|
PageHelper.startPage(query.getPageNum(), query.getPageSize());
|
||||||
|
|
||||||
|
// 2. 查询
|
||||||
|
List<RkInfo> list = rkInfoService.selectBillHeaderList(query);
|
||||||
|
|
||||||
|
return getDataTable(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 导出出入库记录
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('wisdom:stock:export')")
|
||||||
|
@Log(title = "出入库记录", businessType = BusinessType.EXPORT)
|
||||||
|
@PostMapping("/exportPageList")
|
||||||
|
public void exportPageList(HttpServletResponse response, RkInfoQueryDTO query)
|
||||||
|
{
|
||||||
|
List<RkInfo> list = rkInfoService.selectRkInfoPageList(query);
|
||||||
|
ExcelUtil<RkInfo> util = new ExcelUtil<>(RkInfo.class);
|
||||||
|
util.exportExcel(response, list, "出入库记录导出");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出入库查询
|
||||||
|
*/
|
||||||
|
@PostMapping("/pageList")
|
||||||
|
public TableDataInfo pageList(@RequestBody RkInfoQueryDTO dto) {
|
||||||
|
PageHelper.startPage(dto.getPageNum(), dto.getPageSize());
|
||||||
|
List<RkInfo> list = rkInfoService.selectRkInfoPageList(dto);
|
||||||
|
return getDataTable(list);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -117,7 +158,7 @@ public class RkInfoController extends BaseController
|
|||||||
{
|
{
|
||||||
List<RkInfo> list = rkInfoService.selectRkInfoList(rkInfo);
|
List<RkInfo> list = rkInfoService.selectRkInfoList(rkInfo);
|
||||||
ExcelUtil<RkInfo> util = new ExcelUtil<RkInfo>(RkInfo.class);
|
ExcelUtil<RkInfo> util = new ExcelUtil<RkInfo>(RkInfo.class);
|
||||||
util.exportExcel(response, list, "库存单据主数据");
|
util.exportExcel(response, list, "数据导出");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -146,12 +187,25 @@ public class RkInfoController extends BaseController
|
|||||||
*/
|
*/
|
||||||
@PreAuthorize("@ss.hasPermi('wisdom:stock:edit')")
|
@PreAuthorize("@ss.hasPermi('wisdom:stock:edit')")
|
||||||
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
|
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
|
||||||
@PutMapping("/update")
|
@PostMapping("/update")
|
||||||
public AjaxResult edit(@RequestBody RkInfo rkInfo)
|
public AjaxResult edit(@RequestBody RkInfo rkInfo)
|
||||||
{
|
{
|
||||||
return toAjax(rkInfoService.updateRkInfo(rkInfo));
|
return toAjax(rkInfoService.updateRkInfo(rkInfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据出库单据号修改库存单据
|
||||||
|
*/
|
||||||
|
@PreAuthorize("@ss.hasPermi('wisdom:stock:edit')")
|
||||||
|
@Log(title = "库存单据-按出库单号修改", businessType = BusinessType.UPDATE)
|
||||||
|
@PostMapping("/updateByBillNoCk")
|
||||||
|
public AjaxResult updateByBillNoCk(@RequestBody RkInfo rkInfo) {
|
||||||
|
if (StringUtils.isBlank(rkInfo.getBillNoCk())) {
|
||||||
|
return AjaxResult.error("出库单据号 billNoCk 不能为空");
|
||||||
|
}
|
||||||
|
return toAjax(rkInfoService.updateRkInfoByBillNoCk(rkInfo));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除库存单据主
|
* 删除库存单据主
|
||||||
*/
|
*/
|
||||||
@@ -353,16 +407,5 @@ public class RkInfoController extends BaseController
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("/statistics")
|
|
||||||
public Map<String, Object> statistics(@RequestBody RkInfoQueryDTO dto) {
|
|
||||||
|
|
||||||
Long sumMoney = rkInfoService.selectStatistics(dto);
|
|
||||||
Long pcdeCount = rkInfoService.selectPcde(dto);
|
|
||||||
|
|
||||||
Map<String, Object> dataInfo = new HashMap<>();
|
|
||||||
dataInfo.put("sumMoney", sumMoney);
|
|
||||||
dataInfo.put("pcdeCount", pcdeCount);
|
|
||||||
return dataInfo;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.zg.project.wisdom.controller;
|
package com.zg.project.wisdom.controller;
|
||||||
|
|
||||||
import com.zg.framework.web.domain.AjaxResult;
|
import com.zg.framework.web.domain.AjaxResult;
|
||||||
|
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
import com.zg.project.wisdom.domain.vo.*;
|
||||||
import com.zg.project.wisdom.service.RkStatisticsService;
|
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||||
import com.zg.project.wisdom.service.WarehouseStatService;
|
import com.zg.project.wisdom.service.WarehouseStatService;
|
||||||
@@ -178,4 +179,10 @@ public class RkStatisticsController {
|
|||||||
List<IOBucketVO> rows = rkStatisticsService.getIOBuckets(range);
|
List<IOBucketVO> rows = rkStatisticsService.getIOBuckets(range);
|
||||||
return AjaxResult.success(rows);
|
return AjaxResult.success(rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("/statistics")
|
||||||
|
public Map<String, Object> statistics(@RequestBody RkInfoQueryDTO dto) {
|
||||||
|
// 调用新的合并查询方法
|
||||||
|
return rkStatisticsService.selectStockStatistics(dto);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
package com.zg.project.wisdom.domain;
|
package com.zg.project.wisdom.domain;
|
||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
import org.apache.commons.lang3.builder.ToStringBuilder;
|
import org.apache.commons.lang3.builder.ToStringBuilder;
|
||||||
import org.apache.commons.lang3.builder.ToStringStyle;
|
import org.apache.commons.lang3.builder.ToStringStyle;
|
||||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||||
@@ -19,6 +22,10 @@ public class GysJh extends BaseEntity
|
|||||||
/** 主键ID */
|
/** 主键ID */
|
||||||
private Long id;
|
private Long id;
|
||||||
|
|
||||||
|
/** 行号 */
|
||||||
|
@Excel(name = "行号")
|
||||||
|
private String xh;
|
||||||
|
|
||||||
/** 序号 */
|
/** 序号 */
|
||||||
@Excel(name = "序号")
|
@Excel(name = "序号")
|
||||||
private Long indexNo;
|
private Long indexNo;
|
||||||
@@ -59,25 +66,24 @@ public class GysJh extends BaseEntity
|
|||||||
@Excel(name = "合同单价")
|
@Excel(name = "合同单价")
|
||||||
private BigDecimal htDj;
|
private BigDecimal htDj;
|
||||||
|
|
||||||
|
/** 合同数量 */
|
||||||
|
@Excel(name = "合同数量")
|
||||||
|
private BigDecimal htQty;
|
||||||
|
|
||||||
/** SAP订单编号 */
|
/** SAP订单编号 */
|
||||||
@Excel(name = "SAP订单编号")
|
@Excel(name = "SAP订单编号")
|
||||||
private String sapNo;
|
private String sapNo;
|
||||||
|
|
||||||
/** 行号 */
|
|
||||||
@Excel(name = "行号")
|
|
||||||
private String xh;
|
|
||||||
|
|
||||||
/** 计划交货数量 */
|
/** 计划交货数量 */
|
||||||
|
@Excel(name = "计划交货数量")
|
||||||
private BigDecimal jhQty;
|
private BigDecimal jhQty;
|
||||||
|
|
||||||
/** 合同数量 */
|
|
||||||
private BigDecimal htQty;
|
|
||||||
/** 计量单位 */
|
/** 计量单位 */
|
||||||
@Excel(name = "计量单位")
|
@Excel(name = "计量单位")
|
||||||
private String dw;
|
private String dw;
|
||||||
|
|
||||||
/** 0:未到货,1:已入库,2部分入库 */
|
/** 0:未到货,1:已入库,2部分入库 */
|
||||||
@Excel(name = "0:未到货,1:已入库,2部分入库")
|
// @Excel(name = "0:未到货,1:已入库,2部分入库")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
/** 身份码 */
|
/** 身份码 */
|
||||||
@@ -89,9 +95,17 @@ public class GysJh extends BaseEntity
|
|||||||
private String remark;
|
private String remark;
|
||||||
|
|
||||||
/** 是否删除(0正常 1删除) */
|
/** 是否删除(0正常 1删除) */
|
||||||
@Excel(name = "是否删除", readConverterExp = "0=正常,1=删除")
|
// @Excel(name = "是否删除", readConverterExp = "0=正常,1=删除")
|
||||||
private String isDelete;
|
private String isDelete;
|
||||||
|
|
||||||
|
/** 查询开始时间(yyyy-MM-dd HH:mm:ss) */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date beginTime;
|
||||||
|
|
||||||
|
/** 查询结束时间(yyyy-MM-dd HH:mm:ss) */
|
||||||
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date endTime;
|
||||||
|
|
||||||
public void setId(Long id)
|
public void setId(Long id)
|
||||||
{
|
{
|
||||||
this.id = id;
|
this.id = id;
|
||||||
@@ -278,6 +292,23 @@ public class GysJh extends BaseEntity
|
|||||||
return isDelete;
|
return isDelete;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Date getBeginTime() {
|
||||||
|
return beginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setBeginTime(Date beginTime) {
|
||||||
|
this.beginTime = beginTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Date getEndTime() {
|
||||||
|
return endTime;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setEndTime(Date endTime) {
|
||||||
|
this.endTime = endTime;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||||
|
|||||||
@@ -29,8 +29,12 @@ public class RkInfo extends BaseEntity {
|
|||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
private List<Long> ids;
|
private List<Long> ids;
|
||||||
|
|
||||||
|
/** 是否已出库(0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销) */
|
||||||
|
@Excel(name = "库存状态", readConverterExp = "0=已入库,1=已出库,2=待审批,3=借料出库,4=入库撤销,5=出库撤销")
|
||||||
|
private String isChuku;
|
||||||
|
|
||||||
/** 供应计划ID(对应供应计划表主键) */
|
/** 供应计划ID(对应供应计划表主键) */
|
||||||
@Excel(name = "供应计划ID")
|
// @Excel(name = "供应计划ID")
|
||||||
private Long gysJhId;
|
private Long gysJhId;
|
||||||
|
|
||||||
/** 审批人ID(非数据库字段) */
|
/** 审批人ID(非数据库字段) */
|
||||||
@@ -70,7 +74,7 @@ public class RkInfo extends BaseEntity {
|
|||||||
|
|
||||||
/** 所属大仓编码 */
|
/** 所属大仓编码 */
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
@Excel(name = "所属大仓编码")
|
// @Excel(name = "所属大仓编码")
|
||||||
private String parentWarehouseCode;
|
private String parentWarehouseCode;
|
||||||
|
|
||||||
/** 所属大仓名称 */
|
/** 所属大仓名称 */
|
||||||
@@ -80,7 +84,7 @@ public class RkInfo extends BaseEntity {
|
|||||||
|
|
||||||
/** 所属小仓编码 */
|
/** 所属小仓编码 */
|
||||||
@TableField(exist = false)
|
@TableField(exist = false)
|
||||||
@Excel(name = "所属小仓编码")
|
// @Excel(name = "所属小仓编码")
|
||||||
private String warehouseCode;
|
private String warehouseCode;
|
||||||
|
|
||||||
/** 所属小仓名称 */
|
/** 所属小仓名称 */
|
||||||
@@ -105,16 +109,13 @@ public class RkInfo extends BaseEntity {
|
|||||||
private Date returnTime;
|
private Date returnTime;
|
||||||
|
|
||||||
/** 理货员 */
|
/** 理货员 */
|
||||||
@Excel(name = "理货员")
|
// @Excel(name = "理货员")
|
||||||
private String lihuoY;
|
private String lihuoY;
|
||||||
|
|
||||||
/** 理货员名称(联查显示用,导出专用) */
|
/** 理货员名称(联查显示用,导出专用) */
|
||||||
|
@Excel(name = "理货员")
|
||||||
private String lihuoYName;
|
private String lihuoYName;
|
||||||
|
|
||||||
/** 是否已出库(0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销) */
|
|
||||||
@Excel(name = "是否已出库", readConverterExp = "0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销")
|
|
||||||
private String isChuku;
|
|
||||||
|
|
||||||
/** 单据号 */
|
/** 单据号 */
|
||||||
@Excel(name = "单据号")
|
@Excel(name = "单据号")
|
||||||
private String billNo;
|
private String billNo;
|
||||||
@@ -124,11 +125,11 @@ public class RkInfo extends BaseEntity {
|
|||||||
private String billNoCk;
|
private String billNoCk;
|
||||||
|
|
||||||
/** 是否需要配送(0否 1是 2配送中 3配送完成) */
|
/** 是否需要配送(0否 1是 2配送中 3配送完成) */
|
||||||
@Excel(name = "是否需要配送", readConverterExp = "0=否,1=是,2=配送中,3=配送完成")
|
// @Excel(name = "是否需要配送", readConverterExp = "0=否,1=是,2=配送中,3=配送完成")
|
||||||
private String isDelivery;
|
private String isDelivery;
|
||||||
|
|
||||||
/** 县局 */
|
/** 县局 */
|
||||||
@Excel(name = "县局")
|
// @Excel(name = "县局")
|
||||||
private String xj;
|
private String xj;
|
||||||
|
|
||||||
/** 项目号 */
|
/** 项目号 */
|
||||||
@@ -139,10 +140,10 @@ public class RkInfo extends BaseEntity {
|
|||||||
@Excel(name = "库存项目描述")
|
@Excel(name = "库存项目描述")
|
||||||
private String xmMs;
|
private String xmMs;
|
||||||
|
|
||||||
@Excel(name = "领取方项目号")
|
// @Excel(name = "领取方项目号")
|
||||||
private String xmNoCk;
|
private String xmNoCk;
|
||||||
|
|
||||||
@Excel(name = "领取方项目描述")
|
// @Excel(name = "领取方项目描述")
|
||||||
private String xmMsCk;
|
private String xmMsCk;
|
||||||
|
|
||||||
/** 物料号 */
|
/** 物料号 */
|
||||||
@@ -174,7 +175,7 @@ public class RkInfo extends BaseEntity {
|
|||||||
private String sapNo;
|
private String sapNo;
|
||||||
|
|
||||||
/** 行号 */
|
/** 行号 */
|
||||||
@Excel(name = "行号")
|
// @Excel(name = "行号")
|
||||||
private String xh;
|
private String xh;
|
||||||
|
|
||||||
/** 计划交货数量 */
|
/** 计划交货数量 */
|
||||||
@@ -193,12 +194,19 @@ public class RkInfo extends BaseEntity {
|
|||||||
@Excel(name = "实际入库数量")
|
@Excel(name = "实际入库数量")
|
||||||
private BigDecimal realQty;
|
private BigDecimal realQty;
|
||||||
|
|
||||||
|
/** 总金额 = 合同单价 × 实际入库数量(导出专用) */
|
||||||
|
@Excel(name = "总金额")
|
||||||
|
private BigDecimal totalAmount;
|
||||||
|
|
||||||
|
@Excel(name = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
/** 库位码(编码) */
|
/** 库位码(编码) */
|
||||||
@Excel(name = "库位码")
|
@Excel(name = "库位码")
|
||||||
private String pcode;
|
private String pcode;
|
||||||
|
|
||||||
/** 库位主键ID(pcde_detail.id) */
|
/** 库位主键ID(pcde_detail.id) */
|
||||||
@Excel(name = "库位主键ID")
|
// @Excel(name = "库位主键ID")
|
||||||
private String pcodeId;
|
private String pcodeId;
|
||||||
|
|
||||||
/** 托盘码 */
|
/** 托盘码 */
|
||||||
@@ -206,7 +214,7 @@ public class RkInfo extends BaseEntity {
|
|||||||
private String trayCode;
|
private String trayCode;
|
||||||
|
|
||||||
/** 实物ID */
|
/** 实物ID */
|
||||||
@Excel(name = "实物ID")
|
// @Excel(name = "实物ID")
|
||||||
private String entityId;
|
private String entityId;
|
||||||
|
|
||||||
/** 一货一图 - 货物照片URL(非表字段) */
|
/** 一货一图 - 货物照片URL(非表字段) */
|
||||||
@@ -227,21 +235,21 @@ public class RkInfo extends BaseEntity {
|
|||||||
private String teamName;
|
private String teamName;
|
||||||
|
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
|
||||||
@Excel(name = "领用时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
@Excel(name = "出库时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
private Date lyTime;
|
private Date lyTime;
|
||||||
|
|
||||||
@Excel(name = "出库备注")
|
@Excel(name = "出库备注")
|
||||||
private String ckRemark;
|
private String ckRemark;
|
||||||
|
|
||||||
@Excel(name = "出库备注")
|
// @Excel(name = "审核状态")
|
||||||
private String status;
|
private String status;
|
||||||
|
|
||||||
/** 是否移库过(0否 1是) */
|
/** 是否移库过(0否 1是) */
|
||||||
@Excel(name = "是否移库过")
|
// @Excel(name = "是否移库过")
|
||||||
private String hasMoved;
|
private String hasMoved;
|
||||||
|
|
||||||
/** 是否借料(0否 1是 2已归还) */
|
/** 是否借料(0否 1是 2已归还) */
|
||||||
@Excel(name = "是否借料", readConverterExp = "0=否,1=是,2=已归还")
|
// @Excel(name = "是否借料", readConverterExp = "0=否,1=是,2=已归还")
|
||||||
private String isBorrowed;
|
private String isBorrowed;
|
||||||
|
|
||||||
/** 签字图片URL(image_type = sign,非表字段) */
|
/** 签字图片URL(image_type = sign,非表字段) */
|
||||||
@@ -452,6 +460,14 @@ public class RkInfo extends BaseEntity {
|
|||||||
public String getCkRemark() { return ckRemark; }
|
public String getCkRemark() { return ckRemark; }
|
||||||
public void setCkRemark(String ckRemark) { this.ckRemark = ckRemark; }
|
public void setCkRemark(String ckRemark) { this.ckRemark = ckRemark; }
|
||||||
|
|
||||||
|
public String getRemark() {
|
||||||
|
return remark;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setRemark(String remark) {
|
||||||
|
this.remark = remark;
|
||||||
|
}
|
||||||
|
|
||||||
public String getStatus() { return status; }
|
public String getStatus() { return status; }
|
||||||
public void setStatus(String status) { this.status = status; }
|
public void setStatus(String status) { this.status = status; }
|
||||||
|
|
||||||
@@ -488,6 +504,14 @@ public class RkInfo extends BaseEntity {
|
|||||||
public String getFycde2() { return fycde2; }
|
public String getFycde2() { return fycde2; }
|
||||||
public void setFycde2(String fycde2) { this.fycde2 = fycde2; }
|
public void setFycde2(String fycde2) { this.fycde2 = fycde2; }
|
||||||
|
|
||||||
|
public BigDecimal getTotalAmount() {
|
||||||
|
return totalAmount;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTotalAmount(BigDecimal totalAmount) {
|
||||||
|
this.totalAmount = totalAmount;
|
||||||
|
}
|
||||||
|
|
||||||
public String getIsDelete() { return isDelete; }
|
public String getIsDelete() { return isDelete; }
|
||||||
public void setIsDelete(String isDelete) { this.isDelete = isDelete; }
|
public void setIsDelete(String isDelete) { this.isDelete = isDelete; }
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,17 @@
|
|||||||
package com.zg.project.wisdom.domain.dto;
|
package com.zg.project.wisdom.domain.dto;
|
||||||
|
|
||||||
|
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
public class OutGoodsDTO {
|
public class OutGoodsDTO {
|
||||||
private String taskNo;
|
private String taskNo;
|
||||||
private Integer materialStatus; // 0=空托,1=有货(影响是否传物料信息)
|
private Integer materialStatus; // 0=空托,1=有货(影响是否传物料信息)
|
||||||
|
/**
|
||||||
|
* 调度模式
|
||||||
|
* 1 = 仅立库(WCS)
|
||||||
|
* 2 = 立库 + AGV
|
||||||
|
*/
|
||||||
|
@Excel(name = "调度模式", readConverterExp = "1=仅立库,2=立库+AGV")
|
||||||
|
private Integer dispatchMode;
|
||||||
}
|
}
|
||||||
@@ -14,6 +14,9 @@ public class RefundRequestDTO {
|
|||||||
/** 新库位码 */
|
/** 新库位码 */
|
||||||
private String pcode;
|
private String pcode;
|
||||||
|
|
||||||
|
/** 新仓库 */
|
||||||
|
private String warehouseCode;
|
||||||
|
|
||||||
/** 入库类型 */
|
/** 入库类型 */
|
||||||
private String rkType;
|
private String rkType;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,10 +20,10 @@ public class RkInfoQueryDTO extends RkInfo {
|
|||||||
private Integer pageSize;
|
private Integer pageSize;
|
||||||
|
|
||||||
/** 开始时间 */
|
/** 开始时间 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
private Date statDate;
|
private Date statDate;
|
||||||
|
|
||||||
/** 结束时间 */
|
/** 结束时间 */
|
||||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||||
private Date endDate;
|
private Date endDate;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,10 @@
|
|||||||
package com.zg.project.wisdom.domain.dto;
|
package com.zg.project.wisdom.domain.dto;
|
||||||
|
|
||||||
|
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 出库明细 DTO
|
* 出库明细 DTO
|
||||||
*/
|
*/
|
||||||
@@ -20,6 +23,9 @@ public class StockOutItemDTO {
|
|||||||
/** 托盘码 */
|
/** 托盘码 */
|
||||||
private String trayCode;
|
private String trayCode;
|
||||||
|
|
||||||
|
/** 实际数量 */
|
||||||
|
private BigDecimal realQty;
|
||||||
|
|
||||||
/** 现场照片(单张) */
|
/** 现场照片(单张) */
|
||||||
private String photoUrl; // ✅ 一物一图绑定
|
private String photoUrl; // ✅ 一物一图绑定
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,79 @@
|
|||||||
|
package com.zg.project.wisdom.domain.vo;
|
||||||
|
|
||||||
|
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
import java.math.BigDecimal;
|
||||||
|
import java.util.Date;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 出入库统计明细 VO
|
||||||
|
* 仅用于查询与展示,不参与落库
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class RkCkStatisticVO implements Serializable {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
/** 操作类型:入库 / 出库 */
|
||||||
|
@Excel(name = "操作类型")
|
||||||
|
private String operationType;
|
||||||
|
|
||||||
|
/** 详细类型:入库类型名 / 出库类型名 */
|
||||||
|
@Excel(name = "详细类型")
|
||||||
|
private String detailType;
|
||||||
|
|
||||||
|
/** 库存状态(在库 / 已出库 / 借料等) */
|
||||||
|
@Excel(name = "库存状态")
|
||||||
|
private String stockStatus;
|
||||||
|
|
||||||
|
/** 单据号(入库单号或出库单号) */
|
||||||
|
@Excel(name = "单据号")
|
||||||
|
private String billNo;
|
||||||
|
|
||||||
|
/** 物料号 */
|
||||||
|
@Excel(name = "物料号")
|
||||||
|
private String materialCode;
|
||||||
|
|
||||||
|
/** 物料描述 */
|
||||||
|
@Excel(name = "物料描述")
|
||||||
|
private String materialName;
|
||||||
|
|
||||||
|
/** 单位 */
|
||||||
|
@Excel(name = "单位")
|
||||||
|
private String unit;
|
||||||
|
|
||||||
|
/** 数量(实际数量) */
|
||||||
|
@Excel(name = "数量")
|
||||||
|
private BigDecimal quantity;
|
||||||
|
|
||||||
|
/** 项目号 */
|
||||||
|
@Excel(name = "项目号")
|
||||||
|
private String projectCode;
|
||||||
|
|
||||||
|
/** 项目描述 */
|
||||||
|
@Excel(name = "项目描述")
|
||||||
|
private String projectName;
|
||||||
|
|
||||||
|
/** 库位码 */
|
||||||
|
@Excel(name = "库位码")
|
||||||
|
private String locationCode;
|
||||||
|
|
||||||
|
/** 订单编号(SAP 订单号) */
|
||||||
|
@Excel(name = "订单编号")
|
||||||
|
private String orderNo;
|
||||||
|
|
||||||
|
/** 供应商名称 */
|
||||||
|
@Excel(name = "供应商名称")
|
||||||
|
private String supplierName;
|
||||||
|
|
||||||
|
/** 备注 */
|
||||||
|
@Excel(name = "备注")
|
||||||
|
private String remark;
|
||||||
|
|
||||||
|
/** 入库时间(用户操作入库的日期) */
|
||||||
|
@Excel(name = "操作时间", dateFormat = "yyyy-MM-dd HH:mm:ss")
|
||||||
|
private Date operationTime;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -120,5 +120,16 @@ public interface GysJhMapper
|
|||||||
*/
|
*/
|
||||||
List<PlanToMtdVO> selectMissingMtdItems();
|
List<PlanToMtdVO> selectMissingMtdItems();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据物料号查询供应计划(用于回填单位)
|
||||||
|
*/
|
||||||
|
List<GysJh> selectByWlNo(@Param("wlNo") String wlNo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据主键更新单位
|
||||||
|
*/
|
||||||
|
int updateDwById(@Param("id") Long id,
|
||||||
|
@Param("dw") String dw);
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.zg.project.wisdom.mapper;
|
package com.zg.project.wisdom.mapper;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.zg.project.inventory.domain.vo.PcdeCntVO;
|
import com.zg.project.inventory.domain.vo.PcdeCntVO;
|
||||||
import com.zg.project.inventory.domain.vo.RkInfoMatchVO;
|
import com.zg.project.inventory.domain.vo.RkInfoMatchVO;
|
||||||
@@ -34,12 +35,14 @@ public interface RkInfoMapper
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 使用 selectRkInfoVo 作为子查询,外层按 bill_no 分组聚合
|
* 使用 selectRkInfoVo 作为子查询,外层按 bill_no 分组聚合
|
||||||
* 不新增 resultMap / VO,直接用 RkInfoResult 映射需要的字段
|
|
||||||
*/
|
*/
|
||||||
List<RkInfo> selectGroupedByBill(@Param("q") RkInfoQueryDTO query,
|
List<RkInfo> selectGroupedByBill(@Param("q") RkInfoQueryDTO query,
|
||||||
@Param("needAudit") Integer needAudit);
|
@Param("needAudit") Integer needAudit);
|
||||||
|
|
||||||
|
|
||||||
|
List<RkInfo> selectBillHeaderList(@Param("q") RkInfoQueryDTO query,
|
||||||
|
@Param("needAudit") Integer needAudit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改库存单据主
|
* 修改库存单据主
|
||||||
*
|
*
|
||||||
@@ -48,6 +51,14 @@ public interface RkInfoMapper
|
|||||||
*/
|
*/
|
||||||
public int updateRkInfo(RkInfo rkInfo);
|
public int updateRkInfo(RkInfo rkInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据出库单据号更新库存单据
|
||||||
|
*
|
||||||
|
* @param rkInfo 库存单据
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int updateByBillNoCk(RkInfo rkInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 删除库存单据主
|
* 删除库存单据主
|
||||||
*
|
*
|
||||||
@@ -107,7 +118,7 @@ public interface RkInfoMapper
|
|||||||
List<RkInfo> selectTopOverdueStock(@Param("limit") int limit);
|
List<RkInfo> selectTopOverdueStock(@Param("limit") int limit);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 出库操作
|
*
|
||||||
* @param update
|
* @param update
|
||||||
*/
|
*/
|
||||||
void updateById(RkInfo update);
|
void updateById(RkInfo update);
|
||||||
@@ -226,9 +237,10 @@ public interface RkInfoMapper
|
|||||||
*/
|
*/
|
||||||
List<RkInfo> selectAllRkInfo(RkInfo query);
|
List<RkInfo> selectAllRkInfo(RkInfo query);
|
||||||
|
|
||||||
Long selectStatistics(RkInfo query);
|
/**
|
||||||
|
* 出入库明细分页查询(统计页面)
|
||||||
Long selectPcde(RkInfo query);
|
*/
|
||||||
|
List<RkInfo> selectRkInfoPageList(RkInfo query);
|
||||||
|
|
||||||
int updateBillInfo(RkInfo query);
|
int updateBillInfo(RkInfo query);
|
||||||
|
|
||||||
@@ -254,4 +266,7 @@ public interface RkInfoMapper
|
|||||||
RkInfo selectHeaderByBillNo(String billNo);
|
RkInfo selectHeaderByBillNo(String billNo);
|
||||||
|
|
||||||
String selectMaxBillNo(@Param("prefix") String prefix);
|
String selectMaxBillNo(@Param("prefix") String prefix);
|
||||||
|
|
||||||
|
|
||||||
|
Map<String, Object> selectStockStatistics(RkInfoQueryDTO query);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +0,0 @@
|
|||||||
package com.zg.project.wisdom.mqtt.dispatcher;
|
|
||||||
|
|
||||||
import com.zg.project.wisdom.mqtt.handler.HumiSensorHandler;
|
|
||||||
import com.zg.project.wisdom.mqtt.handler.SmokeSensorHandler;
|
|
||||||
import com.zg.project.wisdom.mqtt.handler.TempSensorHandler;
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT消息分发器
|
|
||||||
* 负责根据MQTT主题(topic)将消息分发给相应的传感器处理器
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class MqttMessageDispatcher {
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
private TempSensorHandler tempSensorHandler;
|
|
||||||
@Autowired
|
|
||||||
private HumiSensorHandler humiSensorHandler;
|
|
||||||
@Autowired
|
|
||||||
private SmokeSensorHandler smokeSensorHandler;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 分发MQTT消息到对应的处理器
|
|
||||||
* 根据topic的前缀判断消息类型,并调用相应的处理器进行处理
|
|
||||||
*
|
|
||||||
* @param topic MQTT主题,用于判断消息类型
|
|
||||||
* @param payload 消息负载,包含具体的传感器数据
|
|
||||||
*/
|
|
||||||
public void dispatch(String topic, String payload) {
|
|
||||||
|
|
||||||
// 处理温度传感器消息
|
|
||||||
if (topic.startsWith("zg/wms/test/temp/")) {
|
|
||||||
tempSensorHandler.handle(topic, payload);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理湿度传感器消息
|
|
||||||
if (topic.startsWith("zg/wms/test/humi/")) {
|
|
||||||
humiSensorHandler.handle(topic, payload);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 处理烟雾传感器消息
|
|
||||||
if (topic.startsWith("zg/wms/test/smoke/")) {
|
|
||||||
smokeSensorHandler.handle(topic, payload);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.warn("未知 MQTT Topic: {}", topic);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,43 +0,0 @@
|
|||||||
package com.zg.project.wisdom.mqtt.handler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 湿度传感器 Handler
|
|
||||||
* Topic 示例:zg/wms/test/humi/{deviceId}
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class HumiSensorHandler {
|
|
||||||
|
|
||||||
public static final String TOPIC_PREFIX = "zg/wms/test/humi/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理湿度传感器消息
|
|
||||||
* @param topic MQTT主题
|
|
||||||
* @param payload 消息负载
|
|
||||||
*/
|
|
||||||
public void handle(String topic, String payload) {
|
|
||||||
String deviceId = resolveDeviceId(topic, TOPIC_PREFIX);
|
|
||||||
|
|
||||||
log.info("[HUMI] deviceId={}, topic={}, payload={}", deviceId, topic, payload);
|
|
||||||
|
|
||||||
// TODO: 这里后续写湿度业务逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从MQTT主题中解析设备ID
|
|
||||||
* @param topic MQTT主题
|
|
||||||
* @param prefix 主题前缀
|
|
||||||
* @return 设备ID
|
|
||||||
*/
|
|
||||||
private String resolveDeviceId(String topic, String prefix) {
|
|
||||||
if (topic == null || !topic.startsWith(prefix)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
// 提取设备ID部分
|
|
||||||
return topic.substring(prefix.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package com.zg.project.wisdom.mqtt.handler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 烟雾传感器 Handler
|
|
||||||
* Topic 示例:zg/wms/test/smoke/{deviceId}
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class SmokeSensorHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT主题前缀,用于烟雾传感器消息
|
|
||||||
*/
|
|
||||||
public static final String TOPIC_PREFIX = "zg/wms/test/smoke/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理烟雾传感器消息
|
|
||||||
*
|
|
||||||
* @param topic MQTT主题
|
|
||||||
* @param payload 消息负载内容
|
|
||||||
*/
|
|
||||||
public void handle(String topic, String payload) {
|
|
||||||
String deviceId = resolveDeviceId(topic, TOPIC_PREFIX);
|
|
||||||
|
|
||||||
log.info("[SMOKE] deviceId={}, topic={}, payload={}", deviceId, topic, payload);
|
|
||||||
|
|
||||||
// TODO: 这里后续写烟雾业务逻辑
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从MQTT主题中解析设备ID
|
|
||||||
*
|
|
||||||
* @param topic 完整的MQTT主题
|
|
||||||
* @param prefix 主题前缀
|
|
||||||
* @return 设备ID,如果主题格式不正确则返回空字符串
|
|
||||||
*/
|
|
||||||
private String resolveDeviceId(String topic, String prefix) {
|
|
||||||
if (topic == null || !topic.startsWith(prefix)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
// 提取前缀后的设备ID部分
|
|
||||||
return topic.substring(prefix.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
package com.zg.project.wisdom.mqtt.handler;
|
|
||||||
|
|
||||||
import lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 温度传感器 Handler
|
|
||||||
* Topic 示例:zg/wms/test/temp/{deviceId}
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Component
|
|
||||||
public class TempSensorHandler {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* MQTT主题前缀,用于温度传感器数据
|
|
||||||
*/
|
|
||||||
public static final String TOPIC_PREFIX = "zg/wms/test/temp/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 处理温度传感器数据
|
|
||||||
*
|
|
||||||
* @param topic MQTT主题,格式为 zg/wms/test/temp/{deviceId}
|
|
||||||
* @param payload 传感器数据载荷
|
|
||||||
*/
|
|
||||||
public void handle(String topic, String payload) {
|
|
||||||
String deviceId = resolveDeviceId(topic, TOPIC_PREFIX);
|
|
||||||
|
|
||||||
log.info("[TEMP] deviceId={}, topic={}, payload={}", deviceId, topic, payload);
|
|
||||||
|
|
||||||
// TODO: 这里后续写温度业务逻辑(解析JSON、落库、告警等)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 从MQTT主题中解析设备ID
|
|
||||||
*
|
|
||||||
* @param topic MQTT主题
|
|
||||||
* @param prefix 主题前缀
|
|
||||||
* @return 设备ID,如果主题格式不正确则返回空字符串
|
|
||||||
*/
|
|
||||||
private String resolveDeviceId(String topic, String prefix) {
|
|
||||||
if (topic == null || !topic.startsWith(prefix)) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
return topic.substring(prefix.length());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,8 @@
|
|||||||
package com.zg.project.wisdom.service;
|
package com.zg.project.wisdom.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
import com.zg.framework.web.domain.AjaxResult;
|
||||||
import com.zg.project.wisdom.domain.GysJh;
|
import com.zg.project.wisdom.domain.GysJh;
|
||||||
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@@ -51,6 +53,9 @@ public interface IGysJhService
|
|||||||
* @param ids 需要删除的供应计划主键集合
|
* @param ids 需要删除的供应计划主键集合
|
||||||
* @return 结果
|
* @return 结果
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public int deleteGysJhByIds(Long[] ids);
|
public int deleteGysJhByIds(Long[] ids);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,7 +79,7 @@ public interface IGysJhService
|
|||||||
* @param sapNo
|
* @param sapNo
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
List<GysJh> getBySapNo(String sapNo);
|
AjaxResult getBySapNo(String sapNo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 按字段映射导入供应计划
|
* 按字段映射导入供应计划
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package com.zg.project.wisdom.service;
|
package com.zg.project.wisdom.service;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
import com.zg.project.inventory.domain.dto.QueryDTO;
|
import com.zg.project.inventory.domain.dto.QueryDTO;
|
||||||
import com.zg.project.inventory.domain.vo.ChartDataVO;
|
import com.zg.project.inventory.domain.vo.ChartDataVO;
|
||||||
@@ -38,6 +39,10 @@ public interface IRkInfoService
|
|||||||
*/
|
*/
|
||||||
List<RkInfo> selectGroupedByBill(RkInfoQueryDTO query);
|
List<RkInfo> selectGroupedByBill(RkInfoQueryDTO query);
|
||||||
|
|
||||||
|
// 接口
|
||||||
|
List<RkInfo> selectBillHeaderList(RkInfoQueryDTO query);
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 修改库存单据主
|
* 修改库存单据主
|
||||||
*
|
*
|
||||||
@@ -46,6 +51,14 @@ public interface IRkInfoService
|
|||||||
*/
|
*/
|
||||||
public int updateRkInfo(RkInfo rkInfo);
|
public int updateRkInfo(RkInfo rkInfo);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据出库单据号修改库存单据
|
||||||
|
*
|
||||||
|
* @param rkInfo 库存单据
|
||||||
|
* @return 影响行数
|
||||||
|
*/
|
||||||
|
int updateRkInfoByBillNoCk(RkInfo rkInfo);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量删除库存单据主
|
* 批量删除库存单据主
|
||||||
*
|
*
|
||||||
@@ -160,9 +173,10 @@ public interface IRkInfoService
|
|||||||
*/
|
*/
|
||||||
List<RkInfo> selectAllRkInfo(RkInfo query);
|
List<RkInfo> selectAllRkInfo(RkInfo query);
|
||||||
|
|
||||||
Long selectStatistics(RkInfo query);
|
/**
|
||||||
|
* 出入库明细分页查询(统计页面)
|
||||||
Long selectPcde(RkInfo query);
|
*/
|
||||||
|
List<RkInfo> selectRkInfoPageList(RkInfo query);
|
||||||
|
|
||||||
public int updateBillInfo(RkInfo rkInfo);
|
public int updateBillInfo(RkInfo rkInfo);
|
||||||
|
|
||||||
|
|||||||
@@ -87,6 +87,7 @@ public class QwenOcrRemoteService {
|
|||||||
|
|
||||||
// 远程服务返回:{ success: true, found: true/false, erpOrderNo: "0101398982" }
|
// 远程服务返回:{ success: true, found: true/false, erpOrderNo: "0101398982" }
|
||||||
JsonNode erpNode = rootNode.get("erpOrderNo");
|
JsonNode erpNode = rootNode.get("erpOrderNo");
|
||||||
|
|
||||||
if (erpNode == null || erpNode.isNull()) {
|
if (erpNode == null || erpNode.isNull()) {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
package com.zg.project.wisdom.service;
|
package com.zg.project.wisdom.service;
|
||||||
|
|
||||||
|
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
import com.zg.project.wisdom.domain.vo.*;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@@ -87,4 +88,11 @@ public interface RkStatisticsService {
|
|||||||
* 规则:排除 rk_info 中未出库(is_chuku=0 或 NULL)的占用库位
|
* 规则:排除 rk_info 中未出库(is_chuku=0 或 NULL)的占用库位
|
||||||
*/
|
*/
|
||||||
List<SceneAvailableVO> listAvailableByWarehouse(String warehouseCode);
|
List<SceneAvailableVO> listAvailableByWarehouse(String warehouseCode);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 库存统计
|
||||||
|
* @param dto 查询参数
|
||||||
|
* @return { "total": 0, "rows": List<StockStatVO> }
|
||||||
|
*/
|
||||||
|
Map<String, Object> selectStockStatistics(RkInfoQueryDTO dto);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -135,8 +135,12 @@ public class AgvTaskResultServiceImpl implements IAgvTaskResultService {
|
|||||||
* 货物上架
|
* 货物上架
|
||||||
* @param
|
* @param
|
||||||
*/
|
*/
|
||||||
|
/**
|
||||||
|
* 货物上架
|
||||||
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String handleUpGoods(String taskNo, Integer materialStatus) {
|
public String handleUpGoods(String taskNo, Integer materialStatus) {
|
||||||
|
|
||||||
Date now = DateUtils.getNowDate();
|
Date now = DateUtils.getNowDate();
|
||||||
|
|
||||||
// 1. 查询调度任务
|
// 1. 查询调度任务
|
||||||
@@ -172,13 +176,11 @@ public class AgvTaskResultServiceImpl implements IAgvTaskResultService {
|
|||||||
|
|
||||||
// 3. 发起调用
|
// 3. 发起调用
|
||||||
String wcsResp = OkHttpUtils.postJson(wcsJobCreateUrl, wcsParam.toJSONString());
|
String wcsResp = OkHttpUtils.postJson(wcsJobCreateUrl, wcsParam.toJSONString());
|
||||||
|
|
||||||
if (StringUtils.isBlank(wcsResp)) {
|
if (StringUtils.isBlank(wcsResp)) {
|
||||||
throw new ServiceException("WCS 接口无响应");
|
throw new ServiceException("WCS 接口无响应");
|
||||||
}
|
}
|
||||||
|
|
||||||
JSONObject json = JSON.parseObject(wcsResp);
|
JSONObject json = JSON.parseObject(wcsResp);
|
||||||
|
|
||||||
if (!json.containsKey("result")) {
|
if (!json.containsKey("result")) {
|
||||||
throw new ServiceException("WCS 返回格式异常:" + wcsResp);
|
throw new ServiceException("WCS 返回格式异常:" + wcsResp);
|
||||||
}
|
}
|
||||||
@@ -203,12 +205,19 @@ public class AgvTaskResultServiceImpl implements IAgvTaskResultService {
|
|||||||
wcs.setUpdateTime(now);
|
wcs.setUpdateTime(now);
|
||||||
wcsTaskResultMapper.insertWcsTaskResult(wcs);
|
wcsTaskResultMapper.insertWcsTaskResult(wcs);
|
||||||
|
|
||||||
log.info("[上架] 执行成功,任务 {} 状态已更新为已完成", taskNo);
|
// ✅ 5. 根据 dispatchMode 判断:仅立库(WCS)模式,WCS成功即任务完成
|
||||||
|
if (ddTask.getDispatchMode() != null && ddTask.getDispatchMode() == 1) {
|
||||||
|
ddTaskMapper.updateTaskStatusByTaskNo(taskNo, 2); // 2=已完成
|
||||||
|
log.info("[上架] dispatchMode=1,仅立库模式:任务 {} 已更新为已完成(task_status=2)", taskNo);
|
||||||
|
} else {
|
||||||
|
log.info("[上架] dispatchMode!=1,非仅立库模式:任务 {} 不在此处置完成,后续流程继续", taskNo);
|
||||||
|
}
|
||||||
|
|
||||||
// ✅ 返回 taskId
|
// ✅ 返回 taskId
|
||||||
return taskId;
|
return taskId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 货物下架
|
* 货物下架
|
||||||
* @param
|
* @param
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ import com.zg.common.exception.ServiceException;
|
|||||||
import com.zg.common.utils.DateUtils;
|
import com.zg.common.utils.DateUtils;
|
||||||
import com.zg.common.utils.SecurityUtils;
|
import com.zg.common.utils.SecurityUtils;
|
||||||
import com.zg.common.utils.StringUtils;
|
import com.zg.common.utils.StringUtils;
|
||||||
|
import com.zg.framework.web.domain.AjaxResult;
|
||||||
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
||||||
import org.apache.poi.ss.usermodel.*;
|
import org.apache.poi.ss.usermodel.*;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@@ -162,10 +163,39 @@ public class GysJhServiceImpl implements IGysJhService
|
|||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<GysJh> getBySapNo(String sapNo) {
|
public AjaxResult getBySapNo(String sapNo) {
|
||||||
return gysJhMapper.getBySapNo(sapNo);
|
|
||||||
|
List<GysJh> list = gysJhMapper.getBySapNo(sapNo);
|
||||||
|
|
||||||
|
AjaxResult result = AjaxResult.success(list);
|
||||||
|
|
||||||
|
if (list == null || list.isEmpty()) {
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 找出已入库(status=1)的物料号,去重、过滤空值
|
||||||
|
List<String> inStockWlNos = list.stream()
|
||||||
|
.filter(x -> x != null && "1".equals(String.valueOf(x.getStatus()).trim()))
|
||||||
|
.map(GysJh::getWlNo)
|
||||||
|
.filter(wlNo -> wlNo != null && !wlNo.trim().isEmpty())
|
||||||
|
.map(String::trim)
|
||||||
|
.distinct()
|
||||||
|
.collect(java.util.stream.Collectors.toList());
|
||||||
|
|
||||||
|
if (!inStockWlNos.isEmpty()) {
|
||||||
|
result.put("warn", true);
|
||||||
|
result.put("inStockWlNos", inStockWlNos);
|
||||||
|
|
||||||
|
// 组装提示文案(可根据前端展示需要调整长度)
|
||||||
|
String msg = "该 SAP 订单号下,以下物料号已入库过,请注意:"
|
||||||
|
+ String.join("、", inStockWlNos);
|
||||||
|
result.put("msg", msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
|||||||
@@ -107,6 +107,11 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
|||||||
return moveRecordMapper.deleteMoveRecordById(id);
|
return moveRecordMapper.deleteMoveRecordById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 处理库存移库操作
|
||||||
|
*
|
||||||
|
* @param dto 移库请求参数(包含原库存ID、移库目标列表等)
|
||||||
|
*/
|
||||||
/**
|
/**
|
||||||
* 处理库存移库操作
|
* 处理库存移库操作
|
||||||
*
|
*
|
||||||
@@ -124,11 +129,6 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
|||||||
throw new ServiceException("目标位置列表不能为空");
|
throw new ServiceException("目标位置列表不能为空");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 0.1 校验每个目标库位与仓库关系
|
|
||||||
for (MoveTargetItem target : dto.getTargets()) {
|
|
||||||
validatePcodeWarehouseRelation(target.getToPcode(), target.getToCangku());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 1. 查询原始库存记录
|
// 1. 查询原始库存记录
|
||||||
RkInfo original = rkInfoMapper.selectRkInfoById(dto.getFromRkId());
|
RkInfo original = rkInfoMapper.selectRkInfoById(dto.getFromRkId());
|
||||||
if (original == null || "1".equals(original.getIsDelete())) {
|
if (original == null || "1".equals(original.getIsDelete())) {
|
||||||
@@ -154,69 +154,61 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
|||||||
String username = dto.getMovedBy();
|
String username = dto.getMovedBy();
|
||||||
Date now = DateUtils.parseDate(dto.getMovedAt());
|
Date now = DateUtils.parseDate(dto.getMovedAt());
|
||||||
|
|
||||||
// ===== 情况一:整库移库(目标总数量 = 原库存,且仅一个目标)=====
|
// ===== 情况一:整库移库(单目标 + 数量相等)=====
|
||||||
if (dto.getTargets().size() == 1 && totalQty.compareTo(realQty) == 0) {
|
if (dto.getTargets().size() == 1 && totalQty.compareTo(realQty) == 0) {
|
||||||
MoveTargetItem target = dto.getTargets().get(0);
|
MoveTargetItem target = dto.getTargets().get(0);
|
||||||
|
|
||||||
// 记录移库前快照
|
// 移库前快照
|
||||||
RkInfo info = new RkInfo();
|
RkInfo snapshot = new RkInfo();
|
||||||
BeanUtils.copyProperties(original, info);
|
BeanUtils.copyProperties(original, snapshot);
|
||||||
|
|
||||||
// ✅ 更新原库存到新位置(统一写入 cangku)
|
// 更新原库存位置
|
||||||
original.setCangku(target.getToCangku());
|
original.setCangku(target.getToCangku());
|
||||||
original.setPcode(target.getToPcode());
|
original.setPcode(target.getToPcode());
|
||||||
original.setTrayCode(target.getToTrayCode());
|
original.setTrayCode(target.getToTrayCode());
|
||||||
|
|
||||||
// ✅ 发生移库就标记
|
|
||||||
original.setHasMoved("1");
|
original.setHasMoved("1");
|
||||||
|
|
||||||
original.setUpdateBy(username);
|
original.setUpdateBy(username);
|
||||||
original.setUpdateTime(now);
|
original.setUpdateTime(now);
|
||||||
rkInfoMapper.updateRkInfo(original);
|
rkInfoMapper.updateRkInfo(original);
|
||||||
|
|
||||||
// 记录移库日志(从 info → target)
|
// 移库记录
|
||||||
moveRecordMapper.insertMoveRecord(createMoveRecord(info, target, dto));
|
moveRecordMapper.insertMoveRecord(
|
||||||
|
createMoveRecord(snapshot, target, dto)
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ===== 情况二 & 三:需要新建多条库存记录 =====
|
// ===== 情况二 / 三:拆分移库 =====
|
||||||
List<RkInfo> insertList = new ArrayList<>();
|
List<RkInfo> insertList = new ArrayList<>();
|
||||||
|
|
||||||
// ✅ 注意:做移库的“来源记录快照”,用于日志一致性(不受后面数量更新影响)
|
// 来源快照(用于日志 & 新库存模板)
|
||||||
RkInfo fromSnapshot = new RkInfo();
|
RkInfo fromSnapshot = new RkInfo();
|
||||||
BeanUtils.copyProperties(original, fromSnapshot);
|
BeanUtils.copyProperties(original, fromSnapshot);
|
||||||
|
|
||||||
// 情况三:部分移库(目标总量 < 原库存) → 原库存数量减少
|
// 情况三:部分移库(原库存减少)
|
||||||
if (totalQty.compareTo(realQty) < 0) {
|
if (totalQty.compareTo(realQty) < 0) {
|
||||||
original.setRealQty(realQty.subtract(totalQty));
|
original.setRealQty(realQty.subtract(totalQty));
|
||||||
|
|
||||||
// ✅ 关键:发生移库就标记(你问的 has_moved 应该是 1)
|
|
||||||
original.setHasMoved("1");
|
original.setHasMoved("1");
|
||||||
|
|
||||||
original.setUpdateBy(username);
|
original.setUpdateBy(username);
|
||||||
original.setUpdateTime(now);
|
original.setUpdateTime(now);
|
||||||
rkInfoMapper.updateRkInfo(original);
|
rkInfoMapper.updateRkInfo(original);
|
||||||
} else {
|
} else {
|
||||||
// 情况二:原库存刚好用完(但目标多个) → 删除原库存
|
// 情况二:原库存刚好用完(但目标多个)
|
||||||
rkInfoMapper.deleteRkInfoById(original.getId());
|
rkInfoMapper.deleteRkInfoById(original.getId());
|
||||||
}
|
}
|
||||||
|
|
||||||
// 新增多条目标库存
|
// 新增目标库存
|
||||||
for (MoveTargetItem target : dto.getTargets()) {
|
for (MoveTargetItem target : dto.getTargets()) {
|
||||||
RkInfo newInfo = new RkInfo();
|
RkInfo newInfo = new RkInfo();
|
||||||
|
|
||||||
// ✅ 以“移库前快照”作为模板,避免被上面修改过数量影响其它字段
|
// 以移库前快照为模板
|
||||||
BeanUtils.copyProperties(fromSnapshot, newInfo, "id");
|
BeanUtils.copyProperties(fromSnapshot, newInfo, "id");
|
||||||
|
|
||||||
// ✅ 目标位置字段
|
|
||||||
newInfo.setCangku(target.getToCangku());
|
newInfo.setCangku(target.getToCangku());
|
||||||
newInfo.setPcode(target.getToPcode());
|
newInfo.setPcode(target.getToPcode());
|
||||||
newInfo.setTrayCode(target.getToTrayCode());
|
newInfo.setTrayCode(target.getToTrayCode());
|
||||||
|
|
||||||
// ✅ 目标数量
|
|
||||||
newInfo.setRealQty(target.getRealQty());
|
newInfo.setRealQty(target.getRealQty());
|
||||||
|
|
||||||
// ✅ 发生移库就标记
|
|
||||||
newInfo.setHasMoved("1");
|
newInfo.setHasMoved("1");
|
||||||
|
|
||||||
newInfo.setCreateBy(username);
|
newInfo.setCreateBy(username);
|
||||||
@@ -226,8 +218,10 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
|||||||
|
|
||||||
insertList.add(newInfo);
|
insertList.add(newInfo);
|
||||||
|
|
||||||
// ✅ 移库记录:从“移库前快照” → 每个 target(更准确)
|
// 移库记录
|
||||||
moveRecordMapper.insertMoveRecord(createMoveRecord(fromSnapshot, target, dto));
|
moveRecordMapper.insertMoveRecord(
|
||||||
|
createMoveRecord(fromSnapshot, target, dto)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!insertList.isEmpty()) {
|
if (!insertList.isEmpty()) {
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.zg.project.wisdom.service.impl;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
import java.time.LocalDate;
|
import java.time.LocalDate;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.temporal.ChronoUnit;
|
import java.time.temporal.ChronoUnit;
|
||||||
@@ -12,6 +14,8 @@ import com.zg.common.exception.ServiceException;
|
|||||||
import com.zg.common.utils.DateUtils;
|
import com.zg.common.utils.DateUtils;
|
||||||
import com.zg.common.utils.SecurityUtils;
|
import com.zg.common.utils.SecurityUtils;
|
||||||
import com.zg.common.utils.StringUtils;
|
import com.zg.common.utils.StringUtils;
|
||||||
|
import com.zg.project.information.domain.Mtd;
|
||||||
|
import com.zg.project.information.mapper.MtdMapper;
|
||||||
import com.zg.project.inventory.AutoInventory.mapper.InventoryMatchScanMapper;
|
import com.zg.project.inventory.AutoInventory.mapper.InventoryMatchScanMapper;
|
||||||
import com.zg.project.inventory.Task.mapper.InventoryTaskMapper;
|
import com.zg.project.inventory.Task.mapper.InventoryTaskMapper;
|
||||||
import com.zg.project.inventory.domain.dto.QueryDTO;
|
import com.zg.project.inventory.domain.dto.QueryDTO;
|
||||||
@@ -30,12 +34,15 @@ import com.zg.project.wisdom.utils.BillNoUtil;
|
|||||||
import com.zg.project.wisdom.utils.CodeConvertUtil;
|
import com.zg.project.wisdom.utils.CodeConvertUtil;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
||||||
import com.zg.project.wisdom.domain.RkInfo;
|
import com.zg.project.wisdom.domain.RkInfo;
|
||||||
import com.zg.project.wisdom.service.IRkInfoService;
|
import com.zg.project.wisdom.service.IRkInfoService;
|
||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
import static com.zg.common.utils.SecurityUtils.getUsername;
|
import static com.zg.common.utils.SecurityUtils.getUsername;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -69,6 +76,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PcdeDetailMapper pcdeDetailMapper;
|
private PcdeDetailMapper pcdeDetailMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MtdMapper mtdMapper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 查询库存单据主
|
* 查询库存单据主
|
||||||
@@ -89,43 +98,19 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
* @return 库存单据主
|
* @return 库存单据主
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public List<RkInfo> selectRkInfoList(RkInfo rkInfo) {
|
public List<RkInfo> selectRkInfoList(RkInfo rkInfo)
|
||||||
|
{
|
||||||
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
||||||
|
|
||||||
List<RkInfo> list = rkInfoMapper.selectRkInfoList(rkInfo);
|
List<RkInfo> list = rkInfoMapper.selectRkInfoList(rkInfo);
|
||||||
LocalDate today = LocalDate.now();
|
|
||||||
|
|
||||||
for (RkInfo info : list) {
|
// 审核开启时,过滤掉“审核失败”的数据
|
||||||
// 计算库龄
|
if (needAudit)
|
||||||
if (info.getRkTime() != null) {
|
{
|
||||||
LocalDate rkDate = info.getRkTime().toInstant()
|
|
||||||
.atZone(ZoneId.systemDefault())
|
|
||||||
.toLocalDate();
|
|
||||||
long days = ChronoUnit.DAYS.between(rkDate, today);
|
|
||||||
info.setStockAge(days);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查询现场图片 + 审核结果
|
|
||||||
AuditSignature signature = auditSignatureMapper.selectPhotoUrlByRkId(info.getId());
|
|
||||||
if (signature != null) {
|
|
||||||
info.setScenePhotoUrl(signature.getSignUrl());
|
|
||||||
info.setAuditResult(signature.getAuditResult());
|
|
||||||
info.setApproverId(signature.getApproverId());
|
|
||||||
} else {
|
|
||||||
info.setScenePhotoUrl(null);
|
|
||||||
info.setAuditResult(null);
|
|
||||||
info.setApproverId(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 审核开启,过滤掉审核结果不是“通过” 且 审核人不为空(说明是审核失败)
|
|
||||||
if (needAudit) {
|
|
||||||
list = list.stream()
|
list = list.stream()
|
||||||
.filter(info ->
|
.filter(info ->
|
||||||
// ① 未审核过(approverId 为空)或
|
info.getApproverId() == null
|
||||||
info.getApproverId() == null ||
|
|| "1".equals(info.getAuditResult())
|
||||||
// ② 审核通过
|
|
||||||
"1".equals(info.getAuditResult())
|
|
||||||
)
|
)
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
@@ -183,6 +168,13 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
return rkInfoMapper.selectGroupedByBill(query, needAudit ? 1 : 0);
|
return rkInfoMapper.selectGroupedByBill(query, needAudit ? 1 : 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<RkInfo> selectBillHeaderList(RkInfoQueryDTO query) {
|
||||||
|
// 同样传入审核开关逻辑(保留原逻辑一致性)
|
||||||
|
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
||||||
|
return rkInfoMapper.selectBillHeaderList(query, needAudit ? 1 : 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public RkInfo selectHeaderByBillNo(String billNo) {
|
public RkInfo selectHeaderByBillNo(String billNo) {
|
||||||
if (StringUtils.isBlank(billNo)) {
|
if (StringUtils.isBlank(billNo)) {
|
||||||
@@ -213,26 +205,62 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
String pcode = rkInfo.getPcode();
|
String pcode = rkInfo.getPcode();
|
||||||
|
|
||||||
// 只有当小仓 + 库位都有的时候才做这层校验
|
// 只有当小仓 + 库位都有的时候才做这层校验
|
||||||
if (StringUtils.isNotBlank(warehouseCode) && StringUtils.isNotBlank(pcode)) {
|
// if (StringUtils.isNotBlank(warehouseCode) && StringUtils.isNotBlank(pcode)) {
|
||||||
|
//
|
||||||
// 临时组装一个 PcRkInfoBatchDTO,专门给 validateWarehouseAndPcode 用
|
// // 临时组装一个 PcRkInfoBatchDTO,专门给 validateWarehouseAndPcode 用
|
||||||
PcRkInfoBatchDTO tmpDto = new PcRkInfoBatchDTO();
|
// PcRkInfoBatchDTO tmpDto = new PcRkInfoBatchDTO();
|
||||||
tmpDto.setWarehouseCode(warehouseCode);
|
// tmpDto.setWarehouseCode(warehouseCode);
|
||||||
|
//
|
||||||
List<PcRkInfoItemDTO> rkList = new ArrayList<>();
|
// List<PcRkInfoItemDTO> rkList = new ArrayList<>();
|
||||||
PcRkInfoItemDTO item = new PcRkInfoItemDTO();
|
// PcRkInfoItemDTO item = new PcRkInfoItemDTO();
|
||||||
item.setPcode(pcode);
|
// item.setPcode(pcode);
|
||||||
rkList.add(item);
|
// rkList.add(item);
|
||||||
|
//
|
||||||
tmpDto.setRkList(rkList);
|
// tmpDto.setRkList(rkList);
|
||||||
|
//
|
||||||
validateWarehouseAndPcode(tmpDto);
|
// validateWarehouseAndPcode(tmpDto);
|
||||||
}
|
// }
|
||||||
|
|
||||||
// ====== 校验通过再更新 ======
|
// ====== 校验通过再更新 ======
|
||||||
return rkInfoMapper.updateRkInfo(rkInfo);
|
return rkInfoMapper.updateRkInfo(rkInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public int updateRkInfoByBillNoCk(RkInfo rkInfo) {
|
||||||
|
|
||||||
|
// ====== 基础校验 ======
|
||||||
|
if (StringUtils.isBlank(rkInfo.getBillNoCk())) {
|
||||||
|
throw new ServiceException("出库单据号 billNoCk 不能为空");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用审计字段
|
||||||
|
rkInfo.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
rkInfo.setUpdateBy(SecurityUtils.getUserId().toString());
|
||||||
|
|
||||||
|
// ====== 仓库 + 库位校验(保持与你 updateRkInfo 完全一致) ======
|
||||||
|
String warehouseCode = rkInfo.getWarehouseCode();
|
||||||
|
if (StringUtils.isBlank(warehouseCode)) {
|
||||||
|
warehouseCode = rkInfo.getCangku();
|
||||||
|
}
|
||||||
|
String pcode = rkInfo.getPcode();
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(warehouseCode) && StringUtils.isNotBlank(pcode)) {
|
||||||
|
PcRkInfoBatchDTO tmpDto = new PcRkInfoBatchDTO();
|
||||||
|
tmpDto.setWarehouseCode(warehouseCode);
|
||||||
|
|
||||||
|
PcRkInfoItemDTO item = new PcRkInfoItemDTO();
|
||||||
|
item.setPcode(pcode);
|
||||||
|
|
||||||
|
tmpDto.setRkList(Collections.singletonList(item));
|
||||||
|
validateWarehouseAndPcode(tmpDto);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ====== 按 bill_no_ck 批量更新 ======
|
||||||
|
return rkInfoMapper.updateByBillNoCk(rkInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 批量处理撤销入库 / 撤销出库的逻辑(不是通用删除接口)
|
* 批量处理撤销入库 / 撤销出库的逻辑(不是通用删除接口)
|
||||||
*
|
*
|
||||||
@@ -366,27 +394,31 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
String userId = SecurityUtils.getUserId().toString();
|
String userId = SecurityUtils.getUserId().toString();
|
||||||
Date now = DateUtils.getNowDate();
|
Date now = DateUtils.getNowDate();
|
||||||
|
|
||||||
// 🚩 0. 校验库位是否属于当前小仓
|
// ✅ 0. 只有前端传了库位编码,才做“库位属于当前小仓”的校验(否则不传库位会被拦截)
|
||||||
validateWarehouseAndPcode(dto);
|
/*暂时去掉校验*/
|
||||||
|
// boolean hasPcode = list != null && list.stream()
|
||||||
|
// .anyMatch(x -> StringUtils.isNotBlank(x.getPcode()));
|
||||||
|
// if (hasPcode) {
|
||||||
|
// validateWarehouseAndPcode(dto);
|
||||||
|
// }
|
||||||
|
|
||||||
// ✅ 1. 供应计划扣减映射
|
// ✅ 1. 供应计划扣减映射(同一个 gysJhId 多条明细时,realQty 累加)
|
||||||
Map<Long, BigDecimal> realQtyMap = list.stream()
|
Map<Long, BigDecimal> realQtyMap = list.stream()
|
||||||
.filter(item -> item.getGysJhId() != null && item.getRealQty() != null)
|
.filter(item -> item.getGysJhId() != null && item.getRealQty() != null)
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
PcRkInfoItemDTO::getGysJhId,
|
PcRkInfoItemDTO::getGysJhId,
|
||||||
PcRkInfoItemDTO::getRealQty,
|
PcRkInfoItemDTO::getRealQty,
|
||||||
(a, b) -> b
|
(a, b) -> a.add(b)
|
||||||
));
|
));
|
||||||
|
|
||||||
// ✅ 2-4. 供应计划扣减&状态更新
|
// ✅ 2-4. 供应计划扣减&状态更新(保持你原逻辑)
|
||||||
if (!realQtyMap.isEmpty()) {
|
if (!realQtyMap.isEmpty()) {
|
||||||
List<GysJh> jhList = gysJhMapper.selectByIds(new ArrayList<>(realQtyMap.keySet()));
|
List<GysJh> jhList = gysJhMapper.selectByIds(new ArrayList<>(realQtyMap.keySet()));
|
||||||
Set<Long> idsToUpdateStatus = new HashSet<>();
|
Set<Long> idsToUpdateStatus = new HashSet<>();
|
||||||
|
|
||||||
for (GysJh jh : jhList) {
|
for (GysJh jh : jhList) {
|
||||||
Long jhId = jh.getId();
|
Long jhId = jh.getId();
|
||||||
BigDecimal planQty =
|
BigDecimal planQty = jh.getJhQty() == null ? BigDecimal.ZERO : jh.getJhQty();
|
||||||
jh.getJhQty() == null ? BigDecimal.ZERO : jh.getJhQty();
|
|
||||||
BigDecimal realQty = realQtyMap.get(jhId);
|
BigDecimal realQty = realQtyMap.get(jhId);
|
||||||
if (realQty == null) {
|
if (realQty == null) {
|
||||||
continue;
|
continue;
|
||||||
@@ -395,13 +427,11 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
boolean isEqual = realQty.compareTo(planQty) == 0;
|
boolean isEqual = realQty.compareTo(planQty) == 0;
|
||||||
|
|
||||||
if (!isEqual) {
|
if (!isEqual) {
|
||||||
// 部分入库:扣减计划数量
|
|
||||||
gysJhMapper.decreaseJhQtyById(jhId, realQty);
|
gysJhMapper.decreaseJhQtyById(jhId, realQty);
|
||||||
if (!needAudit) {
|
if (!needAudit) {
|
||||||
gysJhMapper.updateStatusById(jhId, "2"); // 2 = 部分入库
|
gysJhMapper.updateStatusById(jhId, "2"); // 2 = 部分入库
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// 全部入库:状态=1
|
|
||||||
if (!needAudit) {
|
if (!needAudit) {
|
||||||
gysJhMapper.updateStatusById(jhId, "1"); // 1 = 全部入库
|
gysJhMapper.updateStatusById(jhId, "1"); // 1 = 全部入库
|
||||||
}
|
}
|
||||||
@@ -413,27 +443,18 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ✅ 5. 构建 RkInfo 入库记录(注意:小仓 = dto.getWarehouseCode())
|
// ✅ 5. 构建 RkInfo 入库记录(库位字段按“前端是否传 pcode”决定是否设置)
|
||||||
for (PcRkInfoItemDTO item : list) {
|
for (PcRkInfoItemDTO item : list) {
|
||||||
RkInfo rk = new RkInfo();
|
RkInfo rk = new RkInfo();
|
||||||
// 物料、项目、供应商、xj(县局)、数量等等从 item 拷贝
|
|
||||||
BeanUtils.copyProperties(item, rk);
|
BeanUtils.copyProperties(item, rk);
|
||||||
|
|
||||||
rk.setBillNo(billNo);
|
rk.setBillNo(billNo);
|
||||||
rk.setRkType(dto.getRkType());
|
rk.setRkType(dto.getRkType());
|
||||||
rk.setWlType(dto.getWlType());
|
rk.setWlType(dto.getWlType());
|
||||||
rk.setLihuoY(dto.getLihuoY());
|
rk.setLihuoY(dto.getLihuoY());
|
||||||
|
|
||||||
// 🚩 所属小仓:页面选的小仓编码
|
|
||||||
rk.setCangku(dto.getWarehouseCode());
|
rk.setCangku(dto.getWarehouseCode());
|
||||||
|
|
||||||
// 🚩 入库时间:页面传,若为空则使用当前时间
|
|
||||||
rk.setRkTime(dto.getRkTime() != null ? dto.getRkTime() : DateUtils.getNowDate());
|
rk.setRkTime(dto.getRkTime() != null ? dto.getRkTime() : DateUtils.getNowDate());
|
||||||
|
|
||||||
// 库位 encodedId
|
|
||||||
String encodedId = pcdeDetailMapper.selectEncodedIdByPcode(item.getPcode());
|
|
||||||
rk.setPcodeId(encodedId);
|
|
||||||
|
|
||||||
rk.setCreateBy(userId);
|
rk.setCreateBy(userId);
|
||||||
rk.setCreateTime(now);
|
rk.setCreateTime(now);
|
||||||
rk.setIsDelete("0");
|
rk.setIsDelete("0");
|
||||||
@@ -442,6 +463,45 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
rk.setFycde1(item.getFycde1());
|
rk.setFycde1(item.getFycde1());
|
||||||
rk.setFycde2(item.getFycde2());
|
rk.setFycde2(item.getFycde2());
|
||||||
|
|
||||||
|
if (StringUtils.isBlank(rk.getDw()) && StringUtils.isNotBlank(item.getWlNo())) {
|
||||||
|
Mtd mtd = mtdMapper.selectMtdByMid(item.getWlNo().trim());
|
||||||
|
if (mtd != null && StringUtils.isNotBlank(mtd.getUnt())) {
|
||||||
|
rk.setDw(mtd.getUnt());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 库位编码前端不传,就不设置库位相关字段(并且不查 encodedId)
|
||||||
|
if (StringUtils.isNotBlank(item.getPcode())) {
|
||||||
|
// pcode 有值:允许设置/绑定库位
|
||||||
|
rk.setPcode(item.getPcode());
|
||||||
|
|
||||||
|
// 只有有 pcode 才查 pcodeId
|
||||||
|
String encodedId = pcdeDetailMapper.selectEncodedIdByPcodeAndWarehouse(
|
||||||
|
item.getPcode(),
|
||||||
|
dto.getWarehouseCode()
|
||||||
|
);
|
||||||
|
rk.setPcodeId(encodedId);
|
||||||
|
|
||||||
|
// 这些字段如果前端没传,保持 null;如果传了就写入
|
||||||
|
if (StringUtils.isNotBlank(item.getTrayCode())) {
|
||||||
|
rk.setTrayCode(item.getTrayCode());
|
||||||
|
} else {
|
||||||
|
rk.setTrayCode(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (StringUtils.isNotBlank(item.getEntityId())) {
|
||||||
|
rk.setEntityId(item.getEntityId());
|
||||||
|
} else {
|
||||||
|
rk.setEntityId(null);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// pcode 不传:明确不设置库位信息
|
||||||
|
rk.setPcode(null);
|
||||||
|
rk.setPcodeId(null);
|
||||||
|
rk.setTrayCode(null);
|
||||||
|
rk.setEntityId(null);
|
||||||
|
}
|
||||||
|
|
||||||
if (needAudit) {
|
if (needAudit) {
|
||||||
rk.setStatus("0"); // 待审核
|
rk.setStatus("0"); // 待审核
|
||||||
rk.setIsChuku("2"); // 待入库(审核中)
|
rk.setIsChuku("2"); // 待入库(审核中)
|
||||||
@@ -449,6 +509,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
rk.setStatus("1"); // 审核通过
|
rk.setStatus("1"); // 审核通过
|
||||||
rk.setIsChuku("0"); // 已入库
|
rk.setIsChuku("0"); // 已入库
|
||||||
}
|
}
|
||||||
|
|
||||||
rkInfos.add(rk);
|
rkInfos.add(rk);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -465,15 +526,18 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
AuditSignature photo = new AuditSignature();
|
AuditSignature photo = new AuditSignature();
|
||||||
photo.setRkId(rk.getId());
|
photo.setRkId(rk.getId());
|
||||||
photo.setBillNo(billNo);
|
photo.setBillNo(billNo);
|
||||||
photo.setBillType("0"); // 入库
|
photo.setBillType("0");
|
||||||
photo.setAuditResult("2"); // 待审核
|
photo.setAuditResult("2");
|
||||||
photo.setSignerId(userId);
|
photo.setSignerId(userId);
|
||||||
photo.setSignerRole("2"); // 现场照片
|
photo.setSignerRole("2");
|
||||||
photo.setImageType("1"); // photo
|
photo.setImageType("1");
|
||||||
photo.setSignUrl(item.getPhotoUrl());
|
photo.setSignUrl(item.getPhotoUrl());
|
||||||
photo.setSignTime(now);
|
photo.setSignTime(now);
|
||||||
photo.setPcode(item.getPcode());
|
|
||||||
photo.setTrayCode(item.getTrayCode());
|
// 这里照旧:有库位就写库位/托盘;没库位就是 null
|
||||||
|
photo.setPcode(rk.getPcode());
|
||||||
|
photo.setTrayCode(rk.getTrayCode());
|
||||||
|
|
||||||
photo.setApproverId(dto.getApproverId());
|
photo.setApproverId(dto.getApproverId());
|
||||||
photo.setIsCurrent("1");
|
photo.setIsCurrent("1");
|
||||||
photo.setIsDelete("0");
|
photo.setIsDelete("0");
|
||||||
@@ -493,15 +557,15 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
|
|
||||||
AuditSignature mainSign = new AuditSignature();
|
AuditSignature mainSign = new AuditSignature();
|
||||||
mainSign.setBillNo(billNo);
|
mainSign.setBillNo(billNo);
|
||||||
mainSign.setBillType("0"); // 入库
|
mainSign.setBillType("0");
|
||||||
mainSign.setSignerId(userId);
|
mainSign.setSignerId(userId);
|
||||||
mainSign.setSignerRole("0"); // 发起人
|
mainSign.setSignerRole("0");
|
||||||
mainSign.setApproverId(dto.getApproverId());
|
mainSign.setApproverId(dto.getApproverId());
|
||||||
mainSign.setSignUrl(dto.getSignatureUrl());
|
mainSign.setSignUrl(dto.getSignatureUrl());
|
||||||
mainSign.setImageType("0"); // sign
|
mainSign.setImageType("0");
|
||||||
mainSign.setSignTime(now);
|
mainSign.setSignTime(now);
|
||||||
mainSign.setIsCurrent("1");
|
mainSign.setIsCurrent("1");
|
||||||
mainSign.setAuditResult("2"); // 待审核
|
mainSign.setAuditResult("2");
|
||||||
mainSign.setIsDelete("0");
|
mainSign.setIsDelete("0");
|
||||||
mainSign.setCreateBy(userId);
|
mainSign.setCreateBy(userId);
|
||||||
mainSign.setCreateTime(now);
|
mainSign.setCreateTime(now);
|
||||||
@@ -616,8 +680,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional(rollbackFor = Exception.class)
|
||||||
public int batchInsertApp(RkInfoBatchDTO dto) {
|
public int batchInsertApp(RkInfoBatchDTO dto) {
|
||||||
|
|
||||||
// ✅ 0. 小仓 + 库位一致性校验(统一用 warehouseCode)
|
// // ✅ 0. 小仓 + 库位一致性校验(统一用 warehouseCode)
|
||||||
validateWarehouseAndPcode(dto);
|
// validateWarehouseAndPcode(dto);
|
||||||
|
|
||||||
List<RkInfo> saveList = new ArrayList<>();
|
List<RkInfo> saveList = new ArrayList<>();
|
||||||
String userId = SecurityUtils.getUserId().toString();
|
String userId = SecurityUtils.getUserId().toString();
|
||||||
@@ -871,10 +935,97 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
||||||
|
|
||||||
// Step 2: 生成出库单据号
|
// Step 2: 生成出库单据号
|
||||||
String billNo = BillNoUtil.generateTodayBillNo("RK", rkInfoMapper);
|
String billNo = BillNoUtil.generateTodayBillNo("CK", rkInfoMapper);
|
||||||
|
|
||||||
// Step 3: 批量更新 rk_info 出库字段
|
// 记录:原记录id -> 出库记录id(部分出库时,照片要绑定到新插入的出库记录)
|
||||||
|
Map<Long, Long> outRkIdMap = new HashMap<>();
|
||||||
|
|
||||||
|
// Step 3: 出库处理(支持部分出库)
|
||||||
for (StockOutItemDTO item : dto.getCkList()) {
|
for (StockOutItemDTO item : dto.getCkList()) {
|
||||||
|
|
||||||
|
if (item.getId() == null) {
|
||||||
|
throw new ServiceException("出库记录ID不能为空");
|
||||||
|
}
|
||||||
|
if (item.getRealQty() == null || item.getRealQty().compareTo(BigDecimal.ZERO) <= 0) {
|
||||||
|
throw new ServiceException("出库数量必须大于0,id=" + item.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 3.1 查询原库存记录
|
||||||
|
RkInfo db = rkInfoMapper.selectRkInfoById(item.getId());
|
||||||
|
if (db == null) {
|
||||||
|
throw new ServiceException("库存记录不存在,id=" + item.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
BigDecimal oldQty = db.getRealQty() == null ? BigDecimal.ZERO : db.getRealQty();
|
||||||
|
BigDecimal outQty = item.getRealQty();
|
||||||
|
|
||||||
|
// 3.2 校验不能超出库存
|
||||||
|
BigDecimal newQty = oldQty.subtract(outQty);
|
||||||
|
if (newQty.compareTo(BigDecimal.ZERO) < 0) {
|
||||||
|
throw new ServiceException("出库数量不能大于库存数量,id=" + item.getId()
|
||||||
|
+ ",库存=" + oldQty + ",出库=" + outQty);
|
||||||
|
}
|
||||||
|
|
||||||
|
boolean partialOut = newQty.compareTo(BigDecimal.ZERO) > 0;
|
||||||
|
|
||||||
|
if (partialOut) {
|
||||||
|
// ✅ 部分出库:原记录只扣减 real_qty
|
||||||
|
RkInfo reduce = new RkInfo();
|
||||||
|
reduce.setId(db.getId());
|
||||||
|
reduce.setRealQty(newQty);
|
||||||
|
reduce.setUpdateBy(userId);
|
||||||
|
reduce.setUpdateTime(now);
|
||||||
|
rkInfoMapper.updateById(reduce);
|
||||||
|
|
||||||
|
// ✅ 插入一条新的“出库记录”:复制原记录 + 覆盖本次出库字段
|
||||||
|
RkInfo outRow = new RkInfo();
|
||||||
|
BeanUtils.copyProperties(db, outRow);
|
||||||
|
outRow.setId(null);
|
||||||
|
|
||||||
|
// —— 出库这次操作字段
|
||||||
|
outRow.setBillNoCk(billNo);
|
||||||
|
outRow.setIsDelivery(dto.getIsDelivery());
|
||||||
|
outRow.setCkType(dto.getCkType());
|
||||||
|
outRow.setTeamCode(dto.getTeamCode());
|
||||||
|
outRow.setLyTime(now);
|
||||||
|
outRow.setCkLihuoY(dto.getCkLihuoY());
|
||||||
|
outRow.setCkRemark(item.getCkRemark());
|
||||||
|
outRow.setXmNoCk(dto.getXmNoCk());
|
||||||
|
outRow.setXmMsCk(dto.getXmMsCk());
|
||||||
|
|
||||||
|
// 新出库记录数量=本次出库数量
|
||||||
|
outRow.setRealQty(outQty);
|
||||||
|
|
||||||
|
// 借料字段(仅 JLCK 才写)
|
||||||
|
if ("JLCK".equals(dto.getCkType())) {
|
||||||
|
outRow.setIsBorrowed("1");
|
||||||
|
outRow.setBorrowTime(dto.getBorrowTime());
|
||||||
|
outRow.setReturnTime(dto.getReturnTime());
|
||||||
|
}
|
||||||
|
|
||||||
|
// 审核状态 + is_chuku(部分出库:新出库记录按正常出库逻辑走)
|
||||||
|
if (needAudit) {
|
||||||
|
outRow.setStatus("3"); // 出库待审核
|
||||||
|
outRow.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "2");
|
||||||
|
} else {
|
||||||
|
outRow.setStatus("1"); // 审核通过
|
||||||
|
outRow.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "1");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 通用字段
|
||||||
|
outRow.setIsDelete("0");
|
||||||
|
outRow.setCreateBy(userId);
|
||||||
|
outRow.setCreateTime(now);
|
||||||
|
outRow.setUpdateBy(userId);
|
||||||
|
outRow.setUpdateTime(now);
|
||||||
|
|
||||||
|
rkInfoMapper.insertRkInfo(outRow);
|
||||||
|
|
||||||
|
// 记录映射:照片绑定新出库记录
|
||||||
|
outRkIdMap.put(db.getId(), outRow.getId());
|
||||||
|
|
||||||
|
} else {
|
||||||
|
// ✅ 全部出库:不扣减 real_qty,直接改状态
|
||||||
RkInfo update = new RkInfo();
|
RkInfo update = new RkInfo();
|
||||||
update.setId(item.getId());
|
update.setId(item.getId());
|
||||||
update.setBillNoCk(billNo);
|
update.setBillNoCk(billNo);
|
||||||
@@ -904,9 +1055,13 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
}
|
}
|
||||||
|
|
||||||
rkInfoMapper.updateById(update);
|
rkInfoMapper.updateById(update);
|
||||||
|
|
||||||
|
// 全出库:照片绑定原记录
|
||||||
|
outRkIdMap.put(item.getId(), item.getId());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 4: 如果启用审核,写入签字记录
|
// Step 4: 如果启用审核,写入签字记录(部分出库:照片绑定新出库记录ID)
|
||||||
if (needAudit) {
|
if (needAudit) {
|
||||||
List<AuditSignature> recordList = new ArrayList<>();
|
List<AuditSignature> recordList = new ArrayList<>();
|
||||||
|
|
||||||
@@ -934,6 +1089,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
for (StockOutItemDTO item : dto.getCkList()) {
|
for (StockOutItemDTO item : dto.getCkList()) {
|
||||||
if (StringUtils.isBlank(item.getPhotoUrl())) continue;
|
if (StringUtils.isBlank(item.getPhotoUrl())) continue;
|
||||||
|
|
||||||
|
Long rkIdForPhoto = outRkIdMap.getOrDefault(item.getId(), item.getId());
|
||||||
|
|
||||||
AuditSignature photo = new AuditSignature();
|
AuditSignature photo = new AuditSignature();
|
||||||
photo.setBillNo(billNo);
|
photo.setBillNo(billNo);
|
||||||
photo.setBillType("1");
|
photo.setBillType("1");
|
||||||
@@ -948,9 +1105,12 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
photo.setIsDelete("0");
|
photo.setIsDelete("0");
|
||||||
photo.setCreateBy(userId);
|
photo.setCreateBy(userId);
|
||||||
photo.setCreateTime(now);
|
photo.setCreateTime(now);
|
||||||
photo.setRkId(item.getId());
|
|
||||||
|
// ✅ 关键:部分出库绑定“新出库记录”的 rk_id
|
||||||
|
photo.setRkId(rkIdForPhoto);
|
||||||
photo.setPcode(item.getPcode());
|
photo.setPcode(item.getPcode());
|
||||||
photo.setTrayCode(item.getTrayCode());
|
photo.setTrayCode(item.getTrayCode());
|
||||||
|
|
||||||
recordList.add(photo);
|
recordList.add(photo);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -962,6 +1122,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
return dto.getCkList().size();
|
return dto.getCkList().size();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Transactional(rollbackFor = Exception.class) // 开启事务,异常时回滚
|
@Transactional(rollbackFor = Exception.class) // 开启事务,异常时回滚
|
||||||
public void matchWithStatus(QueryDTO dto) {
|
public void matchWithStatus(QueryDTO dto) {
|
||||||
@@ -1110,8 +1271,6 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
@Override
|
@Override
|
||||||
public int refundMaterial(RefundRequestDTO dto) {
|
public int refundMaterial(RefundRequestDTO dto) {
|
||||||
Long originalId = dto.getOriginalId();
|
Long originalId = dto.getOriginalId();
|
||||||
String newPcode = dto.getPcode();
|
|
||||||
|
|
||||||
// 1. 查原出库记录
|
// 1. 查原出库记录
|
||||||
RkInfo original = rkInfoMapper.selectRkInfoById(originalId);
|
RkInfo original = rkInfoMapper.selectRkInfoById(originalId);
|
||||||
if (original == null || "1".equals(original.getIsDelete())) {
|
if (original == null || "1".equals(original.getIsDelete())) {
|
||||||
@@ -1123,9 +1282,11 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
BeanUtils.copyProperties(original, newEntry);
|
BeanUtils.copyProperties(original, newEntry);
|
||||||
newEntry.setId(null);
|
newEntry.setId(null);
|
||||||
newEntry.setIsChuku("0");
|
newEntry.setIsChuku("0");
|
||||||
newEntry.setPcode(newPcode);
|
newEntry.setPcode(dto.getPcode());
|
||||||
|
newEntry.setCangku(dto.getWarehouseCode());
|
||||||
newEntry.setRkType(dto.getRkType());
|
newEntry.setRkType(dto.getRkType());
|
||||||
newEntry.setRkTime(DateUtils.getNowDate());
|
newEntry.setRkTime(DateUtils.getNowDate());
|
||||||
|
newEntry.setBorrowTime(original.getBorrowTime());
|
||||||
newEntry.setBillNo(BillNoUtil.generateTodayBillNo("RK", rkInfoMapper));
|
newEntry.setBillNo(BillNoUtil.generateTodayBillNo("RK", rkInfoMapper));
|
||||||
newEntry.setCreateBy(SecurityUtils.getUserId().toString());
|
newEntry.setCreateBy(SecurityUtils.getUserId().toString());
|
||||||
newEntry.setCreateTime(DateUtils.getNowDate());
|
newEntry.setCreateTime(DateUtils.getNowDate());
|
||||||
@@ -1143,6 +1304,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
update.setReturnTime(DateUtils.getNowDate());
|
update.setReturnTime(DateUtils.getNowDate());
|
||||||
update.setUpdateBy(getUsername());
|
update.setUpdateBy(getUsername());
|
||||||
update.setUpdateTime(DateUtils.getNowDate());
|
update.setUpdateTime(DateUtils.getNowDate());
|
||||||
|
update.setPcode(dto.getPcode());
|
||||||
|
update.setCangku(dto.getWarehouseCode());
|
||||||
rkInfoMapper.updateById(update);
|
rkInfoMapper.updateById(update);
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
@@ -1204,21 +1367,16 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
return rkInfoMapper.listRkInfoByPcode(pcode);
|
return rkInfoMapper.listRkInfoByPcode(pcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<RkInfo> selectAllRkInfo(RkInfo query) {
|
public List<RkInfo> selectAllRkInfo(RkInfo query) {
|
||||||
return rkInfoMapper.selectAllRkInfo(query);
|
return rkInfoMapper.selectAllRkInfo(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Long selectStatistics(RkInfo query) {
|
public List<RkInfo> selectRkInfoPageList(RkInfo query) {
|
||||||
return rkInfoMapper.selectStatistics(query);
|
return rkInfoMapper.selectRkInfoPageList(query);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public Long selectPcde(RkInfo query) {
|
|
||||||
return rkInfoMapper.selectPcde(query);
|
|
||||||
}
|
|
||||||
@Override
|
@Override
|
||||||
public int updateBillInfo(RkInfo query) {
|
public int updateBillInfo(RkInfo query) {
|
||||||
return rkInfoMapper.updateBillInfo(query);
|
return rkInfoMapper.updateBillInfo(query);
|
||||||
@@ -1256,7 +1414,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
|||||||
e.setBillNo(dto.getBillNo());
|
e.setBillNo(dto.getBillNo());
|
||||||
e.setRkType(dto.getRkType());
|
e.setRkType(dto.getRkType());
|
||||||
e.setWlType(dto.getWlType());
|
e.setWlType(dto.getWlType());
|
||||||
e.setWarehouseCode(dto.getWarehouseCode());
|
e.setCangku(dto.getWarehouseCode());
|
||||||
e.setLihuoY(dto.getLihuoY());
|
e.setLihuoY(dto.getLihuoY());
|
||||||
e.setRkTime(rkTime);
|
e.setRkTime(rkTime);
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,13 @@ import com.zg.common.exception.ServiceException;
|
|||||||
import com.zg.common.utils.DateUtils;
|
import com.zg.common.utils.DateUtils;
|
||||||
import com.zg.common.utils.StringUtils;
|
import com.zg.common.utils.StringUtils;
|
||||||
import com.zg.common.utils.poi.ExcelUtil;
|
import com.zg.common.utils.poi.ExcelUtil;
|
||||||
|
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
||||||
import com.zg.project.wisdom.domain.vo.*;
|
import com.zg.project.wisdom.domain.vo.*;
|
||||||
import com.zg.project.wisdom.mapper.GysJhMapper;
|
import com.zg.project.wisdom.mapper.GysJhMapper;
|
||||||
|
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
||||||
import com.zg.project.wisdom.mapper.RkStatisticsMapper;
|
import com.zg.project.wisdom.mapper.RkStatisticsMapper;
|
||||||
import com.zg.project.wisdom.service.RkStatisticsService;
|
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -23,9 +26,12 @@ import java.util.*;
|
|||||||
@Service
|
@Service
|
||||||
public class RkStatisticsServiceImpl implements RkStatisticsService {
|
public class RkStatisticsServiceImpl implements RkStatisticsService {
|
||||||
|
|
||||||
@Resource
|
@Autowired
|
||||||
private RkStatisticsMapper rkStatisticsMapper;
|
private RkStatisticsMapper rkStatisticsMapper;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RkInfoMapper rkInfoMapper;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Map<String, Object>> getAgeStatsAsList() {
|
public List<Map<String, Object>> getAgeStatsAsList() {
|
||||||
@@ -426,4 +432,24 @@ public class RkStatisticsServiceImpl implements RkStatisticsService {
|
|||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> selectStockStatistics(RkInfoQueryDTO query) {
|
||||||
|
|
||||||
|
if (query.getIsChuku() == null) {
|
||||||
|
query.setIsChuku("0"); // 默认只查在库
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> result = rkInfoMapper.selectStockStatistics(query);
|
||||||
|
|
||||||
|
// 处理空值情况,防止前端拿到 null 报错
|
||||||
|
if (result == null) {
|
||||||
|
result = new HashMap<>();
|
||||||
|
}
|
||||||
|
result.putIfAbsent("sumMoney", 0);
|
||||||
|
result.putIfAbsent("sumQty", 0);
|
||||||
|
result.putIfAbsent("pcdeCount", 0);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,45 +4,63 @@ import com.zg.project.wisdom.mapper.RkInfoMapper;
|
|||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Map;
|
import java.util.concurrent.ThreadLocalRandom;
|
||||||
import java.util.concurrent.ConcurrentHashMap;
|
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 单据号生成工具类
|
||||||
|
*
|
||||||
|
* 目标:
|
||||||
|
* 1) 每次业务操作都生成全新单据号(不依赖历史,不查DB)
|
||||||
|
* 2) 单号短、可读
|
||||||
|
* 3) 避免串单:不同出库操作绝不复用同一个 billNo
|
||||||
|
*
|
||||||
|
* 推荐格式:
|
||||||
|
* CK24011315384227
|
||||||
|
* 前缀 + yyMMdd + HHmmss + 2位随机数
|
||||||
|
*/
|
||||||
public class BillNoUtil {
|
public class BillNoUtil {
|
||||||
|
|
||||||
// 内存缓存:key = prefix + yyyyMMdd
|
private static final String DEFAULT_PREFIX = "RK";
|
||||||
private static final Map<String, AtomicInteger> DAILY_SEQUENCE_MAP = new ConcurrentHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 生成当天单据号(格式:RK20251222_1)
|
* 生成单据号(短号,不查数据库)
|
||||||
|
* 格式:PREFIX + yyMMdd + HHmmss + 2位随机数
|
||||||
|
* 示例:CK24011315384227
|
||||||
|
*
|
||||||
|
* @param prefix 单据前缀:RK/CK/...
|
||||||
|
* @param rkInfoMapper 兼容旧签名(不再使用,可传 null)
|
||||||
*/
|
*/
|
||||||
public static synchronized String generateTodayBillNo(String prefix, RkInfoMapper rkInfoMapper) {
|
public static synchronized String generateTodayBillNo(String prefix, RkInfoMapper rkInfoMapper) {
|
||||||
|
|
||||||
// ✅ 先得到最终前缀(不要让 lambda 捕获一个会被重新赋值的变量)
|
// 前缀处理
|
||||||
final String finalPrefix = (prefix == null || prefix.trim().isEmpty()) ? "RK" : prefix.trim();
|
final String p = (prefix == null || prefix.trim().isEmpty())
|
||||||
|
? DEFAULT_PREFIX
|
||||||
|
: prefix.trim().toUpperCase();
|
||||||
|
|
||||||
// ✅ today / key 也用 final,确保 lambda 可用
|
// 时间到秒:yyMMddHHmmss(12位)
|
||||||
final String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
String time = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
|
||||||
final String key = finalPrefix + today;
|
|
||||||
final String likePrefix = finalPrefix + today + "_";
|
|
||||||
|
|
||||||
// 如果当天还没初始化,从数据库取最大号
|
// 2位随机数:10~99(避免同一秒内多次点击撞号)
|
||||||
AtomicInteger counter = DAILY_SEQUENCE_MAP.computeIfAbsent(key, k -> {
|
int rnd = ThreadLocalRandom.current().nextInt(10, 100);
|
||||||
|
|
||||||
String maxBillNo = rkInfoMapper.selectMaxBillNo(likePrefix);
|
return p + time + rnd;
|
||||||
|
|
||||||
int start = 1;
|
|
||||||
if (maxBillNo != null) {
|
|
||||||
try {
|
|
||||||
String seqStr = maxBillNo.substring(maxBillNo.lastIndexOf("_") + 1);
|
|
||||||
start = Integer.parseInt(seqStr) + 1;
|
|
||||||
} catch (Exception ignored) {
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return new AtomicInteger(start);
|
|
||||||
});
|
|
||||||
|
|
||||||
int seq = counter.getAndIncrement();
|
/**
|
||||||
return finalPrefix + today + "_" + seq;
|
* 需要更短的版本(可选)
|
||||||
|
* 格式:PREFIX + yyMMdd + 4位随机数
|
||||||
|
* 示例:CK2401134837
|
||||||
|
*
|
||||||
|
* 注意:比带秒的版本更短,但理论碰撞概率略高(一般够用)
|
||||||
|
*/
|
||||||
|
public static synchronized String generateShortBillNo(String prefix) {
|
||||||
|
final String p = (prefix == null || prefix.trim().isEmpty())
|
||||||
|
? DEFAULT_PREFIX
|
||||||
|
: prefix.trim().toUpperCase();
|
||||||
|
|
||||||
|
String day = new SimpleDateFormat("yyMMdd").format(new Date());
|
||||||
|
int rnd4 = ThreadLocalRandom.current().nextInt(1000, 10000);
|
||||||
|
|
||||||
|
return p + day + rnd4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,10 +6,10 @@ spring:
|
|||||||
druid:
|
druid:
|
||||||
# 主库数据源
|
# 主库数据源
|
||||||
master:
|
master:
|
||||||
# url: jdbc:mysql://101.132.133.142:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://47.100.212.83:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# url: jdbc:mysql://192.168.1.28:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
url: jdbc:mysql://192.168.1.28:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# url: jdbc:mysql://192.168.1.192:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://192.168.1.192:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
url: jdbc:mysql://192.168.1.251:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://192.168.1.251:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
# url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
# url: jdbc:mysql://localhost:3306/wisdom?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
|
||||||
username: root
|
username: root
|
||||||
password: shzg
|
password: shzg
|
||||||
|
|||||||
@@ -170,51 +170,3 @@ mock:
|
|||||||
#配送系统中调用大模型进行图片识别
|
#配送系统中调用大模型进行图片识别
|
||||||
qwen-ocr:
|
qwen-ocr:
|
||||||
base-url: http://192.168.1.253:8087/ocr/extractErpByBase64
|
base-url: http://192.168.1.253:8087/ocr/extractErpByBase64
|
||||||
|
|
||||||
# =========================
|
|
||||||
# MQTT 配置(EMQX 接入)
|
|
||||||
# =========================
|
|
||||||
mqtt:
|
|
||||||
# 是否启用 MQTT 功能
|
|
||||||
# true:系统启动时自动连接 EMQX 并订阅 Topic
|
|
||||||
# false:不初始化 MQTT 客户端
|
|
||||||
enabled: true
|
|
||||||
|
|
||||||
# MQTT Broker 地址
|
|
||||||
# tcp://IP:1883 —— MQTT TCP
|
|
||||||
# ws://IP:8083 —— MQTT WebSocket
|
|
||||||
# ssl://IP:8883 —— MQTT SSL
|
|
||||||
broker: tcp://192.168.1.29:1883
|
|
||||||
|
|
||||||
# MQTT 客户端 ID(在 EMQX 中唯一)
|
|
||||||
# 建议:系统名 + 模块名,避免重复
|
|
||||||
clientId: zg-wms-backend
|
|
||||||
|
|
||||||
# MQTT 账号(EMQX Dashboard 中配置)
|
|
||||||
username: demo02
|
|
||||||
|
|
||||||
# MQTT 密码
|
|
||||||
password: admin123
|
|
||||||
|
|
||||||
# 是否清除会话
|
|
||||||
# true :断开后清除订阅和未接收消息(推荐后端使用)
|
|
||||||
# false :保留会话(适合设备端)
|
|
||||||
cleanSession: true
|
|
||||||
|
|
||||||
# 心跳时间(秒)
|
|
||||||
# 客户端与 Broker 保持连接的心跳间隔
|
|
||||||
keepAlive: 30
|
|
||||||
|
|
||||||
# 连接超时时间(秒)
|
|
||||||
timeout: 10
|
|
||||||
|
|
||||||
# 默认消息 QoS
|
|
||||||
# 0:最多一次(不保证到达,性能最好)
|
|
||||||
# 1:至少一次(推荐,业务数据常用)
|
|
||||||
# 2:仅一次(最严格,性能最差)
|
|
||||||
qos: 1
|
|
||||||
|
|
||||||
# 订阅的 Topic 列表(支持通配符)
|
|
||||||
# 建议先使用测试 Topic,确认链路正常后再接入真实业务 Topic
|
|
||||||
topics:
|
|
||||||
- zg/wms/test/#
|
|
||||||
@@ -37,6 +37,22 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
where id = #{id}
|
where id = #{id}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByTeamCode" resultMap="ConstructionTeamResult">
|
||||||
|
SELECT *
|
||||||
|
FROM construction_team
|
||||||
|
WHERE team_code = #{teamCode}
|
||||||
|
AND is_delete = '0'
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<select id="selectByTeamName" resultMap="ConstructionTeamResult">
|
||||||
|
SELECT *
|
||||||
|
FROM construction_team
|
||||||
|
WHERE team_name = #{teamName}
|
||||||
|
AND is_delete = '0'
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
<insert id="insertConstructionTeam" parameterType="ConstructionTeam" useGeneratedKeys="true" keyProperty="id">
|
<insert id="insertConstructionTeam" parameterType="ConstructionTeam" useGeneratedKeys="true" keyProperty="id">
|
||||||
insert into construction_team
|
insert into construction_team
|
||||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||||
@@ -59,6 +75,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</trim>
|
</trim>
|
||||||
</insert>
|
</insert>
|
||||||
|
|
||||||
|
<select id="selectMaxTeamCode" resultType="java.lang.String">
|
||||||
|
SELECT MAX(team_code)
|
||||||
|
FROM construction_team
|
||||||
|
WHERE team_code LIKE 'CT%'
|
||||||
|
</select>
|
||||||
|
|
||||||
<update id="updateConstructionTeam" parameterType="ConstructionTeam">
|
<update id="updateConstructionTeam" parameterType="ConstructionTeam">
|
||||||
update construction_team
|
update construction_team
|
||||||
<trim prefix="SET" suffixOverrides=",">
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
|||||||
@@ -182,6 +182,15 @@
|
|||||||
LIMIT 1
|
LIMIT 1
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectEncodedIdByPcodeAndWarehouse" resultType="java.lang.String">
|
||||||
|
SELECT encoded_id
|
||||||
|
FROM pcde_detail
|
||||||
|
WHERE pcode = #{pcode}
|
||||||
|
AND warehouse_code = #{warehouseCode}
|
||||||
|
AND is_delete = '0'
|
||||||
|
LIMIT 1
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- 单条插入 -->
|
<!-- 单条插入 -->
|
||||||
<insert id="insertPcdeDetail"
|
<insert id="insertPcdeDetail"
|
||||||
parameterType="PcdeDetail"
|
parameterType="PcdeDetail"
|
||||||
|
|||||||
@@ -59,11 +59,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<if test="status != null and status != ''">
|
<if test="status != null and status != ''">
|
||||||
and status = #{status}
|
and status = #{status}
|
||||||
</if>
|
</if>
|
||||||
and (status is null or trim(status) != '1')
|
<!-- and (status is null or trim(status) != '1') -->
|
||||||
|
|
||||||
<if test="isDelete != null and isDelete != ''">
|
<if test="isDelete != null and isDelete != ''">
|
||||||
and is_delete = #{isDelete}
|
and is_delete = #{isDelete}
|
||||||
</if>
|
</if>
|
||||||
|
<!-- 按创建时间筛选:create_time 在 [beginTime, endTime] -->
|
||||||
|
<if test="beginTime != null">
|
||||||
|
and create_time <![CDATA[>=]]> #{beginTime}
|
||||||
|
</if>
|
||||||
|
<if test="endTime != null">
|
||||||
|
and create_time <![CDATA[<]]> #{endTime}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
@@ -75,7 +81,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
<select id="getBySapNo" parameterType="java.lang.String" resultMap="GysJhResult">
|
<select id="getBySapNo" parameterType="java.lang.String" resultMap="GysJhResult">
|
||||||
<include refid="selectGysJhVo"/>
|
<include refid="selectGysJhVo"/>
|
||||||
WHERE sap_no = #{sapNo}
|
WHERE sap_no = #{sapNo}
|
||||||
AND status != '1'
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<!-- 【已注释】唯一性校验查询:基于SAP订单号、项目号、物料号判断是否已存在 -->
|
<!-- 【已注释】唯一性校验查询:基于SAP订单号、项目号、物料号判断是否已存在 -->
|
||||||
@@ -234,5 +239,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
|||||||
</foreach>
|
</foreach>
|
||||||
</delete>
|
</delete>
|
||||||
|
|
||||||
|
<select id="selectByWlNo" resultMap="GysJhResult">
|
||||||
|
SELECT *
|
||||||
|
FROM gys_jh
|
||||||
|
WHERE wl_no = #{wlNo}
|
||||||
|
AND is_delete = '0'
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<update id="updateDwById">
|
||||||
|
UPDATE gys_jh
|
||||||
|
SET dw = #{dw}
|
||||||
|
WHERE id = #{id}
|
||||||
|
</update>
|
||||||
</mapper>
|
</mapper>
|
||||||
|
|
||||||
|
|||||||
@@ -67,6 +67,10 @@
|
|||||||
<result property="fycde1" column="fycde_1"/>
|
<result property="fycde1" column="fycde_1"/>
|
||||||
<result property="fycde2" column="fycde_2"/>
|
<result property="fycde2" column="fycde_2"/>
|
||||||
<result property="isDelivery" column="is_delivery"/>
|
<result property="isDelivery" column="is_delivery"/>
|
||||||
|
<!-- ✅ 库龄(天) -->
|
||||||
|
<result property="stockAge" column="stock_age"/>
|
||||||
|
<!-- 总金额 -->
|
||||||
|
<result property="totalAmount" column="total_amount"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
|
|
||||||
<!-- 明细查询SQL(包含多表JOIN,用于普通明细分页等) -->
|
<!-- 明细查询SQL(包含多表JOIN,用于普通明细分页等) -->
|
||||||
@@ -81,26 +85,73 @@
|
|||||||
ri.cangku,
|
ri.cangku,
|
||||||
wh.warehouse_name AS cangku_name,
|
wh.warehouse_name AS cangku_name,
|
||||||
|
|
||||||
-- 新增:大仓/小仓编码和名称
|
|
||||||
wh.parent_warehouse_code AS parent_warehouse_code,
|
wh.parent_warehouse_code AS parent_warehouse_code,
|
||||||
wh.parent_warehouse_name AS parent_warehouse_name,
|
wh.parent_warehouse_name AS parent_warehouse_name,
|
||||||
wh.warehouse_code AS warehouse_code,
|
wh.warehouse_code AS warehouse_code,
|
||||||
wh.warehouse_name AS warehouse_name,
|
wh.warehouse_name AS warehouse_name,
|
||||||
|
|
||||||
ri.rk_time, ri.lihuo_y, ri.is_chuku, ri.is_borrowed, ri.is_delivery,ri.remark,
|
ri.rk_time,
|
||||||
ri.ck_lihuo_y, ri.ck_type, sot.type_name AS ck_type_name,
|
ri.lihuo_y,
|
||||||
ri.team_code, ct.team_name,
|
ri.is_chuku,
|
||||||
|
ri.is_borrowed,
|
||||||
|
ri.is_delivery,
|
||||||
|
ri.remark,
|
||||||
|
|
||||||
|
ri.ck_lihuo_y,
|
||||||
|
ri.ck_type,
|
||||||
|
sot.type_name AS ck_type_name,
|
||||||
|
|
||||||
|
ri.team_code,
|
||||||
|
ct.team_name,
|
||||||
|
|
||||||
ri.ck_remark,
|
ri.ck_remark,
|
||||||
ri.ly_time,
|
ri.ly_time,
|
||||||
ri.fycde_1, ri.fycde_2,
|
ri.borrow_time,
|
||||||
ri.borrow_time, ri.return_time,
|
ri.return_time,
|
||||||
ri.xj, ri.xm_no, ri.xm_ms, ri.wl_no, ri.wl_ms, ri.xm_no_ck, ri.xm_ms_ck,
|
|
||||||
ri.gys_no, ri.gys_mc, ri.jh_amt, ri.ht_dj, ri.sap_no, ri.xh, ri.gys_jh_id,
|
ri.xj,
|
||||||
ri.jh_qty, ri.ht_qty, ri.dw, ri.real_qty,
|
ri.xm_no,
|
||||||
ri.pcode, ri.pcode_id, ri.tray_code, ri.entity_id,
|
ri.xm_ms,
|
||||||
ri.status, ri.has_moved,
|
ri.xm_no_ck,
|
||||||
ri.create_by, ri.create_time, ri.update_by, ri.update_time, ri.is_delete,
|
ri.xm_ms_ck,
|
||||||
u.user_name AS lihuo_y_name
|
|
||||||
|
ri.wl_no,
|
||||||
|
ri.wl_ms,
|
||||||
|
ri.gys_no,
|
||||||
|
ri.gys_mc,
|
||||||
|
|
||||||
|
ri.jh_amt,
|
||||||
|
ri.ht_dj,
|
||||||
|
ri.sap_no,
|
||||||
|
ri.xh,
|
||||||
|
ri.gys_jh_id,
|
||||||
|
|
||||||
|
ri.jh_qty,
|
||||||
|
ri.ht_qty,
|
||||||
|
ri.dw,
|
||||||
|
ri.real_qty,
|
||||||
|
|
||||||
|
ri.pcode,
|
||||||
|
ri.pcode_id,
|
||||||
|
ri.tray_code,
|
||||||
|
ri.entity_id,
|
||||||
|
|
||||||
|
ri.status,
|
||||||
|
ri.has_moved,
|
||||||
|
|
||||||
|
ri.create_by,
|
||||||
|
ri.create_time,
|
||||||
|
ri.update_by,
|
||||||
|
ri.update_time,
|
||||||
|
ri.is_delete,
|
||||||
|
|
||||||
|
u.user_name AS lihuo_y_name,
|
||||||
|
|
||||||
|
-- ✅ 库龄(天)
|
||||||
|
DATEDIFF(CURDATE(), ri.rk_time) AS stock_age,
|
||||||
|
|
||||||
|
-- 总金额 = 单价 × 实际数量
|
||||||
|
COALESCE(ri.ht_dj, 0) * COALESCE(ri.real_qty, 0) AS total_amount
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
LEFT JOIN stock_in_type st ON ri.rk_type = st.type_code
|
LEFT JOIN stock_in_type st ON ri.rk_type = st.type_code
|
||||||
LEFT JOIN material_type mt ON ri.wl_type = mt.type_code
|
LEFT JOIN material_type mt ON ri.wl_type = mt.type_code
|
||||||
@@ -110,6 +161,7 @@
|
|||||||
LEFT JOIN sys_user u ON ri.lihuo_y = u.user_id
|
LEFT JOIN sys_user u ON ri.lihuo_y = u.user_id
|
||||||
</sql>
|
</sql>
|
||||||
|
|
||||||
|
|
||||||
<!-- 轻量分组专用SQL:仅rk_info字段,不做JOIN(供按单据分组内层使用) -->
|
<!-- 轻量分组专用SQL:仅rk_info字段,不做JOIN(供按单据分组内层使用) -->
|
||||||
<sql id="selectRkInfoForGroup">
|
<sql id="selectRkInfoForGroup">
|
||||||
SELECT
|
SELECT
|
||||||
@@ -181,8 +233,9 @@
|
|||||||
sap_no, xh, jh_qty, ht_qty, dw, real_qty,
|
sap_no, xh, jh_qty, ht_qty, dw, real_qty,
|
||||||
pcode, tray_code, entity_id,
|
pcode, tray_code, entity_id,
|
||||||
ck_lihuo_y, ck_type, team_code, ck_remark,
|
ck_lihuo_y, ck_type, team_code, ck_remark,
|
||||||
ly_time, bill_no_ck, has_moved,
|
ly_time, bill_no_ck, has_moved, borrow_time,
|
||||||
gys_jh_id,
|
gys_jh_id,
|
||||||
|
status,
|
||||||
create_by, create_time, update_by, update_time, is_delete
|
create_by, create_time, update_by, update_time, is_delete
|
||||||
) VALUES (
|
) VALUES (
|
||||||
#{rkType}, #{wlType}, #{cangku}, #{rkTime}, #{lihuoY},
|
#{rkType}, #{wlType}, #{cangku}, #{rkTime}, #{lihuoY},
|
||||||
@@ -191,8 +244,9 @@
|
|||||||
#{sapNo}, #{xh}, #{jhQty}, #{htQty}, #{dw}, #{realQty},
|
#{sapNo}, #{xh}, #{jhQty}, #{htQty}, #{dw}, #{realQty},
|
||||||
#{pcode}, #{trayCode}, #{entityId},
|
#{pcode}, #{trayCode}, #{entityId},
|
||||||
#{ckLihuoY}, #{ckType}, #{teamCode}, #{ckRemark},
|
#{ckLihuoY}, #{ckType}, #{teamCode}, #{ckRemark},
|
||||||
#{lyTime}, #{billNoCk}, #{hasMoved},
|
#{lyTime}, #{billNoCk}, #{hasMoved}, #{borrowTime},
|
||||||
#{gysJhId},
|
#{gysJhId},
|
||||||
|
#{status},
|
||||||
#{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{isDelete}
|
#{createBy}, #{createTime}, #{updateBy}, #{updateTime}, #{isDelete}
|
||||||
)
|
)
|
||||||
</insert>
|
</insert>
|
||||||
@@ -252,6 +306,9 @@
|
|||||||
)
|
)
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<if test="remark != null and remark != ''">
|
||||||
|
AND ri.remark LIKE concat('%', #{remark}, '%')
|
||||||
|
</if>
|
||||||
<if test="rkType != null and rkType != ''">
|
<if test="rkType != null and rkType != ''">
|
||||||
AND ri.rk_type LIKE concat('%', #{rkType}, '%')
|
AND ri.rk_type LIKE concat('%', #{rkType}, '%')
|
||||||
</if>
|
</if>
|
||||||
@@ -300,10 +357,10 @@
|
|||||||
AND ri.xj LIKE concat('%', #{xj}, '%')
|
AND ri.xj LIKE concat('%', #{xj}, '%')
|
||||||
</if>
|
</if>
|
||||||
<if test="billNo != null and billNo != ''">
|
<if test="billNo != null and billNo != ''">
|
||||||
AND ri.bill_no LIKE concat('%', #{billNo}, '%')
|
AND ri.bill_no = #{billNo}
|
||||||
</if>
|
</if>
|
||||||
<if test="billNoCk != null and billNoCk != ''">
|
<if test="billNoCk != null and billNoCk != ''">
|
||||||
AND ri.bill_no_ck LIKE concat('%', #{billNoCk}, '%')
|
AND ri.bill_no_ck = #{billNoCk}
|
||||||
</if>
|
</if>
|
||||||
<if test="xmNo != null and xmNo != ''">
|
<if test="xmNo != null and xmNo != ''">
|
||||||
AND ri.xm_no LIKE concat('%', #{xmNo}, '%')
|
AND ri.xm_no LIKE concat('%', #{xmNo}, '%')
|
||||||
@@ -393,8 +450,9 @@
|
|||||||
AND ri.is_delete = 0
|
AND ri.is_delete = 0
|
||||||
|
|
||||||
<!-- ✅ 关键:只允许未出库的数据 -->
|
<!-- ✅ 关键:只允许未出库的数据 -->
|
||||||
AND ri.is_chuku = '0'
|
<if test="isChuku != null and isChuku != ''">
|
||||||
|
AND ri.is_chuku = #{isChuku}
|
||||||
|
</if>
|
||||||
<!-- 借料状态 -->
|
<!-- 借料状态 -->
|
||||||
<choose>
|
<choose>
|
||||||
<when test="isBorrowed != null and isBorrowed != ''">
|
<when test="isBorrowed != null and isBorrowed != ''">
|
||||||
@@ -453,27 +511,20 @@
|
|||||||
a.ck_lihuo_y,
|
a.ck_lihuo_y,
|
||||||
u.user_name AS ck_lihuo_y_name,
|
u.user_name AS ck_lihuo_y_name,
|
||||||
ru.user_name AS lihuo_y_name,
|
ru.user_name AS lihuo_y_name,
|
||||||
a.is_delivery AS is_delivery
|
a.is_delivery AS is_delivery,
|
||||||
|
a.team_code,
|
||||||
|
ct.team_name AS team_name
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
MIN(t.id) AS id,
|
MIN(t.id) AS id,
|
||||||
|
|
||||||
/* ✅ 单据号:出库/借料出库 -> CK;其它 -> RK(用于页面展示) */
|
|
||||||
t.show_bill_no AS bill_no,
|
t.show_bill_no AS bill_no,
|
||||||
|
|
||||||
/* 保留 bill_no_ck 字段(出库态有值) */
|
|
||||||
MIN(t.bill_no_ck) AS bill_no_ck,
|
MIN(t.bill_no_ck) AS bill_no_ck,
|
||||||
|
|
||||||
MIN(t.rk_type) AS rk_type,
|
MIN(t.rk_type) AS rk_type,
|
||||||
MIN(t.wl_type) AS wl_type,
|
MIN(t.wl_type) AS wl_type,
|
||||||
MIN(t.cangku) AS cangku,
|
MIN(t.cangku) AS cangku,
|
||||||
|
|
||||||
/* 时间:你要更合理也可以改成 MAX(COALESCE(ly_time,rk_time)) */
|
|
||||||
MIN(t.rk_time) AS rk_time,
|
MIN(t.rk_time) AS rk_time,
|
||||||
|
|
||||||
MIN(t.lihuo_y) AS lihuo_y,
|
MIN(t.lihuo_y) AS lihuo_y,
|
||||||
MAX(t.is_chuku) AS is_chuku,
|
MAX(t.is_chuku) AS is_chuku,
|
||||||
|
|
||||||
MIN(t.xj) AS xj,
|
MIN(t.xj) AS xj,
|
||||||
MIN(t.xm_no) AS xm_no,
|
MIN(t.xm_no) AS xm_no,
|
||||||
MIN(t.xm_ms) AS xm_ms,
|
MIN(t.xm_ms) AS xm_ms,
|
||||||
@@ -484,14 +535,13 @@
|
|||||||
MIN(t.wl_ms) AS wl_ms,
|
MIN(t.wl_ms) AS wl_ms,
|
||||||
MIN(t.gys_no) AS gys_no,
|
MIN(t.gys_no) AS gys_no,
|
||||||
MIN(t.sap_no) AS sap_no,
|
MIN(t.sap_no) AS sap_no,
|
||||||
|
|
||||||
MIN(t.ck_type) AS ck_type,
|
MIN(t.ck_type) AS ck_type,
|
||||||
MAX(t.ly_time) AS ly_time,
|
MAX(t.ly_time) AS ly_time,
|
||||||
MIN(t.ck_lihuo_y) AS ck_lihuo_y,
|
MIN(t.ck_lihuo_y) AS ck_lihuo_y,
|
||||||
MIN(t.is_delivery) AS is_delivery,
|
MIN(t.is_delivery) AS is_delivery,
|
||||||
|
MIN(t.team_code) AS team_code,
|
||||||
/* ✅ 用于 needAudit 子查询判断:本组是 RK 组还是 CK 组 */
|
MIN(t.show_bill_type) AS show_bill_type,
|
||||||
MIN(t.show_bill_type) AS show_bill_type
|
MAX(t.create_time) AS create_time
|
||||||
|
|
||||||
FROM (
|
FROM (
|
||||||
SELECT
|
SELECT
|
||||||
@@ -520,6 +570,8 @@
|
|||||||
ri.pcode,
|
ri.pcode,
|
||||||
ri.is_delete,
|
ri.is_delete,
|
||||||
ri.is_delivery,
|
ri.is_delivery,
|
||||||
|
ri.team_code,
|
||||||
|
ri.create_time,
|
||||||
|
|
||||||
CASE
|
CASE
|
||||||
WHEN ri.is_chuku IN ('1','3')
|
WHEN ri.is_chuku IN ('1','3')
|
||||||
@@ -528,7 +580,6 @@
|
|||||||
THEN ri.bill_no_ck
|
THEN ri.bill_no_ck
|
||||||
ELSE ri.bill_no
|
ELSE ri.bill_no
|
||||||
END AS show_bill_no,
|
END AS show_bill_no,
|
||||||
|
|
||||||
CASE
|
CASE
|
||||||
WHEN ri.is_chuku IN ('1','3')
|
WHEN ri.is_chuku IN ('1','3')
|
||||||
AND ri.bill_no_ck IS NOT NULL
|
AND ri.bill_no_ck IS NOT NULL
|
||||||
@@ -536,161 +587,214 @@
|
|||||||
THEN 'CK'
|
THEN 'CK'
|
||||||
ELSE 'RK'
|
ELSE 'RK'
|
||||||
END AS show_bill_type
|
END AS show_bill_type
|
||||||
|
|
||||||
FROM rk_info ri
|
FROM rk_info ri
|
||||||
) t
|
|
||||||
|
|
||||||
<where>
|
<where>
|
||||||
<!-- 只查未删除 -->
|
AND ri.is_delete = 0
|
||||||
<choose>
|
|
||||||
<when test="q.isDelete != null and q.isDelete != ''">
|
|
||||||
AND t.is_delete = #{q.isDelete}
|
|
||||||
</when>
|
|
||||||
<otherwise>
|
|
||||||
AND t.is_delete = 0
|
|
||||||
</otherwise>
|
|
||||||
</choose>
|
|
||||||
|
|
||||||
<!-- is_chuku / isChukuList -->
|
<!-- isChukuList 优先生效 -->
|
||||||
<choose>
|
<if test="q.isChukuList != null and q.isChukuList.size() > 0">
|
||||||
<when test="q.isChukuList != null and q.isChukuList.size > 0">
|
AND ri.is_chuku IN
|
||||||
AND t.is_chuku IN
|
<foreach collection="q.isChukuList" item="s" open="(" separator="," close=")">
|
||||||
<foreach collection="q.isChukuList" item="val" open="(" separator="," close=")">
|
#{s}
|
||||||
#{val}
|
|
||||||
</foreach>
|
</foreach>
|
||||||
</when>
|
|
||||||
<when test="q.isChuku != null and q.isChuku != ''">
|
|
||||||
AND t.is_chuku = #{q.isChuku}
|
|
||||||
</when>
|
|
||||||
</choose>
|
|
||||||
|
|
||||||
<!-- 时间过滤:rk_time -->
|
|
||||||
<if test="q.startTime != null and q.startTime != ''">
|
|
||||||
<![CDATA[ AND t.rk_time >= #{q.startTime} ]]>
|
|
||||||
</if>
|
|
||||||
<if test="q.endTime != null and q.endTime != ''">
|
|
||||||
<![CDATA[ AND t.rk_time <= #{q.endTime} ]]>
|
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- 时间过滤:ly_time -->
|
<!-- isChukuList 为空时才用 isChuku 单值 -->
|
||||||
<if test="q.lyStartTime != null and q.lyStartTime != ''">
|
<if test="(q.isChukuList == null or q.isChukuList.size() == 0) and q.isChuku != null and q.isChuku != ''">
|
||||||
<![CDATA[ AND t.ly_time >= #{q.lyStartTime} ]]>
|
AND ri.is_chuku = #{q.isChuku}
|
||||||
</if>
|
|
||||||
<if test="q.lyEndTime != null and q.lyEndTime != ''">
|
|
||||||
<![CDATA[ AND t.ly_time <= #{q.lyEndTime} ]]>
|
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- 维度条件 -->
|
|
||||||
<if test="q.rkType != null and q.rkType != ''">
|
|
||||||
AND t.rk_type LIKE concat('%', #{q.rkType}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.wlType != null and q.wlType != ''">
|
|
||||||
AND t.wl_type LIKE concat('%', #{q.wlType}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.cangku != null and q.cangku != ''">
|
|
||||||
AND t.cangku LIKE concat('%', #{q.cangku}, '%')
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="q.lihuoY != null and q.lihuoY != ''">
|
|
||||||
AND t.lihuo_y LIKE concat('%', #{q.lihuoY}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.xj != null and q.xj != ''">
|
|
||||||
AND t.xj LIKE concat('%', #{q.xj}, '%')
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<!-- 单据号(如果你页面输入框叫 billNo,就建议这里也去匹配 show_bill_no) -->
|
|
||||||
<if test="q.billNo != null and q.billNo != ''">
|
|
||||||
AND t.show_bill_no LIKE concat('%', #{q.billNo}, '%')
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<!-- 如果你还保留 billNoCk 入参,也允许精确筛 CK -->
|
|
||||||
<if test="q.billNoCk != null and q.billNoCk != ''">
|
|
||||||
AND t.bill_no_ck LIKE concat('%', #{q.billNoCk}, '%')
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<!-- 其它模糊 -->
|
|
||||||
<if test="q.xmNo != null and q.xmNo != ''">
|
|
||||||
AND t.xm_no LIKE concat('%', #{q.xmNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.xmMs != null and q.xmMs != ''">
|
|
||||||
AND t.xm_ms LIKE concat('%', #{q.xmMs}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.wlNo != null and q.wlNo != ''">
|
|
||||||
AND t.wl_no LIKE concat('%', #{q.wlNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.wlMs != null and q.wlMs != ''">
|
|
||||||
AND t.wl_ms LIKE concat('%', #{q.wlMs}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.gysNo != null and q.gysNo != ''">
|
|
||||||
AND t.gys_no LIKE concat('%', #{q.gysNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.gysMc != null and q.gysMc != ''">
|
|
||||||
AND t.gys_mc LIKE concat('%', #{q.gysMc}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.sapNo != null and q.sapNo != ''">
|
|
||||||
AND t.sap_no LIKE concat('%', #{q.sapNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.pcode != null and q.pcode != ''">
|
|
||||||
AND t.pcode LIKE concat('%', #{q.pcode}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="q.ckType != null and q.ckType != ''">
|
|
||||||
AND t.ck_type LIKE concat('%', #{q.ckType}, '%')
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="q.isDelivery != null and q.isDelivery != ''">
|
|
||||||
AND t.is_delivery = #{q.isDelivery}
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<!-- keyword:建议也命中 show_bill_no(解决用户输入 CK/RK 都能搜到) -->
|
|
||||||
<if test="q.keyword != null and q.keyword != ''">
|
<if test="q.keyword != null and q.keyword != ''">
|
||||||
AND (
|
AND (
|
||||||
t.xm_no LIKE concat('%', #{q.keyword}, '%')
|
ri.bill_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.xm_ms LIKE concat('%', #{q.keyword}, '%')
|
OR ri.bill_no_ck LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.wl_no LIKE concat('%', #{q.keyword}, '%')
|
OR ri.xm_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.wl_ms LIKE concat('%', #{q.keyword}, '%')
|
OR ri.xm_ms LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.gys_no LIKE concat('%', #{q.keyword}, '%')
|
OR ri.wl_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.gys_mc LIKE concat('%', #{q.keyword}, '%')
|
OR ri.wl_ms LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.sap_no LIKE concat('%', #{q.keyword}, '%')
|
OR ri.sap_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.bill_no LIKE concat('%', #{q.keyword}, '%')
|
OR ri.gys_mc LIKE concat('%', #{q.keyword}, '%')
|
||||||
OR t.bill_no_ck LIKE concat('%', #{q.keyword}, '%')
|
|
||||||
OR t.show_bill_no LIKE concat('%', #{q.keyword}, '%')
|
|
||||||
OR t.ck_type LIKE concat('%', #{q.keyword}, '%')
|
|
||||||
OR t.pcode LIKE concat('%', #{q.keyword}, '%')
|
|
||||||
)
|
)
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- ✅ 审核过滤:按组类型匹配 RK 或 CK -->
|
<if test="q.cangku != null and q.cangku != ''">
|
||||||
<if test="needAudit != null and needAudit == 1">
|
AND ri.cangku = #{q.cangku}
|
||||||
AND NOT EXISTS (
|
</if>
|
||||||
SELECT 1
|
<if test="q.startTime != null and q.startTime != ''">
|
||||||
FROM rk_info r2
|
AND ri.rk_time >= #{q.startTime}
|
||||||
JOIN audit_signature asg
|
|
||||||
ON asg.rk_id = r2.id
|
|
||||||
AND asg.approver_id IS NOT NULL
|
|
||||||
AND (asg.audit_result IS NOT NULL AND asg.audit_result != '1')
|
|
||||||
WHERE r2.is_delete = 0
|
|
||||||
AND (
|
|
||||||
(t.show_bill_type = 'RK' AND r2.bill_no = t.show_bill_no)
|
|
||||||
OR (t.show_bill_type = 'CK' AND r2.bill_no_ck = t.show_bill_no)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<if test="q.endTime != null and q.endTime != ''">
|
||||||
|
AND ri.rk_time <= #{q.endTime}
|
||||||
|
</if>
|
||||||
</where>
|
</where>
|
||||||
|
) t
|
||||||
/* ✅ 关键:按 show_bill_no 分组(出库合并 CK,在库保留 RK) */
|
|
||||||
GROUP BY t.show_bill_no
|
GROUP BY t.show_bill_no
|
||||||
|
|
||||||
) a
|
) a
|
||||||
LEFT JOIN stock_in_type si ON a.rk_type = si.type_code
|
LEFT JOIN stock_in_type si ON a.rk_type = si.type_code
|
||||||
LEFT JOIN stock_out_type so ON a.ck_type = so.type_code
|
LEFT JOIN stock_out_type so ON a.ck_type = so.type_code
|
||||||
LEFT JOIN sys_user u ON a.ck_lihuo_y = u.user_id
|
LEFT JOIN sys_user u ON a.ck_lihuo_y = u.user_id
|
||||||
LEFT JOIN material_type mt ON a.wl_type = mt.type_code
|
LEFT JOIN material_type mt ON a.wl_type = mt.type_code
|
||||||
LEFT JOIN sys_user ru ON a.lihuo_y = ru.user_id
|
LEFT JOIN sys_user ru ON a.lihuo_y = ru.user_id
|
||||||
ORDER BY a.rk_time DESC
|
LEFT JOIN construction_team ct ON a.team_code = ct.team_code
|
||||||
|
|
||||||
|
ORDER BY a.create_time DESC
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectBillHeaderList" resultMap="RkInfoResult">
|
||||||
|
SELECT
|
||||||
|
-- 3. 外层:关联字典表获取名称
|
||||||
|
a.show_bill_no AS bill_no, -- 最终展示的单据号
|
||||||
|
a.bill_no AS bill_no, -- 原始入库单号(兼容实体)
|
||||||
|
a.bill_no_ck AS bill_no_ck, -- 原始出库单号
|
||||||
|
|
||||||
|
-- 状态与标识
|
||||||
|
a.is_chuku,
|
||||||
|
a.is_delivery,
|
||||||
|
a.id, -- 取聚合后的最小ID作为主键标识
|
||||||
|
|
||||||
|
-- 入库维度的公共字段
|
||||||
|
a.rk_type,
|
||||||
|
si.type_name AS rk_type_name,
|
||||||
|
a.wl_type,
|
||||||
|
mt.type_name AS wl_type_name,
|
||||||
|
a.rk_time,
|
||||||
|
a.lihuo_y,
|
||||||
|
ru.user_name AS lihuo_y_name,
|
||||||
|
|
||||||
|
-- 仓库信息
|
||||||
|
a.cangku,
|
||||||
|
wh.warehouse_name AS cangku_name,
|
||||||
|
wh.parent_warehouse_code AS parent_warehouse_code,
|
||||||
|
wh.parent_warehouse_name AS parent_warehouse_name,
|
||||||
|
wh.warehouse_code AS warehouse_code,
|
||||||
|
wh.warehouse_name AS warehouse_name,
|
||||||
|
|
||||||
|
-- 出库维度的公共字段
|
||||||
|
a.ck_type,
|
||||||
|
so.type_name AS ck_type_name,
|
||||||
|
a.ly_time,
|
||||||
|
a.ck_lihuo_y,
|
||||||
|
u.user_name AS ck_lihuo_y_name, -- 注意:这里对应 XML 里的 u 表别名
|
||||||
|
a.team_code,
|
||||||
|
ct.team_name AS team_name,
|
||||||
|
|
||||||
|
-- 创建时间
|
||||||
|
a.create_time
|
||||||
|
|
||||||
|
FROM (
|
||||||
|
SELECT
|
||||||
|
-- 2. 中间层:按单据号聚合
|
||||||
|
t.show_bill_no,
|
||||||
|
MIN(t.id) AS id,
|
||||||
|
-- 单据头信息聚合(取最大值或最小值均可,因为同一单据号下这些字段是一致的)
|
||||||
|
MAX(t.bill_no) AS bill_no,
|
||||||
|
MAX(t.bill_no_ck) AS bill_no_ck,
|
||||||
|
|
||||||
|
MAX(t.is_chuku) AS is_chuku,
|
||||||
|
MAX(t.is_delivery) AS is_delivery,
|
||||||
|
|
||||||
|
MIN(t.rk_type) AS rk_type,
|
||||||
|
MIN(t.wl_type) AS wl_type,
|
||||||
|
MIN(t.rk_time) AS rk_time,
|
||||||
|
MIN(t.lihuo_y) AS lihuo_y,
|
||||||
|
MIN(t.cangku) AS cangku,
|
||||||
|
|
||||||
|
MIN(t.ck_type) AS ck_type,
|
||||||
|
MIN(t.ly_time) AS ly_time,
|
||||||
|
MIN(t.ck_lihuo_y) AS ck_lihuo_y,
|
||||||
|
MIN(t.team_code) AS team_code,
|
||||||
|
|
||||||
|
MAX(t.create_time) AS create_time
|
||||||
|
FROM (
|
||||||
|
-- 1. 内层:过滤并计算 show_bill_no
|
||||||
|
SELECT
|
||||||
|
ri.id,
|
||||||
|
ri.bill_no,
|
||||||
|
ri.bill_no_ck,
|
||||||
|
ri.rk_type,
|
||||||
|
ri.wl_type,
|
||||||
|
ri.cangku,
|
||||||
|
ri.rk_time,
|
||||||
|
ri.lihuo_y,
|
||||||
|
ri.is_chuku,
|
||||||
|
ri.is_delivery,
|
||||||
|
ri.ck_type,
|
||||||
|
ri.ly_time,
|
||||||
|
ri.ck_lihuo_y,
|
||||||
|
ri.team_code,
|
||||||
|
ri.create_time,
|
||||||
|
-- 计算逻辑:如果是出库状态且有出库单号,则以出库单号为主
|
||||||
|
CASE
|
||||||
|
WHEN ri.is_chuku IN ('1','3') AND ri.bill_no_ck IS NOT NULL AND ri.bill_no_ck != ''
|
||||||
|
THEN ri.bill_no_ck
|
||||||
|
ELSE ri.bill_no
|
||||||
|
END AS show_bill_no
|
||||||
|
FROM rk_info ri
|
||||||
|
<where>
|
||||||
|
AND ri.is_delete = 0
|
||||||
|
|
||||||
|
<!-- 关键字搜索:依然保留对项目号、物料号等的支持,方便用户查找 -->
|
||||||
|
<if test="q.keyword != null and q.keyword != ''">
|
||||||
|
AND (
|
||||||
|
ri.xm_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
|
OR ri.wl_no LIKE concat('%', #{q.keyword}, '%')
|
||||||
|
OR ri.gys_mc LIKE concat('%', #{q.keyword}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<if test="q.isChukuList != null and q.isChukuList.size() > 0">
|
||||||
|
AND ri.is_chuku IN
|
||||||
|
<foreach collection="q.isChukuList" item="s" open="(" separator="," close=")">
|
||||||
|
#{s}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
<if test="(q.isChukuList == null or q.isChukuList.size() == 0) and q.isChuku != null and q.isChuku != ''">
|
||||||
|
AND ri.is_chuku = #{q.isChuku}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<if test="q.ckType != null and q.ckType != ''">
|
||||||
|
AND ri.ck_type = #{q.ckType}
|
||||||
|
</if>
|
||||||
|
<if test="q.cangku != null and q.cangku != ''">
|
||||||
|
AND ri.cangku = #{q.cangku}
|
||||||
|
</if>
|
||||||
|
<if test="q.billNoCk != null and q.billNoCk != ''">
|
||||||
|
AND ri.bill_no_ck = #{q.billNoCk}
|
||||||
|
</if>
|
||||||
|
<if test="q.billNo != null and q.billNo != ''">
|
||||||
|
AND ri.bill_no = #{q.billNo}
|
||||||
|
</if>
|
||||||
|
<if test="q.startTime != null">
|
||||||
|
AND ri.rk_time >= #{q.startTime}
|
||||||
|
</if>
|
||||||
|
<if test="q.endTime != null">
|
||||||
|
AND ri.rk_time <= #{q.endTime}
|
||||||
|
</if>
|
||||||
|
<if test="q.statDate != null">
|
||||||
|
AND ri.ly_time >= #{q.statDate}
|
||||||
|
</if>
|
||||||
|
<if test="q.endDate != null">
|
||||||
|
AND ri.ly_time <= #{q.endDate}
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
) t
|
||||||
|
GROUP BY t.show_bill_no
|
||||||
|
) a
|
||||||
|
|
||||||
|
-- 字典关联
|
||||||
|
LEFT JOIN stock_in_type si ON a.rk_type = si.type_code
|
||||||
|
LEFT JOIN stock_out_type so ON a.ck_type = so.type_code
|
||||||
|
LEFT JOIN warehouse_info wh ON a.cangku = wh.warehouse_code
|
||||||
|
LEFT JOIN sys_user u ON a.ck_lihuo_y = u.user_id -- 出库理货员
|
||||||
|
LEFT JOIN sys_user ru ON a.lihuo_y = ru.user_id -- 入库理货员
|
||||||
|
LEFT JOIN construction_team ct ON a.team_code = ct.team_code
|
||||||
|
LEFT JOIN material_type mt ON a.wl_type = mt.type_code
|
||||||
|
|
||||||
|
-- 排序优化:优先按出库时间排序;若无出库时间(入库单),则按入库时间排序
|
||||||
|
ORDER BY COALESCE(a.ly_time, a.rk_time) DESC, a.id DESC
|
||||||
|
</select>
|
||||||
|
|
||||||
<!-- ================== /按单据分组查询 ================== -->
|
<!-- ================== /按单据分组查询 ================== -->
|
||||||
|
|
||||||
@@ -975,6 +1079,42 @@
|
|||||||
WHERE id = #{id}
|
WHERE id = #{id}
|
||||||
</update>
|
</update>
|
||||||
|
|
||||||
|
<update id="updateByBillNoCk" parameterType="com.zg.project.wisdom.domain.RkInfo">
|
||||||
|
UPDATE rk_info
|
||||||
|
<trim prefix="SET" suffixOverrides=",">
|
||||||
|
<if test="rkType != null">rk_type = #{rkType},</if>
|
||||||
|
<if test="wlType != null">wl_type = #{wlType},</if>
|
||||||
|
<if test="cangku != null and cangku != ''">
|
||||||
|
cangku = #{cangku},
|
||||||
|
</if>
|
||||||
|
<if test="rkTime != null">rk_time = #{rkTime},</if>
|
||||||
|
<if test="lihuoY != null">lihuo_y = #{lihuoY},</if>
|
||||||
|
<if test="isChuku != null">is_chuku = #{isChuku},</if>
|
||||||
|
<if test="isBorrowed != null">is_borrowed = #{isBorrowed},</if>
|
||||||
|
|
||||||
|
<if test="remark != null">remark = #{remark},</if>
|
||||||
|
<if test="xmNoCk != null">xm_no_ck = #{xmNoCk},</if>
|
||||||
|
<if test="xmMsCk != null">xm_ms_ck = #{xmMsCk},</if>
|
||||||
|
|
||||||
|
<if test="ckLihuoY != null">ck_lihuo_y = #{ckLihuoY},</if>
|
||||||
|
<if test="ckType != null">ck_type = #{ckType},</if>
|
||||||
|
<if test="teamCode != null">team_code = #{teamCode},</if>
|
||||||
|
<if test="ckRemark != null">ck_remark = #{ckRemark},</if>
|
||||||
|
|
||||||
|
<if test="lyTime != null">ly_time = #{lyTime},</if>
|
||||||
|
<if test="borrowTime != null">borrow_time = #{borrowTime},</if>
|
||||||
|
<if test="returnTime != null">return_time = #{returnTime},</if>
|
||||||
|
|
||||||
|
<if test="isDelivery != null">is_delivery = #{isDelivery},</if>
|
||||||
|
<if test="hasMoved != null">has_moved = #{hasMoved},</if>
|
||||||
|
|
||||||
|
<if test="updateBy != null">update_by = #{updateBy},</if>
|
||||||
|
<if test="updateTime != null">update_time = #{updateTime},</if>
|
||||||
|
</trim>
|
||||||
|
WHERE bill_no_ck = #{billNoCk}
|
||||||
|
AND is_delete = '0'
|
||||||
|
</update>
|
||||||
|
|
||||||
<update id="deleteRkInfoById" parameterType="Long">
|
<update id="deleteRkInfoById" parameterType="Long">
|
||||||
update rk_info
|
update rk_info
|
||||||
<set>
|
<set>
|
||||||
@@ -1010,7 +1150,10 @@
|
|||||||
<if test="lyTime != null">ly_time = #{lyTime},</if>
|
<if test="lyTime != null">ly_time = #{lyTime},</if>
|
||||||
<if test="borrowTime != null">borrow_time = #{borrowTime},</if>
|
<if test="borrowTime != null">borrow_time = #{borrowTime},</if>
|
||||||
<if test="returnTime != null">return_time = #{returnTime},</if>
|
<if test="returnTime != null">return_time = #{returnTime},</if>
|
||||||
|
<if test="pcode != null and pcode != ''">pcode = #{pcode},</if>
|
||||||
|
<if test="cangku != null and cangku != ''">cangku = #{cangku},</if>
|
||||||
<if test="status != null">status = #{status},</if>
|
<if test="status != null">status = #{status},</if>
|
||||||
|
<if test="realQty != null">real_qty = #{realQty},</if>
|
||||||
</set>
|
</set>
|
||||||
WHERE id = #{id}
|
WHERE id = #{id}
|
||||||
</update>
|
</update>
|
||||||
@@ -1088,29 +1231,45 @@
|
|||||||
<select id="selectAllRkInfo"
|
<select id="selectAllRkInfo"
|
||||||
parameterType="com.zg.project.wisdom.domain.RkInfo"
|
parameterType="com.zg.project.wisdom.domain.RkInfo"
|
||||||
resultMap="RkInfoResult">
|
resultMap="RkInfoResult">
|
||||||
|
|
||||||
<include refid="selectRkInfoVo"/>
|
<include refid="selectRkInfoVo"/>
|
||||||
|
|
||||||
<where>
|
<where>
|
||||||
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
||||||
|
|
||||||
<if test="isChuku != null and isChuku != ''">
|
<if test="isChukuList != null and isChukuList.size() > 0">
|
||||||
|
AND ri.is_chuku IN
|
||||||
|
<foreach collection="isChukuList"
|
||||||
|
item="item"
|
||||||
|
open="("
|
||||||
|
separator=","
|
||||||
|
close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<if test="(isChukuList == null or isChukuList.size() == 0)
|
||||||
|
and isChuku != null">
|
||||||
AND ri.is_chuku = #{isChuku}
|
AND ri.is_chuku = #{isChuku}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="warehouseCode != null and warehouseCode != ''">
|
<if test="warehouseCode != null and warehouseCode != ''">
|
||||||
AND ri.cangku = #{warehouseCode}
|
AND ri.cangku = #{warehouseCode}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="parentWarehouseCode != null and parentWarehouseCode != ''">
|
<if test="parentWarehouseCode != null and parentWarehouseCode != ''">
|
||||||
AND wh.parent_warehouse_code = #{parentWarehouseCode}
|
AND wh.parent_warehouse_code = #{parentWarehouseCode}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- Date 类型:只能判 null,别再判 '' -->
|
<!-- 入库时间 -->
|
||||||
<if test="startTime != null">
|
<if test="startTime != null">
|
||||||
AND ri.rk_time <![CDATA[ >= ]]> #{startTime}
|
AND ri.rk_time <![CDATA[ >= ]]> #{startTime}
|
||||||
</if>
|
</if>
|
||||||
<if test="endTime != null">
|
<if test="endTime != null">
|
||||||
AND ri.rk_time <![CDATA[ <= ]]> #{endTime}
|
AND ri.rk_time <![CDATA[ < ]]> DATE_ADD(#{endTime}, INTERVAL 1 SECOND)
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<!-- 归还时间 -->
|
||||||
<if test="statDate != null">
|
<if test="statDate != null">
|
||||||
AND ri.return_time <![CDATA[ >= ]]> #{statDate}
|
AND ri.return_time <![CDATA[ >= ]]> #{statDate}
|
||||||
</if>
|
</if>
|
||||||
@@ -1121,16 +1280,17 @@
|
|||||||
<if test="rkType != null and rkType != ''">
|
<if test="rkType != null and rkType != ''">
|
||||||
AND ri.rk_type = #{rkType}
|
AND ri.rk_type = #{rkType}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="wlType != null and wlType != ''">
|
<if test="wlType != null and wlType != ''">
|
||||||
AND ri.wl_type = #{wlType}
|
AND ri.wl_type = #{wlType}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<!-- Date 类型:只能判 null -->
|
<!-- 出库时间 -->
|
||||||
<if test="lyStartTime != null">
|
<if test="lyStartTime != null">
|
||||||
AND ri.ly_time <![CDATA[ >= ]]> #{lyStartTime}
|
AND ri.ly_time <![CDATA[ >= ]]> #{lyStartTime}
|
||||||
</if>
|
</if>
|
||||||
<if test="lyEndTime != null">
|
<if test="lyEndTime != null">
|
||||||
AND ri.ly_time <![CDATA[ <= ]]> #{lyEndTime}
|
AND ri.ly_time <![CDATA[ < ]]> DATE_ADD(#{lyEndTime}, INTERVAL 1 SECOND)
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="xmNo != null and xmNo != ''">
|
<if test="xmNo != null and xmNo != ''">
|
||||||
@@ -1173,40 +1333,88 @@
|
|||||||
AND ri.fycde_2 LIKE CONCAT('%', #{fycde2}, '%')
|
AND ri.fycde_2 LIKE CONCAT('%', #{fycde2}, '%')
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
ORDER BY ri.create_time DESC, ri.id DESC
|
|
||||||
|
<!-- ✅ 核心排序规则 -->
|
||||||
|
ORDER BY
|
||||||
|
COALESCE(ri.ly_time, ri.rk_time) DESC,
|
||||||
|
ri.id DESC
|
||||||
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<select id="selectRkInfoPageList"
|
||||||
|
parameterType="com.zg.project.wisdom.domain.RkInfo"
|
||||||
|
resultMap="RkInfoResult">
|
||||||
|
|
||||||
|
<include refid="selectRkInfoVo"/>
|
||||||
|
|
||||||
<select id="selectStatistics" resultType="java.lang.Long" parameterType="java.lang.Object" >
|
|
||||||
SELECT sum(ri.ht_dj * ri.real_qty)
|
|
||||||
FROM rk_info ri
|
|
||||||
<where>
|
<where>
|
||||||
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
||||||
|
|
||||||
<if test="isChuku != null and isChuku != ''">
|
<if test="isChukuList != null and isChukuList.size() > 0">
|
||||||
|
AND ri.is_chuku IN
|
||||||
|
<foreach collection="isChukuList"
|
||||||
|
item="item"
|
||||||
|
open="("
|
||||||
|
separator=","
|
||||||
|
close=")">
|
||||||
|
#{item}
|
||||||
|
</foreach>
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<if test="(isChukuList == null or isChukuList.size() == 0)
|
||||||
|
and isChuku != null">
|
||||||
AND ri.is_chuku = #{isChuku}
|
AND ri.is_chuku = #{isChuku}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="cangku != null and cangku != ''">
|
<if test="warehouseCode != null and warehouseCode != ''">
|
||||||
AND ri.cangku = #{cangku}
|
AND ri.cangku = #{warehouseCode}
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<if test="parentWarehouseCode != null and parentWarehouseCode != ''">
|
||||||
|
AND wh.parent_warehouse_code = #{parentWarehouseCode}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<if test="rkType != null and rkType != ''">
|
<if test="rkType != null and rkType != ''">
|
||||||
AND ri.rk_type = #{rkType}
|
AND ri.rk_type = #{rkType}
|
||||||
</if>
|
</if>
|
||||||
<if test="startTime != null">
|
|
||||||
AND ri.rk_time <![CDATA[ >= ]]> #{startTime}
|
<if test="wlType != null and wlType != ''">
|
||||||
</if>
|
AND ri.wl_type = #{wlType}
|
||||||
<if test="endTime != null">
|
|
||||||
AND ri.rk_time <![CDATA[ <= ]]> #{endTime}
|
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
<if test="lyStartTime != null and lyStartTime != ''">
|
<!-- 时间范围查询:入库时间 OR 出库时间 -->
|
||||||
AND ri.ly_time <![CDATA[ >= ]]> #{lyStartTime}
|
<if test="statDate != null and endDate != null">
|
||||||
</if>
|
AND (
|
||||||
<if test="lyEndTime != null and lyEndTime != ''">
|
(
|
||||||
AND ri.ly_time <![CDATA[ <= ]]> #{lyEndTime}
|
ri.rk_time <![CDATA[ >= ]]> #{statDate}
|
||||||
|
AND ri.rk_time <![CDATA[ < ]]> DATE_ADD(#{endDate}, INTERVAL 1 SECOND)
|
||||||
|
)
|
||||||
|
OR
|
||||||
|
(
|
||||||
|
ri.ly_time <![CDATA[ >= ]]> #{statDate}
|
||||||
|
AND ri.ly_time <![CDATA[ < ]]> DATE_ADD(#{endDate}, INTERVAL 1 SECOND)
|
||||||
|
)
|
||||||
|
)
|
||||||
</if>
|
</if>
|
||||||
|
|
||||||
|
<!-- <!– 入库时间 –>-->
|
||||||
|
<!-- <if test="startTime != null">-->
|
||||||
|
<!-- AND ri.rk_time <![CDATA[ >= ]]> #{startTime}-->
|
||||||
|
<!-- </if>-->
|
||||||
|
<!-- <if test="endTime != null">-->
|
||||||
|
<!-- AND ri.rk_time <![CDATA[ < ]]> DATE_ADD(#{endTime}, INTERVAL 1 SECOND)-->
|
||||||
|
<!-- </if>-->
|
||||||
|
|
||||||
|
<!-- <!– 出库时间 –>-->
|
||||||
|
<!-- <if test="lyStartTime != null">-->
|
||||||
|
<!-- AND ri.ly_time <![CDATA[ >= ]]> #{lyStartTime}-->
|
||||||
|
<!-- </if>-->
|
||||||
|
<!-- <if test="lyEndTime != null">-->
|
||||||
|
<!-- AND ri.ly_time <![CDATA[ < ]]> DATE_ADD(#{lyEndTime}, INTERVAL 1 SECOND)-->
|
||||||
|
<!-- </if>-->
|
||||||
|
|
||||||
<if test="xmNo != null and xmNo != ''">
|
<if test="xmNo != null and xmNo != ''">
|
||||||
AND ri.xm_no LIKE CONCAT('%', #{xmNo}, '%')
|
AND ri.xm_no LIKE CONCAT('%', #{xmNo}, '%')
|
||||||
</if>
|
</if>
|
||||||
@@ -1247,76 +1455,12 @@
|
|||||||
AND ri.fycde_2 LIKE CONCAT('%', #{fycde2}, '%')
|
AND ri.fycde_2 LIKE CONCAT('%', #{fycde2}, '%')
|
||||||
</if>
|
</if>
|
||||||
</where>
|
</where>
|
||||||
</select>
|
|
||||||
|
|
||||||
<select id="selectPcde" resultType="java.lang.Long" parameterType="java.lang.Object" >
|
<!-- ✅ 核心排序规则 -->
|
||||||
SELECT count(distinct pcode)
|
ORDER BY
|
||||||
FROM rk_info ri
|
COALESCE(ri.ly_time, ri.rk_time) DESC,
|
||||||
<where>
|
ri.id DESC
|
||||||
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
|
||||||
|
|
||||||
<if test="isChuku != null and isChuku != ''">
|
|
||||||
AND ri.is_chuku = #{isChuku}
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="cangku != null and cangku != ''">
|
|
||||||
AND ri.cangku = #{cangku}
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="startTime != null">
|
|
||||||
AND ri.rk_time <![CDATA[ >= ]]> #{startTime}
|
|
||||||
</if>
|
|
||||||
<if test="endTime != null">
|
|
||||||
AND ri.rk_time <![CDATA[ <= ]]> #{endTime}
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="lyStartTime != null and lyStartTime != ''">
|
|
||||||
AND ri.ly_time <![CDATA[ >= ]]> #{lyStartTime}
|
|
||||||
</if>
|
|
||||||
<if test="lyEndTime != null and lyEndTime != ''">
|
|
||||||
AND ri.ly_time <![CDATA[ <= ]]> #{lyEndTime}
|
|
||||||
</if>
|
|
||||||
|
|
||||||
<if test="xmNo != null and xmNo != ''">
|
|
||||||
AND ri.xm_no LIKE CONCAT('%', #{xmNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="xmMs != null and xmMs != ''">
|
|
||||||
AND ri.xm_ms LIKE CONCAT('%', #{xmMs}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="wlNo != null and wlNo != ''">
|
|
||||||
AND ri.wl_no LIKE CONCAT('%', #{wlNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="wlMs != null and wlMs != ''">
|
|
||||||
AND ri.wl_ms LIKE CONCAT('%', #{wlMs}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="gysNo != null and gysNo != ''">
|
|
||||||
AND ri.gys_no LIKE CONCAT('%', #{gysNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="gysMc != null and gysMc != ''">
|
|
||||||
AND ri.gys_mc LIKE CONCAT('%', #{gysMc}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="sapNo != null and sapNo != ''">
|
|
||||||
AND ri.sap_no LIKE CONCAT('%', #{sapNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="billNo != null and billNo != ''">
|
|
||||||
AND ri.bill_no LIKE CONCAT('%', #{billNo}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="billNoCk != null and billNoCk != ''">
|
|
||||||
AND ri.bill_no_ck LIKE CONCAT('%', #{billNoCk}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="ckType != null and ckType != ''">
|
|
||||||
AND ri.ck_type LIKE CONCAT('%', #{ckType}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="pcode != null and pcode != ''">
|
|
||||||
AND ri.pcode LIKE CONCAT('%', #{pcode}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="fycde1 != null and fycde1 != ''">
|
|
||||||
AND ri.fycde_1 LIKE CONCAT('%', #{fycde1}, '%')
|
|
||||||
</if>
|
|
||||||
<if test="fycde2 != null and fycde2 != ''">
|
|
||||||
AND ri.fycde_2 LIKE CONCAT('%', #{fycde2}, '%')
|
|
||||||
</if>
|
|
||||||
</where>
|
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
<select id="selectDeliveryCkList"
|
<select id="selectDeliveryCkList"
|
||||||
@@ -1383,6 +1527,95 @@
|
|||||||
AND bill_no LIKE CONCAT(#{prefix}, '%')
|
AND bill_no LIKE CONCAT(#{prefix}, '%')
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<!-- 聚合统计:总金额、总数量、库位数 -->
|
||||||
|
<select id="selectStockStatistics" resultType="java.util.Map">
|
||||||
|
SELECT
|
||||||
|
-- 1. 总金额:合同单价 * 实际入库数量 (处理 null 为 0)
|
||||||
|
COALESCE(SUM(ri.ht_dj * ri.real_qty), 0) AS sumMoney,
|
||||||
|
|
||||||
|
-- 2. 总数量:实际入库数量求和
|
||||||
|
COALESCE(SUM(ri.real_qty), 0) AS sumQty,
|
||||||
|
|
||||||
|
-- 3. 库位数:去重统计 pcode
|
||||||
|
COUNT(DISTINCT ri.pcode) AS pcdeCount
|
||||||
|
|
||||||
|
FROM rk_info ri
|
||||||
|
<where>
|
||||||
|
-- 基础过滤:未删除
|
||||||
|
(ri.is_delete = '0' OR ri.is_delete = 0 OR ri.is_delete IS NULL)
|
||||||
|
|
||||||
|
-- 核心过滤:在库状态 (由Service传参或此处硬编码 '0')
|
||||||
|
<if test="isChuku != null and isChuku != ''">
|
||||||
|
AND ri.is_chuku = #{isChuku}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- 以下为动态查询条件,直接复用你 selectRkInfoList 的逻辑 -->
|
||||||
|
<if test="cangku != null and cangku != ''">
|
||||||
|
AND ri.cangku = #{cangku}
|
||||||
|
</if>
|
||||||
|
<if test="rkType != null and rkType != ''">
|
||||||
|
AND ri.rk_type = #{rkType}
|
||||||
|
</if>
|
||||||
|
<if test="wlType != null and wlType != ''">
|
||||||
|
AND ri.wl_type = #{wlType}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- 时间范围 -->
|
||||||
|
<if test="startTime != null">
|
||||||
|
AND ri.rk_time >= #{startTime}
|
||||||
|
</if>
|
||||||
|
<if test="endTime != null">
|
||||||
|
AND ri.rk_time <= #{endTime}
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- 模糊搜索 (复用原来的逻辑,确保结果与列表一致) -->
|
||||||
|
<if test="keyword != null and keyword != ''">
|
||||||
|
AND (
|
||||||
|
ri.xm_no LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.xm_ms LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.wl_no LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.wl_ms LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.gys_no LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.gys_mc LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.sap_no LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.bill_no LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.bill_no_ck LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.ck_type LIKE concat('%', #{keyword}, '%')
|
||||||
|
OR ri.pcode LIKE concat('%', #{keyword}, '%')
|
||||||
|
)
|
||||||
|
</if>
|
||||||
|
|
||||||
|
<!-- 单字段精确/模糊匹配 -->
|
||||||
|
<if test="xmNo != null and xmNo != ''">
|
||||||
|
AND ri.xm_no LIKE CONCAT('%', #{xmNo}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="xmMs != null and xmMs != ''">
|
||||||
|
AND ri.xm_ms LIKE CONCAT('%', #{xmMs}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="wlNo != null and wlNo != ''">
|
||||||
|
AND ri.wl_no LIKE CONCAT('%', #{wlNo}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="wlMs != null and wlMs != ''">
|
||||||
|
AND ri.wl_ms LIKE CONCAT('%', #{wlMs}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="gysNo != null and gysNo != ''">
|
||||||
|
AND ri.gys_no LIKE CONCAT('%', #{gysNo}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="gysMc != null and gysMc != ''">
|
||||||
|
AND ri.gys_mc LIKE CONCAT('%', #{gysMc}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="sapNo != null and sapNo != ''">
|
||||||
|
AND ri.sap_no LIKE CONCAT('%', #{sapNo}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="billNo != null and billNo != ''">
|
||||||
|
AND ri.bill_no LIKE CONCAT('%', #{billNo}, '%')
|
||||||
|
</if>
|
||||||
|
<if test="pcode != null and pcode != ''">
|
||||||
|
AND ri.pcode LIKE CONCAT('%', #{pcode}, '%')
|
||||||
|
</if>
|
||||||
|
</where>
|
||||||
|
</select>
|
||||||
|
|
||||||
<update id="updateBillInfo" parameterType="com.zg.project.wisdom.domain.RkInfo">
|
<update id="updateBillInfo" parameterType="com.zg.project.wisdom.domain.RkInfo">
|
||||||
UPDATE rk_info
|
UPDATE rk_info
|
||||||
<set>
|
<set>
|
||||||
|
|||||||
Reference in New Issue
Block a user