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>
|
||||
|
||||
<name>zg</name>
|
||||
<url>http://www.zg.vip</url>
|
||||
<description>智慧实物管理系统</description>
|
||||
|
||||
<!-- ======================= -->
|
||||
|
||||
@@ -1116,6 +1116,9 @@ public class ExcelUtil<T>
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加单元格
|
||||
*/
|
||||
/**
|
||||
* 添加单元格
|
||||
*/
|
||||
@@ -1126,11 +1129,13 @@ public class ExcelUtil<T>
|
||||
{
|
||||
// 设置行高
|
||||
row.setHeight(maxHeight);
|
||||
// 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
|
||||
|
||||
// 根据Excel中设置情况决定是否导出
|
||||
if (attr.isExport())
|
||||
{
|
||||
// 创建cell
|
||||
cell = row.createCell(column);
|
||||
|
||||
if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
|
||||
{
|
||||
if (subMergedLastRowNum >= subMergedFirstRowNum)
|
||||
@@ -1138,14 +1143,45 @@ public class ExcelUtil<T>
|
||||
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())));
|
||||
|
||||
// 用于读取对象中的属性
|
||||
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 readConverterExp = attr.readConverterExp();
|
||||
String separator = attr.separator();
|
||||
String dictType = attr.dictType();
|
||||
|
||||
if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
|
||||
{
|
||||
cell.getCellStyle().setDataFormat(this.wb.getCreationHelper().createDataFormat().getFormat(dateFormat));
|
||||
@@ -1164,10 +1200,6 @@ public class ExcelUtil<T>
|
||||
}
|
||||
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))
|
||||
{
|
||||
cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
|
||||
@@ -1177,6 +1209,7 @@ public class ExcelUtil<T>
|
||||
// 设置列类型
|
||||
setCellVo(value, attr, cell);
|
||||
}
|
||||
|
||||
addStatisticsData(column, Convert.toStr(value), attr);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,16 +18,16 @@ import java.util.concurrent.ThreadPoolExecutor;
|
||||
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 keepAliveSeconds = 300;
|
||||
private int keepAliveSeconds = 120;
|
||||
|
||||
@Bean(name = "threadPoolTaskExecutor")
|
||||
public ThreadPoolTaskExecutor threadPoolTaskExecutor()
|
||||
|
||||
@@ -54,7 +54,7 @@ public class ConstructionTeamController extends BaseController
|
||||
}
|
||||
|
||||
/**
|
||||
* 导入施工队数据(全部新增,不校验重复)
|
||||
* 导入施工队数据(全部新增)
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('information:construction:import')")
|
||||
@Log(title = "施工队信息", businessType = BusinessType.IMPORT)
|
||||
|
||||
@@ -38,6 +38,7 @@ public class PcdeDetailController extends BaseController
|
||||
public TableDataInfo list(PcdeDetail pcdeDetail)
|
||||
{
|
||||
startPage();
|
||||
System.out.printf("111111");
|
||||
List<PcdeDetail> list = pcdeDetailService.selectPcdeDetailList(pcdeDetail);
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
@@ -19,7 +19,7 @@ public class Mtd extends BaseEntity
|
||||
private Long Id;
|
||||
|
||||
/** 物料号 */
|
||||
@Excel(name = "物料号")
|
||||
@Excel(name = "物料编号")
|
||||
private String mid;
|
||||
|
||||
/** 物料描述 */
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.zg.project.information.mapper;
|
||||
|
||||
import java.util.List;
|
||||
import com.zg.project.information.domain.ConstructionTeam;
|
||||
import io.lettuce.core.dynamic.annotation.Param;
|
||||
|
||||
/**
|
||||
* 施工队信息Mapper接口
|
||||
@@ -35,6 +36,12 @@ public interface ConstructionTeamMapper
|
||||
*/
|
||||
public int insertConstructionTeam(ConstructionTeam constructionTeam);
|
||||
|
||||
/**
|
||||
* 查询当前最大施工队编号
|
||||
*/
|
||||
String selectMaxTeamCode();
|
||||
|
||||
|
||||
/**
|
||||
* 修改施工队信息
|
||||
*
|
||||
@@ -58,4 +65,8 @@ public interface ConstructionTeamMapper
|
||||
* @return 结果
|
||||
*/
|
||||
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 selectEncodedIdByPcodeAndWarehouse(@Param("pcode") String pcode,
|
||||
@Param("warehouseCode") String warehouseCode);
|
||||
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.zg.project.information.service.impl;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import com.zg.common.exception.ServiceException;
|
||||
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.service.IConstructionTeamService;
|
||||
|
||||
import static com.zg.common.utils.SecurityUtils.getUsername;
|
||||
|
||||
/**
|
||||
* 施工队信息Service业务层处理
|
||||
*
|
||||
@@ -56,9 +60,36 @@ public class ConstructionTeamServiceImpl implements IConstructionTeamService
|
||||
@Override
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* 生成施工队编号(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 operName 操作人员
|
||||
@@ -113,54 +144,106 @@ public class ConstructionTeamServiceImpl implements IConstructionTeamService
|
||||
int successNum = 0;
|
||||
int failureNum = 0;
|
||||
StringBuilder failureMsg = new StringBuilder();
|
||||
|
||||
Date now = new Date();
|
||||
|
||||
// ===== ① Excel 内去重 =====
|
||||
Set<String> teamCodeSet = new HashSet<>();
|
||||
Set<String> teamNameSet = new HashSet<>();
|
||||
|
||||
for (ConstructionTeam team : teamList)
|
||||
{
|
||||
String teamCode = team.getTeamCode();
|
||||
String teamName = team.getTeamName();
|
||||
|
||||
if (StringUtils.isBlank(teamCode) || StringUtils.isBlank(teamName))
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>施工队名称/编号不能为空,已跳过。");
|
||||
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.getTeamName()) || StringUtils.isBlank(team.getTeamCode()))
|
||||
// 跳过前面校验失败的数据
|
||||
if (StringUtils.isBlank(team.getTeamCode()) || StringUtils.isBlank(team.getTeamName()))
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>施工队名称/编号不能为空,已跳过。");
|
||||
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.setCreatedAt(now);
|
||||
team.setUpdatedBy(operName);
|
||||
team.setUpdatedAt(now);
|
||||
|
||||
// isDelete 默认 0
|
||||
if (StringUtils.isBlank(team.getIsDelete()))
|
||||
{
|
||||
team.setIsDelete("0");
|
||||
}
|
||||
|
||||
// 走你现有 insert(Mapper/XML 已存在)
|
||||
insertConstructionTeam(team);
|
||||
|
||||
constructionTeamMapper.insertConstructionTeam(team);
|
||||
successNum++;
|
||||
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
failureNum++;
|
||||
failureMsg.append("<br/>施工队编号:").append(team.getTeamCode())
|
||||
.append(",施工队名称:").append(team.getTeamName())
|
||||
.append(" 导入失败:").append(e.getMessage());
|
||||
failureMsg.append("<br/>施工队编号:")
|
||||
.append(team.getTeamCode())
|
||||
.append(",施工队名称:")
|
||||
.append(team.getTeamName())
|
||||
.append(" 导入失败:")
|
||||
.append(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
if (failureNum > 0)
|
||||
{
|
||||
failureMsg.insert(0, "导入完成,但有 " + failureNum + " 条记录失败:");
|
||||
failureMsg.insert(0,
|
||||
"导入完成,成功 " + successNum + " 条,失败 " + failureNum + " 条:");
|
||||
throw new ServiceException(failureMsg.toString());
|
||||
}
|
||||
|
||||
return "导入成功,共 " + successNum + " 条数据";
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -7,6 +7,8 @@ import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
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.mapper.GysJhMapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -67,9 +69,37 @@ public class MtdServiceImpl implements IMtdService
|
||||
* @return 结果
|
||||
*/
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
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")
|
||||
public AjaxResult upGoods(@RequestBody OutGoodsDTO dto) {
|
||||
|
||||
if (StringUtils.isBlank(dto.getTaskNo())) {
|
||||
throw new ServiceException("taskNo 不能为空");
|
||||
}
|
||||
// 返回 taskId
|
||||
String taskId = agvTaskResultService.handleUpGoods(dto.getTaskNo(), dto.getMaterialStatus());
|
||||
|
||||
return AjaxResult.success("上架任务已提交至WCS").put("taskId", taskId);
|
||||
}
|
||||
|
||||
|
||||
@@ -22,7 +22,7 @@ import org.springframework.security.access.prepost.PreAuthorize;
|
||||
* @author zg
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/wisdom/task")
|
||||
@RequestMapping("/wisdom/dispatch")
|
||||
public class DdTaskController extends BaseController {
|
||||
|
||||
@Autowired
|
||||
|
||||
@@ -33,7 +33,7 @@ public class GysJhController extends BaseController
|
||||
@Autowired
|
||||
private IGysJhService gysJhService;
|
||||
|
||||
/**A
|
||||
/**
|
||||
* 查询供应计划列表
|
||||
*/
|
||||
@PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
||||
@@ -52,10 +52,8 @@ public class GysJhController extends BaseController
|
||||
*/
|
||||
// @PreAuthorize("@ss.hasPermi('plan:jh:list')")
|
||||
@GetMapping("/getBySapNo")
|
||||
public AjaxResult getBySapNo(String sapNo)
|
||||
{
|
||||
List<GysJh> list = gysJhService.getBySapNo(sapNo);
|
||||
return success(list);
|
||||
public AjaxResult getBySapNo(@RequestParam String sapNo) {
|
||||
return gysJhService.getBySapNo(sapNo);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -6,11 +6,11 @@ import java.util.Map;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import com.github.pagehelper.PageHelper;
|
||||
import com.zg.common.utils.StringUtils;
|
||||
import com.zg.project.wisdom.domain.dto.*;
|
||||
import com.zg.project.wisdom.domain.vo.DeliveryBillVO;
|
||||
import com.zg.project.wisdom.domain.vo.PcodeQtyVO;
|
||||
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.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
@@ -67,17 +67,21 @@ public class RkInfoController extends BaseController
|
||||
return getDataTable(list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 库存查询
|
||||
* @param dto
|
||||
* @return
|
||||
*/
|
||||
@PostMapping("/pageStatistics")
|
||||
public Map<String, Object> pageStatistics(@RequestBody RkInfoQueryDTO dto) {
|
||||
|
||||
// 使用 PageHelper 分页
|
||||
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')")
|
||||
@PostMapping("/bill/groups")
|
||||
public TableDataInfo billGroups(@RequestBody RkInfoQueryDTO query) {
|
||||
// 分页
|
||||
PageHelper.startPage(query.getPageNum(), query.getPageSize());
|
||||
// 查询
|
||||
List<RkInfo> rows = rkInfoService.selectGroupedByBill(query);
|
||||
// @PostMapping("/bill/groups")
|
||||
// public TableDataInfo billGroups(@RequestBody RkInfoQueryDTO query) {
|
||||
// // 分页
|
||||
// PageHelper.startPage(query.getPageNum(), query.getPageSize());
|
||||
// // 查询
|
||||
// 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);
|
||||
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')")
|
||||
@Log(title = "库存单据主", businessType = BusinessType.UPDATE)
|
||||
@PutMapping("/update")
|
||||
@PostMapping("/update")
|
||||
public AjaxResult edit(@RequestBody RkInfo 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;
|
||||
|
||||
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.service.RkStatisticsService;
|
||||
import com.zg.project.wisdom.service.WarehouseStatService;
|
||||
@@ -178,4 +179,10 @@ public class RkStatisticsController {
|
||||
List<IOBucketVO> rows = rkStatisticsService.getIOBuckets(range);
|
||||
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;
|
||||
|
||||
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.ToStringStyle;
|
||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||
@@ -19,6 +22,10 @@ public class GysJh extends BaseEntity
|
||||
/** 主键ID */
|
||||
private Long id;
|
||||
|
||||
/** 行号 */
|
||||
@Excel(name = "行号")
|
||||
private String xh;
|
||||
|
||||
/** 序号 */
|
||||
@Excel(name = "序号")
|
||||
private Long indexNo;
|
||||
@@ -59,25 +66,24 @@ public class GysJh extends BaseEntity
|
||||
@Excel(name = "合同单价")
|
||||
private BigDecimal htDj;
|
||||
|
||||
/** 合同数量 */
|
||||
@Excel(name = "合同数量")
|
||||
private BigDecimal htQty;
|
||||
|
||||
/** SAP订单编号 */
|
||||
@Excel(name = "SAP订单编号")
|
||||
private String sapNo;
|
||||
|
||||
/** 行号 */
|
||||
@Excel(name = "行号")
|
||||
private String xh;
|
||||
|
||||
/** 计划交货数量 */
|
||||
@Excel(name = "计划交货数量")
|
||||
private BigDecimal jhQty;
|
||||
|
||||
/** 合同数量 */
|
||||
private BigDecimal htQty;
|
||||
/** 计量单位 */
|
||||
@Excel(name = "计量单位")
|
||||
private String dw;
|
||||
|
||||
/** 0:未到货,1:已入库,2部分入库 */
|
||||
@Excel(name = "0:未到货,1:已入库,2部分入库")
|
||||
// @Excel(name = "0:未到货,1:已入库,2部分入库")
|
||||
private String status;
|
||||
|
||||
/** 身份码 */
|
||||
@@ -89,9 +95,17 @@ public class GysJh extends BaseEntity
|
||||
private String remark;
|
||||
|
||||
/** 是否删除(0正常 1删除) */
|
||||
@Excel(name = "是否删除", readConverterExp = "0=正常,1=删除")
|
||||
// @Excel(name = "是否删除", readConverterExp = "0=正常,1=删除")
|
||||
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)
|
||||
{
|
||||
this.id = id;
|
||||
@@ -278,6 +292,23 @@ public class GysJh extends BaseEntity
|
||||
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
|
||||
public String toString() {
|
||||
return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
|
||||
|
||||
@@ -29,8 +29,12 @@ public class RkInfo extends BaseEntity {
|
||||
@TableField(exist = false)
|
||||
private List<Long> ids;
|
||||
|
||||
/** 是否已出库(0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销) */
|
||||
@Excel(name = "库存状态", readConverterExp = "0=已入库,1=已出库,2=待审批,3=借料出库,4=入库撤销,5=出库撤销")
|
||||
private String isChuku;
|
||||
|
||||
/** 供应计划ID(对应供应计划表主键) */
|
||||
@Excel(name = "供应计划ID")
|
||||
// @Excel(name = "供应计划ID")
|
||||
private Long gysJhId;
|
||||
|
||||
/** 审批人ID(非数据库字段) */
|
||||
@@ -70,7 +74,7 @@ public class RkInfo extends BaseEntity {
|
||||
|
||||
/** 所属大仓编码 */
|
||||
@TableField(exist = false)
|
||||
@Excel(name = "所属大仓编码")
|
||||
// @Excel(name = "所属大仓编码")
|
||||
private String parentWarehouseCode;
|
||||
|
||||
/** 所属大仓名称 */
|
||||
@@ -80,7 +84,7 @@ public class RkInfo extends BaseEntity {
|
||||
|
||||
/** 所属小仓编码 */
|
||||
@TableField(exist = false)
|
||||
@Excel(name = "所属小仓编码")
|
||||
// @Excel(name = "所属小仓编码")
|
||||
private String warehouseCode;
|
||||
|
||||
/** 所属小仓名称 */
|
||||
@@ -105,16 +109,13 @@ public class RkInfo extends BaseEntity {
|
||||
private Date returnTime;
|
||||
|
||||
/** 理货员 */
|
||||
@Excel(name = "理货员")
|
||||
// @Excel(name = "理货员")
|
||||
private String lihuoY;
|
||||
|
||||
/** 理货员名称(联查显示用,导出专用) */
|
||||
@Excel(name = "理货员")
|
||||
private String lihuoYName;
|
||||
|
||||
/** 是否已出库(0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销) */
|
||||
@Excel(name = "是否已出库", readConverterExp = "0已入库,1已出库,2待审批,3借料出库,4入库撤销,5出库撤销")
|
||||
private String isChuku;
|
||||
|
||||
/** 单据号 */
|
||||
@Excel(name = "单据号")
|
||||
private String billNo;
|
||||
@@ -124,11 +125,11 @@ public class RkInfo extends BaseEntity {
|
||||
private String billNoCk;
|
||||
|
||||
/** 是否需要配送(0否 1是 2配送中 3配送完成) */
|
||||
@Excel(name = "是否需要配送", readConverterExp = "0=否,1=是,2=配送中,3=配送完成")
|
||||
// @Excel(name = "是否需要配送", readConverterExp = "0=否,1=是,2=配送中,3=配送完成")
|
||||
private String isDelivery;
|
||||
|
||||
/** 县局 */
|
||||
@Excel(name = "县局")
|
||||
// @Excel(name = "县局")
|
||||
private String xj;
|
||||
|
||||
/** 项目号 */
|
||||
@@ -139,10 +140,10 @@ public class RkInfo extends BaseEntity {
|
||||
@Excel(name = "库存项目描述")
|
||||
private String xmMs;
|
||||
|
||||
@Excel(name = "领取方项目号")
|
||||
// @Excel(name = "领取方项目号")
|
||||
private String xmNoCk;
|
||||
|
||||
@Excel(name = "领取方项目描述")
|
||||
// @Excel(name = "领取方项目描述")
|
||||
private String xmMsCk;
|
||||
|
||||
/** 物料号 */
|
||||
@@ -174,7 +175,7 @@ public class RkInfo extends BaseEntity {
|
||||
private String sapNo;
|
||||
|
||||
/** 行号 */
|
||||
@Excel(name = "行号")
|
||||
// @Excel(name = "行号")
|
||||
private String xh;
|
||||
|
||||
/** 计划交货数量 */
|
||||
@@ -193,12 +194,19 @@ public class RkInfo extends BaseEntity {
|
||||
@Excel(name = "实际入库数量")
|
||||
private BigDecimal realQty;
|
||||
|
||||
/** 总金额 = 合同单价 × 实际入库数量(导出专用) */
|
||||
@Excel(name = "总金额")
|
||||
private BigDecimal totalAmount;
|
||||
|
||||
@Excel(name = "备注")
|
||||
private String remark;
|
||||
|
||||
/** 库位码(编码) */
|
||||
@Excel(name = "库位码")
|
||||
private String pcode;
|
||||
|
||||
/** 库位主键ID(pcde_detail.id) */
|
||||
@Excel(name = "库位主键ID")
|
||||
// @Excel(name = "库位主键ID")
|
||||
private String pcodeId;
|
||||
|
||||
/** 托盘码 */
|
||||
@@ -206,7 +214,7 @@ public class RkInfo extends BaseEntity {
|
||||
private String trayCode;
|
||||
|
||||
/** 实物ID */
|
||||
@Excel(name = "实物ID")
|
||||
// @Excel(name = "实物ID")
|
||||
private String entityId;
|
||||
|
||||
/** 一货一图 - 货物照片URL(非表字段) */
|
||||
@@ -227,21 +235,21 @@ public class RkInfo extends BaseEntity {
|
||||
private String teamName;
|
||||
|
||||
@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;
|
||||
|
||||
@Excel(name = "出库备注")
|
||||
private String ckRemark;
|
||||
|
||||
@Excel(name = "出库备注")
|
||||
// @Excel(name = "审核状态")
|
||||
private String status;
|
||||
|
||||
/** 是否移库过(0否 1是) */
|
||||
@Excel(name = "是否移库过")
|
||||
// @Excel(name = "是否移库过")
|
||||
private String hasMoved;
|
||||
|
||||
/** 是否借料(0否 1是 2已归还) */
|
||||
@Excel(name = "是否借料", readConverterExp = "0=否,1=是,2=已归还")
|
||||
// @Excel(name = "是否借料", readConverterExp = "0=否,1=是,2=已归还")
|
||||
private String isBorrowed;
|
||||
|
||||
/** 签字图片URL(image_type = sign,非表字段) */
|
||||
@@ -452,6 +460,14 @@ public class RkInfo extends BaseEntity {
|
||||
public String getCkRemark() { return 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 void setStatus(String status) { this.status = status; }
|
||||
|
||||
@@ -488,6 +504,14 @@ public class RkInfo extends BaseEntity {
|
||||
public String getFycde2() { return 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 void setIsDelete(String isDelete) { this.isDelete = isDelete; }
|
||||
|
||||
|
||||
@@ -1,9 +1,17 @@
|
||||
package com.zg.project.wisdom.domain.dto;
|
||||
|
||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class OutGoodsDTO {
|
||||
private String taskNo;
|
||||
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 warehouseCode;
|
||||
|
||||
/** 入库类型 */
|
||||
private String rkType;
|
||||
}
|
||||
|
||||
@@ -20,10 +20,10 @@ public class RkInfoQueryDTO extends RkInfo {
|
||||
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;
|
||||
|
||||
/** 结束时间 */
|
||||
@JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
|
||||
@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
|
||||
private Date endDate;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.zg.project.wisdom.domain.dto;
|
||||
|
||||
import com.zg.framework.aspectj.lang.annotation.Excel;
|
||||
import lombok.Data;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
/**
|
||||
* 出库明细 DTO
|
||||
*/
|
||||
@@ -20,6 +23,9 @@ public class StockOutItemDTO {
|
||||
/** 托盘码 */
|
||||
private String trayCode;
|
||||
|
||||
/** 实际数量 */
|
||||
private BigDecimal realQty;
|
||||
|
||||
/** 现场照片(单张) */
|
||||
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<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;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.zg.project.inventory.domain.vo.PcdeCntVO;
|
||||
import com.zg.project.inventory.domain.vo.RkInfoMatchVO;
|
||||
@@ -34,12 +35,14 @@ public interface RkInfoMapper
|
||||
|
||||
/**
|
||||
* 使用 selectRkInfoVo 作为子查询,外层按 bill_no 分组聚合
|
||||
* 不新增 resultMap / VO,直接用 RkInfoResult 映射需要的字段
|
||||
*/
|
||||
List<RkInfo> selectGroupedByBill(@Param("q") RkInfoQueryDTO query,
|
||||
@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);
|
||||
|
||||
/**
|
||||
* 根据出库单据号更新库存单据
|
||||
*
|
||||
* @param rkInfo 库存单据
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updateByBillNoCk(RkInfo rkInfo);
|
||||
|
||||
/**
|
||||
* 删除库存单据主
|
||||
*
|
||||
@@ -107,7 +118,7 @@ public interface RkInfoMapper
|
||||
List<RkInfo> selectTopOverdueStock(@Param("limit") int limit);
|
||||
|
||||
/**
|
||||
* 出库操作
|
||||
*
|
||||
* @param update
|
||||
*/
|
||||
void updateById(RkInfo update);
|
||||
@@ -226,9 +237,10 @@ public interface RkInfoMapper
|
||||
*/
|
||||
List<RkInfo> selectAllRkInfo(RkInfo query);
|
||||
|
||||
Long selectStatistics(RkInfo query);
|
||||
|
||||
Long selectPcde(RkInfo query);
|
||||
/**
|
||||
* 出入库明细分页查询(统计页面)
|
||||
*/
|
||||
List<RkInfo> selectRkInfoPageList(RkInfo query);
|
||||
|
||||
int updateBillInfo(RkInfo query);
|
||||
|
||||
@@ -254,4 +266,7 @@ public interface RkInfoMapper
|
||||
RkInfo selectHeaderByBillNo(String billNo);
|
||||
|
||||
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;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import com.zg.framework.web.domain.AjaxResult;
|
||||
import com.zg.project.wisdom.domain.GysJh;
|
||||
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
@@ -51,6 +53,9 @@ public interface IGysJhService
|
||||
* @param ids 需要删除的供应计划主键集合
|
||||
* @return 结果
|
||||
*/
|
||||
|
||||
|
||||
|
||||
public int deleteGysJhByIds(Long[] ids);
|
||||
|
||||
/**
|
||||
@@ -74,7 +79,7 @@ public interface IGysJhService
|
||||
* @param sapNo
|
||||
* @return
|
||||
*/
|
||||
List<GysJh> getBySapNo(String sapNo);
|
||||
AjaxResult getBySapNo(String sapNo);
|
||||
|
||||
/**
|
||||
* 按字段映射导入供应计划
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.zg.project.wisdom.service;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.zg.project.inventory.domain.dto.QueryDTO;
|
||||
import com.zg.project.inventory.domain.vo.ChartDataVO;
|
||||
@@ -38,6 +39,10 @@ public interface IRkInfoService
|
||||
*/
|
||||
List<RkInfo> selectGroupedByBill(RkInfoQueryDTO query);
|
||||
|
||||
// 接口
|
||||
List<RkInfo> selectBillHeaderList(RkInfoQueryDTO query);
|
||||
|
||||
|
||||
/**
|
||||
* 修改库存单据主
|
||||
*
|
||||
@@ -46,6 +51,14 @@ public interface IRkInfoService
|
||||
*/
|
||||
public int updateRkInfo(RkInfo rkInfo);
|
||||
|
||||
/**
|
||||
* 根据出库单据号修改库存单据
|
||||
*
|
||||
* @param rkInfo 库存单据
|
||||
* @return 影响行数
|
||||
*/
|
||||
int updateRkInfoByBillNoCk(RkInfo rkInfo);
|
||||
|
||||
/**
|
||||
* 批量删除库存单据主
|
||||
*
|
||||
@@ -160,9 +173,10 @@ public interface IRkInfoService
|
||||
*/
|
||||
List<RkInfo> selectAllRkInfo(RkInfo query);
|
||||
|
||||
Long selectStatistics(RkInfo query);
|
||||
|
||||
Long selectPcde(RkInfo query);
|
||||
/**
|
||||
* 出入库明细分页查询(统计页面)
|
||||
*/
|
||||
List<RkInfo> selectRkInfoPageList(RkInfo query);
|
||||
|
||||
public int updateBillInfo(RkInfo rkInfo);
|
||||
|
||||
|
||||
@@ -87,6 +87,7 @@ public class QwenOcrRemoteService {
|
||||
|
||||
// 远程服务返回:{ success: true, found: true/false, erpOrderNo: "0101398982" }
|
||||
JsonNode erpNode = rootNode.get("erpOrderNo");
|
||||
|
||||
if (erpNode == null || erpNode.isNull()) {
|
||||
return "";
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.zg.project.wisdom.service;
|
||||
|
||||
import com.zg.project.wisdom.domain.dto.RkInfoQueryDTO;
|
||||
import com.zg.project.wisdom.domain.vo.*;
|
||||
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
@@ -87,4 +88,11 @@ public interface RkStatisticsService {
|
||||
* 规则:排除 rk_info 中未出库(is_chuku=0 或 NULL)的占用库位
|
||||
*/
|
||||
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
|
||||
*/
|
||||
/**
|
||||
* 货物上架
|
||||
*/
|
||||
@Override
|
||||
public String handleUpGoods(String taskNo, Integer materialStatus) {
|
||||
|
||||
Date now = DateUtils.getNowDate();
|
||||
|
||||
// 1. 查询调度任务
|
||||
@@ -172,13 +176,11 @@ public class AgvTaskResultServiceImpl implements IAgvTaskResultService {
|
||||
|
||||
// 3. 发起调用
|
||||
String wcsResp = OkHttpUtils.postJson(wcsJobCreateUrl, wcsParam.toJSONString());
|
||||
|
||||
if (StringUtils.isBlank(wcsResp)) {
|
||||
throw new ServiceException("WCS 接口无响应");
|
||||
}
|
||||
|
||||
JSONObject json = JSON.parseObject(wcsResp);
|
||||
|
||||
if (!json.containsKey("result")) {
|
||||
throw new ServiceException("WCS 返回格式异常:" + wcsResp);
|
||||
}
|
||||
@@ -203,12 +205,19 @@ public class AgvTaskResultServiceImpl implements IAgvTaskResultService {
|
||||
wcs.setUpdateTime(now);
|
||||
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
|
||||
return taskId;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 货物下架
|
||||
* @param
|
||||
|
||||
@@ -8,6 +8,7 @@ import com.zg.common.exception.ServiceException;
|
||||
import com.zg.common.utils.DateUtils;
|
||||
import com.zg.common.utils.SecurityUtils;
|
||||
import com.zg.common.utils.StringUtils;
|
||||
import com.zg.framework.web.domain.AjaxResult;
|
||||
import com.zg.project.wisdom.domain.dto.ExcelFieldMapping;
|
||||
import org.apache.poi.ss.usermodel.*;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
@@ -162,11 +163,40 @@ public class GysJhServiceImpl implements IGysJhService
|
||||
* @return
|
||||
*/
|
||||
@Override
|
||||
public List<GysJh> getBySapNo(String sapNo) {
|
||||
return gysJhMapper.getBySapNo(sapNo);
|
||||
public AjaxResult getBySapNo(String 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
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int importByMapping(MultipartFile file, List<ExcelFieldMapping> mapping) throws Exception {
|
||||
|
||||
@@ -107,6 +107,11 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
||||
return moveRecordMapper.deleteMoveRecordById(id);
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理库存移库操作
|
||||
*
|
||||
* @param dto 移库请求参数(包含原库存ID、移库目标列表等)
|
||||
*/
|
||||
/**
|
||||
* 处理库存移库操作
|
||||
*
|
||||
@@ -124,11 +129,6 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
||||
throw new ServiceException("目标位置列表不能为空");
|
||||
}
|
||||
|
||||
// 0.1 校验每个目标库位与仓库关系
|
||||
for (MoveTargetItem target : dto.getTargets()) {
|
||||
validatePcodeWarehouseRelation(target.getToPcode(), target.getToCangku());
|
||||
}
|
||||
|
||||
// 1. 查询原始库存记录
|
||||
RkInfo original = rkInfoMapper.selectRkInfoById(dto.getFromRkId());
|
||||
if (original == null || "1".equals(original.getIsDelete())) {
|
||||
@@ -154,69 +154,61 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
||||
String username = dto.getMovedBy();
|
||||
Date now = DateUtils.parseDate(dto.getMovedAt());
|
||||
|
||||
// ===== 情况一:整库移库(目标总数量 = 原库存,且仅一个目标)=====
|
||||
// ===== 情况一:整库移库(单目标 + 数量相等)=====
|
||||
if (dto.getTargets().size() == 1 && totalQty.compareTo(realQty) == 0) {
|
||||
MoveTargetItem target = dto.getTargets().get(0);
|
||||
|
||||
// 记录移库前快照
|
||||
RkInfo info = new RkInfo();
|
||||
BeanUtils.copyProperties(original, info);
|
||||
// 移库前快照
|
||||
RkInfo snapshot = new RkInfo();
|
||||
BeanUtils.copyProperties(original, snapshot);
|
||||
|
||||
// ✅ 更新原库存到新位置(统一写入 cangku)
|
||||
// 更新原库存位置
|
||||
original.setCangku(target.getToCangku());
|
||||
original.setPcode(target.getToPcode());
|
||||
original.setTrayCode(target.getToTrayCode());
|
||||
|
||||
// ✅ 发生移库就标记
|
||||
original.setHasMoved("1");
|
||||
|
||||
original.setUpdateBy(username);
|
||||
original.setUpdateTime(now);
|
||||
rkInfoMapper.updateRkInfo(original);
|
||||
|
||||
// 记录移库日志(从 info → target)
|
||||
moveRecordMapper.insertMoveRecord(createMoveRecord(info, target, dto));
|
||||
// 移库记录
|
||||
moveRecordMapper.insertMoveRecord(
|
||||
createMoveRecord(snapshot, target, dto)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
// ===== 情况二 & 三:需要新建多条库存记录 =====
|
||||
// ===== 情况二 / 三:拆分移库 =====
|
||||
List<RkInfo> insertList = new ArrayList<>();
|
||||
|
||||
// ✅ 注意:做移库的“来源记录快照”,用于日志一致性(不受后面数量更新影响)
|
||||
// 来源快照(用于日志 & 新库存模板)
|
||||
RkInfo fromSnapshot = new RkInfo();
|
||||
BeanUtils.copyProperties(original, fromSnapshot);
|
||||
|
||||
// 情况三:部分移库(目标总量 < 原库存) → 原库存数量减少
|
||||
// 情况三:部分移库(原库存减少)
|
||||
if (totalQty.compareTo(realQty) < 0) {
|
||||
original.setRealQty(realQty.subtract(totalQty));
|
||||
|
||||
// ✅ 关键:发生移库就标记(你问的 has_moved 应该是 1)
|
||||
original.setHasMoved("1");
|
||||
|
||||
original.setUpdateBy(username);
|
||||
original.setUpdateTime(now);
|
||||
rkInfoMapper.updateRkInfo(original);
|
||||
} else {
|
||||
// 情况二:原库存刚好用完(但目标多个) → 删除原库存
|
||||
// 情况二:原库存刚好用完(但目标多个)
|
||||
rkInfoMapper.deleteRkInfoById(original.getId());
|
||||
}
|
||||
|
||||
// 新增多条目标库存
|
||||
// 新增目标库存
|
||||
for (MoveTargetItem target : dto.getTargets()) {
|
||||
RkInfo newInfo = new RkInfo();
|
||||
|
||||
// ✅ 以“移库前快照”作为模板,避免被上面修改过数量影响其它字段
|
||||
// 以移库前快照为模板
|
||||
BeanUtils.copyProperties(fromSnapshot, newInfo, "id");
|
||||
|
||||
// ✅ 目标位置字段
|
||||
newInfo.setCangku(target.getToCangku());
|
||||
newInfo.setPcode(target.getToPcode());
|
||||
newInfo.setTrayCode(target.getToTrayCode());
|
||||
|
||||
// ✅ 目标数量
|
||||
newInfo.setRealQty(target.getRealQty());
|
||||
|
||||
// ✅ 发生移库就标记
|
||||
newInfo.setHasMoved("1");
|
||||
|
||||
newInfo.setCreateBy(username);
|
||||
@@ -226,8 +218,10 @@ public class MoveRecordServiceImpl implements IMoveRecordService
|
||||
|
||||
insertList.add(newInfo);
|
||||
|
||||
// ✅ 移库记录:从“移库前快照” → 每个 target(更准确)
|
||||
moveRecordMapper.insertMoveRecord(createMoveRecord(fromSnapshot, target, dto));
|
||||
// 移库记录
|
||||
moveRecordMapper.insertMoveRecord(
|
||||
createMoveRecord(fromSnapshot, target, dto)
|
||||
);
|
||||
}
|
||||
|
||||
if (!insertList.isEmpty()) {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.zg.project.wisdom.service.impl;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.LocalDate;
|
||||
import java.time.ZoneId;
|
||||
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.SecurityUtils;
|
||||
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.Task.mapper.InventoryTaskMapper;
|
||||
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 org.springframework.beans.BeanUtils;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
|
||||
import org.springframework.stereotype.Service;
|
||||
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
||||
import com.zg.project.wisdom.domain.RkInfo;
|
||||
import com.zg.project.wisdom.service.IRkInfoService;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
import static com.zg.common.utils.SecurityUtils.getUsername;
|
||||
|
||||
/**
|
||||
@@ -69,6 +76,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
@Autowired
|
||||
private PcdeDetailMapper pcdeDetailMapper;
|
||||
|
||||
@Autowired
|
||||
private MtdMapper mtdMapper;
|
||||
|
||||
/**
|
||||
* 查询库存单据主
|
||||
@@ -89,43 +98,19 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
* @return 库存单据主
|
||||
*/
|
||||
@Override
|
||||
public List<RkInfo> selectRkInfoList(RkInfo rkInfo) {
|
||||
public List<RkInfo> selectRkInfoList(RkInfo rkInfo)
|
||||
{
|
||||
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
||||
|
||||
List<RkInfo> list = rkInfoMapper.selectRkInfoList(rkInfo);
|
||||
LocalDate today = LocalDate.now();
|
||||
|
||||
for (RkInfo info : list) {
|
||||
// 计算库龄
|
||||
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) {
|
||||
// 审核开启时,过滤掉“审核失败”的数据
|
||||
if (needAudit)
|
||||
{
|
||||
list = list.stream()
|
||||
.filter(info ->
|
||||
// ① 未审核过(approverId 为空)或
|
||||
info.getApproverId() == null ||
|
||||
// ② 审核通过
|
||||
"1".equals(info.getAuditResult())
|
||||
info.getApproverId() == null
|
||||
|| "1".equals(info.getAuditResult())
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
@@ -183,6 +168,13 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
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
|
||||
public RkInfo selectHeaderByBillNo(String billNo) {
|
||||
if (StringUtils.isBlank(billNo)) {
|
||||
@@ -213,26 +205,62 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
String pcode = rkInfo.getPcode();
|
||||
|
||||
// 只有当小仓 + 库位都有的时候才做这层校验
|
||||
if (StringUtils.isNotBlank(warehouseCode) && StringUtils.isNotBlank(pcode)) {
|
||||
|
||||
// 临时组装一个 PcRkInfoBatchDTO,专门给 validateWarehouseAndPcode 用
|
||||
PcRkInfoBatchDTO tmpDto = new PcRkInfoBatchDTO();
|
||||
tmpDto.setWarehouseCode(warehouseCode);
|
||||
|
||||
List<PcRkInfoItemDTO> rkList = new ArrayList<>();
|
||||
PcRkInfoItemDTO item = new PcRkInfoItemDTO();
|
||||
item.setPcode(pcode);
|
||||
rkList.add(item);
|
||||
|
||||
tmpDto.setRkList(rkList);
|
||||
|
||||
validateWarehouseAndPcode(tmpDto);
|
||||
}
|
||||
// if (StringUtils.isNotBlank(warehouseCode) && StringUtils.isNotBlank(pcode)) {
|
||||
//
|
||||
// // 临时组装一个 PcRkInfoBatchDTO,专门给 validateWarehouseAndPcode 用
|
||||
// PcRkInfoBatchDTO tmpDto = new PcRkInfoBatchDTO();
|
||||
// tmpDto.setWarehouseCode(warehouseCode);
|
||||
//
|
||||
// List<PcRkInfoItemDTO> rkList = new ArrayList<>();
|
||||
// PcRkInfoItemDTO item = new PcRkInfoItemDTO();
|
||||
// item.setPcode(pcode);
|
||||
// rkList.add(item);
|
||||
//
|
||||
// tmpDto.setRkList(rkList);
|
||||
//
|
||||
// validateWarehouseAndPcode(tmpDto);
|
||||
// }
|
||||
|
||||
// ====== 校验通过再更新 ======
|
||||
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();
|
||||
Date now = DateUtils.getNowDate();
|
||||
|
||||
// 🚩 0. 校验库位是否属于当前小仓
|
||||
validateWarehouseAndPcode(dto);
|
||||
// ✅ 0. 只有前端传了库位编码,才做“库位属于当前小仓”的校验(否则不传库位会被拦截)
|
||||
/*暂时去掉校验*/
|
||||
// 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()
|
||||
.filter(item -> item.getGysJhId() != null && item.getRealQty() != null)
|
||||
.collect(Collectors.toMap(
|
||||
PcRkInfoItemDTO::getGysJhId,
|
||||
PcRkInfoItemDTO::getRealQty,
|
||||
(a, b) -> b
|
||||
(a, b) -> a.add(b)
|
||||
));
|
||||
|
||||
// ✅ 2-4. 供应计划扣减&状态更新
|
||||
// ✅ 2-4. 供应计划扣减&状态更新(保持你原逻辑)
|
||||
if (!realQtyMap.isEmpty()) {
|
||||
List<GysJh> jhList = gysJhMapper.selectByIds(new ArrayList<>(realQtyMap.keySet()));
|
||||
Set<Long> idsToUpdateStatus = new HashSet<>();
|
||||
|
||||
for (GysJh jh : jhList) {
|
||||
Long jhId = jh.getId();
|
||||
BigDecimal planQty =
|
||||
jh.getJhQty() == null ? BigDecimal.ZERO : jh.getJhQty();
|
||||
BigDecimal planQty = jh.getJhQty() == null ? BigDecimal.ZERO : jh.getJhQty();
|
||||
BigDecimal realQty = realQtyMap.get(jhId);
|
||||
if (realQty == null) {
|
||||
continue;
|
||||
@@ -395,13 +427,11 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
boolean isEqual = realQty.compareTo(planQty) == 0;
|
||||
|
||||
if (!isEqual) {
|
||||
// 部分入库:扣减计划数量
|
||||
gysJhMapper.decreaseJhQtyById(jhId, realQty);
|
||||
if (!needAudit) {
|
||||
gysJhMapper.updateStatusById(jhId, "2"); // 2 = 部分入库
|
||||
}
|
||||
} else {
|
||||
// 全部入库:状态=1
|
||||
if (!needAudit) {
|
||||
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) {
|
||||
RkInfo rk = new RkInfo();
|
||||
// 物料、项目、供应商、xj(县局)、数量等等从 item 拷贝
|
||||
BeanUtils.copyProperties(item, rk);
|
||||
|
||||
rk.setBillNo(billNo);
|
||||
rk.setRkType(dto.getRkType());
|
||||
rk.setWlType(dto.getWlType());
|
||||
rk.setLihuoY(dto.getLihuoY());
|
||||
|
||||
// 🚩 所属小仓:页面选的小仓编码
|
||||
rk.setCangku(dto.getWarehouseCode());
|
||||
|
||||
// 🚩 入库时间:页面传,若为空则使用当前时间
|
||||
rk.setRkTime(dto.getRkTime() != null ? dto.getRkTime() : DateUtils.getNowDate());
|
||||
|
||||
// 库位 encodedId
|
||||
String encodedId = pcdeDetailMapper.selectEncodedIdByPcode(item.getPcode());
|
||||
rk.setPcodeId(encodedId);
|
||||
|
||||
rk.setCreateBy(userId);
|
||||
rk.setCreateTime(now);
|
||||
rk.setIsDelete("0");
|
||||
@@ -442,6 +463,45 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
rk.setFycde1(item.getFycde1());
|
||||
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) {
|
||||
rk.setStatus("0"); // 待审核
|
||||
rk.setIsChuku("2"); // 待入库(审核中)
|
||||
@@ -449,6 +509,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
rk.setStatus("1"); // 审核通过
|
||||
rk.setIsChuku("0"); // 已入库
|
||||
}
|
||||
|
||||
rkInfos.add(rk);
|
||||
}
|
||||
|
||||
@@ -465,15 +526,18 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
AuditSignature photo = new AuditSignature();
|
||||
photo.setRkId(rk.getId());
|
||||
photo.setBillNo(billNo);
|
||||
photo.setBillType("0"); // 入库
|
||||
photo.setAuditResult("2"); // 待审核
|
||||
photo.setBillType("0");
|
||||
photo.setAuditResult("2");
|
||||
photo.setSignerId(userId);
|
||||
photo.setSignerRole("2"); // 现场照片
|
||||
photo.setImageType("1"); // photo
|
||||
photo.setSignerRole("2");
|
||||
photo.setImageType("1");
|
||||
photo.setSignUrl(item.getPhotoUrl());
|
||||
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.setIsCurrent("1");
|
||||
photo.setIsDelete("0");
|
||||
@@ -493,15 +557,15 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
|
||||
AuditSignature mainSign = new AuditSignature();
|
||||
mainSign.setBillNo(billNo);
|
||||
mainSign.setBillType("0"); // 入库
|
||||
mainSign.setBillType("0");
|
||||
mainSign.setSignerId(userId);
|
||||
mainSign.setSignerRole("0"); // 发起人
|
||||
mainSign.setSignerRole("0");
|
||||
mainSign.setApproverId(dto.getApproverId());
|
||||
mainSign.setSignUrl(dto.getSignatureUrl());
|
||||
mainSign.setImageType("0"); // sign
|
||||
mainSign.setImageType("0");
|
||||
mainSign.setSignTime(now);
|
||||
mainSign.setIsCurrent("1");
|
||||
mainSign.setAuditResult("2"); // 待审核
|
||||
mainSign.setAuditResult("2");
|
||||
mainSign.setIsDelete("0");
|
||||
mainSign.setCreateBy(userId);
|
||||
mainSign.setCreateTime(now);
|
||||
@@ -616,8 +680,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public int batchInsertApp(RkInfoBatchDTO dto) {
|
||||
|
||||
// ✅ 0. 小仓 + 库位一致性校验(统一用 warehouseCode)
|
||||
validateWarehouseAndPcode(dto);
|
||||
// // ✅ 0. 小仓 + 库位一致性校验(统一用 warehouseCode)
|
||||
// validateWarehouseAndPcode(dto);
|
||||
|
||||
List<RkInfo> saveList = new ArrayList<>();
|
||||
String userId = SecurityUtils.getUserId().toString();
|
||||
@@ -871,42 +935,133 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
boolean needAudit = "1".equals(configService.selectConfigByKey("rk.audit.enabled"));
|
||||
|
||||
// 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()) {
|
||||
RkInfo update = new RkInfo();
|
||||
update.setId(item.getId());
|
||||
update.setBillNoCk(billNo);
|
||||
update.setIsDelivery(dto.getIsDelivery());
|
||||
update.setCkType(dto.getCkType());
|
||||
update.setTeamCode(dto.getTeamCode());
|
||||
update.setLyTime(now);
|
||||
update.setCkLihuoY(dto.getCkLihuoY());
|
||||
update.setCkRemark(item.getCkRemark());
|
||||
update.setXmNoCk(dto.getXmNoCk());
|
||||
update.setXmMsCk(dto.getXmMsCk());
|
||||
update.setUpdateBy(userId);
|
||||
update.setUpdateTime(now);
|
||||
|
||||
if ("JLCK".equals(dto.getCkType())) {
|
||||
update.setIsBorrowed("1");
|
||||
update.setBorrowTime(dto.getBorrowTime());
|
||||
update.setReturnTime(dto.getReturnTime());
|
||||
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());
|
||||
}
|
||||
|
||||
if (needAudit) {
|
||||
update.setStatus("3"); // 出库待审核
|
||||
update.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "2");
|
||||
// 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 {
|
||||
update.setStatus("1"); // 审核通过
|
||||
update.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "1");
|
||||
}
|
||||
// ✅ 全部出库:不扣减 real_qty,直接改状态
|
||||
RkInfo update = new RkInfo();
|
||||
update.setId(item.getId());
|
||||
update.setBillNoCk(billNo);
|
||||
update.setIsDelivery(dto.getIsDelivery());
|
||||
update.setCkType(dto.getCkType());
|
||||
update.setTeamCode(dto.getTeamCode());
|
||||
update.setLyTime(now);
|
||||
update.setCkLihuoY(dto.getCkLihuoY());
|
||||
update.setCkRemark(item.getCkRemark());
|
||||
update.setXmNoCk(dto.getXmNoCk());
|
||||
update.setXmMsCk(dto.getXmMsCk());
|
||||
update.setUpdateBy(userId);
|
||||
update.setUpdateTime(now);
|
||||
|
||||
rkInfoMapper.updateById(update);
|
||||
if ("JLCK".equals(dto.getCkType())) {
|
||||
update.setIsBorrowed("1");
|
||||
update.setBorrowTime(dto.getBorrowTime());
|
||||
update.setReturnTime(dto.getReturnTime());
|
||||
}
|
||||
|
||||
if (needAudit) {
|
||||
update.setStatus("3"); // 出库待审核
|
||||
update.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "2");
|
||||
} else {
|
||||
update.setStatus("1"); // 审核通过
|
||||
update.setIsChuku("JLCK".equals(dto.getCkType()) ? "3" : "1");
|
||||
}
|
||||
|
||||
rkInfoMapper.updateById(update);
|
||||
|
||||
// 全出库:照片绑定原记录
|
||||
outRkIdMap.put(item.getId(), item.getId());
|
||||
}
|
||||
}
|
||||
|
||||
// Step 4: 如果启用审核,写入签字记录
|
||||
// Step 4: 如果启用审核,写入签字记录(部分出库:照片绑定新出库记录ID)
|
||||
if (needAudit) {
|
||||
List<AuditSignature> recordList = new ArrayList<>();
|
||||
|
||||
@@ -934,6 +1089,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
for (StockOutItemDTO item : dto.getCkList()) {
|
||||
if (StringUtils.isBlank(item.getPhotoUrl())) continue;
|
||||
|
||||
Long rkIdForPhoto = outRkIdMap.getOrDefault(item.getId(), item.getId());
|
||||
|
||||
AuditSignature photo = new AuditSignature();
|
||||
photo.setBillNo(billNo);
|
||||
photo.setBillType("1");
|
||||
@@ -948,9 +1105,12 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
photo.setIsDelete("0");
|
||||
photo.setCreateBy(userId);
|
||||
photo.setCreateTime(now);
|
||||
photo.setRkId(item.getId());
|
||||
|
||||
// ✅ 关键:部分出库绑定“新出库记录”的 rk_id
|
||||
photo.setRkId(rkIdForPhoto);
|
||||
photo.setPcode(item.getPcode());
|
||||
photo.setTrayCode(item.getTrayCode());
|
||||
|
||||
recordList.add(photo);
|
||||
}
|
||||
|
||||
@@ -962,6 +1122,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
return dto.getCkList().size();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class) // 开启事务,异常时回滚
|
||||
public void matchWithStatus(QueryDTO dto) {
|
||||
@@ -1110,8 +1271,6 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
@Override
|
||||
public int refundMaterial(RefundRequestDTO dto) {
|
||||
Long originalId = dto.getOriginalId();
|
||||
String newPcode = dto.getPcode();
|
||||
|
||||
// 1. 查原出库记录
|
||||
RkInfo original = rkInfoMapper.selectRkInfoById(originalId);
|
||||
if (original == null || "1".equals(original.getIsDelete())) {
|
||||
@@ -1123,9 +1282,11 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
BeanUtils.copyProperties(original, newEntry);
|
||||
newEntry.setId(null);
|
||||
newEntry.setIsChuku("0");
|
||||
newEntry.setPcode(newPcode);
|
||||
newEntry.setPcode(dto.getPcode());
|
||||
newEntry.setCangku(dto.getWarehouseCode());
|
||||
newEntry.setRkType(dto.getRkType());
|
||||
newEntry.setRkTime(DateUtils.getNowDate());
|
||||
newEntry.setBorrowTime(original.getBorrowTime());
|
||||
newEntry.setBillNo(BillNoUtil.generateTodayBillNo("RK", rkInfoMapper));
|
||||
newEntry.setCreateBy(SecurityUtils.getUserId().toString());
|
||||
newEntry.setCreateTime(DateUtils.getNowDate());
|
||||
@@ -1143,6 +1304,8 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
update.setReturnTime(DateUtils.getNowDate());
|
||||
update.setUpdateBy(getUsername());
|
||||
update.setUpdateTime(DateUtils.getNowDate());
|
||||
update.setPcode(dto.getPcode());
|
||||
update.setCangku(dto.getWarehouseCode());
|
||||
rkInfoMapper.updateById(update);
|
||||
|
||||
return rows;
|
||||
@@ -1204,21 +1367,16 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
return rkInfoMapper.listRkInfoByPcode(pcode);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public List<RkInfo> selectAllRkInfo(RkInfo query) {
|
||||
return rkInfoMapper.selectAllRkInfo(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long selectStatistics(RkInfo query) {
|
||||
return rkInfoMapper.selectStatistics(query);
|
||||
public List<RkInfo> selectRkInfoPageList(RkInfo query) {
|
||||
return rkInfoMapper.selectRkInfoPageList(query);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Long selectPcde(RkInfo query) {
|
||||
return rkInfoMapper.selectPcde(query);
|
||||
}
|
||||
@Override
|
||||
public int updateBillInfo(RkInfo query) {
|
||||
return rkInfoMapper.updateBillInfo(query);
|
||||
@@ -1256,7 +1414,7 @@ public class RkInfoServiceImpl implements IRkInfoService
|
||||
e.setBillNo(dto.getBillNo());
|
||||
e.setRkType(dto.getRkType());
|
||||
e.setWlType(dto.getWlType());
|
||||
e.setWarehouseCode(dto.getWarehouseCode());
|
||||
e.setCangku(dto.getWarehouseCode());
|
||||
e.setLihuoY(dto.getLihuoY());
|
||||
e.setRkTime(rkTime);
|
||||
|
||||
|
||||
@@ -5,10 +5,13 @@ import com.zg.common.exception.ServiceException;
|
||||
import com.zg.common.utils.DateUtils;
|
||||
import com.zg.common.utils.StringUtils;
|
||||
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.mapper.GysJhMapper;
|
||||
import com.zg.project.wisdom.mapper.RkInfoMapper;
|
||||
import com.zg.project.wisdom.mapper.RkStatisticsMapper;
|
||||
import com.zg.project.wisdom.service.RkStatisticsService;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -23,9 +26,12 @@ import java.util.*;
|
||||
@Service
|
||||
public class RkStatisticsServiceImpl implements RkStatisticsService {
|
||||
|
||||
@Resource
|
||||
@Autowired
|
||||
private RkStatisticsMapper rkStatisticsMapper;
|
||||
|
||||
@Autowired
|
||||
private RkInfoMapper rkInfoMapper;
|
||||
|
||||
|
||||
@Override
|
||||
public List<Map<String, Object>> getAgeStatsAsList() {
|
||||
@@ -426,4 +432,24 @@ public class RkStatisticsServiceImpl implements RkStatisticsService {
|
||||
}
|
||||
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.util.Date;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.ThreadLocalRandom;
|
||||
|
||||
/**
|
||||
* 单据号生成工具类
|
||||
*
|
||||
* 目标:
|
||||
* 1) 每次业务操作都生成全新单据号(不依赖历史,不查DB)
|
||||
* 2) 单号短、可读
|
||||
* 3) 避免串单:不同出库操作绝不复用同一个 billNo
|
||||
*
|
||||
* 推荐格式:
|
||||
* CK24011315384227
|
||||
* 前缀 + yyMMdd + HHmmss + 2位随机数
|
||||
*/
|
||||
public class BillNoUtil {
|
||||
|
||||
// 内存缓存:key = prefix + yyyyMMdd
|
||||
private static final Map<String, AtomicInteger> DAILY_SEQUENCE_MAP = new ConcurrentHashMap<>();
|
||||
private static final String DEFAULT_PREFIX = "RK";
|
||||
|
||||
/**
|
||||
* 生成当天单据号(格式:RK20251222_1)
|
||||
* 生成单据号(短号,不查数据库)
|
||||
* 格式:PREFIX + yyMMdd + HHmmss + 2位随机数
|
||||
* 示例:CK24011315384227
|
||||
*
|
||||
* @param prefix 单据前缀:RK/CK/...
|
||||
* @param rkInfoMapper 兼容旧签名(不再使用,可传 null)
|
||||
*/
|
||||
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 可用
|
||||
final String today = new SimpleDateFormat("yyyyMMdd").format(new Date());
|
||||
final String key = finalPrefix + today;
|
||||
final String likePrefix = finalPrefix + today + "_";
|
||||
// 时间到秒:yyMMddHHmmss(12位)
|
||||
String time = new SimpleDateFormat("yyMMddHHmmss").format(new Date());
|
||||
|
||||
// 如果当天还没初始化,从数据库取最大号
|
||||
AtomicInteger counter = DAILY_SEQUENCE_MAP.computeIfAbsent(key, k -> {
|
||||
// 2位随机数:10~99(避免同一秒内多次点击撞号)
|
||||
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);
|
||||
});
|
||||
/**
|
||||
* 需要更短的版本(可选)
|
||||
* 格式:PREFIX + yyMMdd + 4位随机数
|
||||
* 示例:CK2401134837
|
||||
*
|
||||
* 注意:比带秒的版本更短,但理论碰撞概率略高(一般够用)
|
||||
*/
|
||||
public static synchronized String generateShortBillNo(String prefix) {
|
||||
final String p = (prefix == null || prefix.trim().isEmpty())
|
||||
? DEFAULT_PREFIX
|
||||
: prefix.trim().toUpperCase();
|
||||
|
||||
int seq = counter.getAndIncrement();
|
||||
return finalPrefix + today + "_" + seq;
|
||||
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:
|
||||
# 主库数据源
|
||||
master:
|
||||
# url: jdbc:mysql://101.132.133.142: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://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.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
|
||||
username: root
|
||||
password: shzg
|
||||
|
||||
@@ -170,51 +170,3 @@ mock:
|
||||
#配送系统中调用大模型进行图片识别
|
||||
qwen-ocr:
|
||||
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/#
|
||||
@@ -31,12 +31,28 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="isDelete != null and isDelete != ''"> and is_delete = #{isDelete}</if>
|
||||
</where>
|
||||
</select>
|
||||
|
||||
|
||||
<select id="selectConstructionTeamById" parameterType="Long" resultMap="ConstructionTeamResult">
|
||||
<include refid="selectConstructionTeamVo"/>
|
||||
where id = #{id}
|
||||
</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 into construction_team
|
||||
<trim prefix="(" suffix=")" suffixOverrides=",">
|
||||
@@ -59,6 +75,12 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</trim>
|
||||
</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 construction_team
|
||||
<trim prefix="SET" suffixOverrides=",">
|
||||
|
||||
@@ -182,6 +182,15 @@
|
||||
LIMIT 1
|
||||
</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"
|
||||
parameterType="PcdeDetail"
|
||||
|
||||
@@ -59,11 +59,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<if test="status != null and status != ''">
|
||||
and status = #{status}
|
||||
</if>
|
||||
and (status is null or trim(status) != '1')
|
||||
|
||||
<!-- and (status is null or trim(status) != '1') -->
|
||||
<if test="isDelete != null and isDelete != ''">
|
||||
and is_delete = #{isDelete}
|
||||
</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>
|
||||
</select>
|
||||
|
||||
@@ -75,7 +81,6 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
<select id="getBySapNo" parameterType="java.lang.String" resultMap="GysJhResult">
|
||||
<include refid="selectGysJhVo"/>
|
||||
WHERE sap_no = #{sapNo}
|
||||
AND status != '1'
|
||||
</select>
|
||||
|
||||
<!-- 【已注释】唯一性校验查询:基于SAP订单号、项目号、物料号判断是否已存在 -->
|
||||
@@ -234,5 +239,17 @@ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
|
||||
</foreach>
|
||||
</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>
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user