新增原料入场记录功能,包含免密接口和数据同步,更新相关控制器、实体和服务,支持条码/批次号生成及管理,优化用户体验和系统实时数据处理能力。

This commit is contained in:
geht
2026-05-09 15:55:11 +08:00
parent 64e978a618
commit 16bb22a113
38 changed files with 2398 additions and 10 deletions

View File

@@ -0,0 +1,132 @@
-- 从截图识别生成密炼物料导入 SQL目标表mes_mixer_material
-- 说明
-- 1) feed_manage_status=1(投管), use_status=1(使用), shelf_life_days=365
-- 2) 物料大类/小类按分类字典映射到 sys_category.id
-- 物料大类名称原辅材料类型编码 code = XSLMES_MATERIAL_RAW_AUXsys_category.code
-- 物料小类名称炭黑 pid 指向大类若已维护父子关系
-- 3) tenant_id / sys_org_code 未知先置空
-- 4) material_name / material_desc / alias_name 中如包含 TODO_*请在执行前按业务名称修正
-- 5) 为避免重复先按 material_code 删除后再插入
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- 大类优先按类型编码匹配否则按名称原辅材料
SET @major_category_id := (
SELECT sc.id
FROM sys_category sc
WHERE sc.code = 'XSLMES_MATERIAL_RAW_AUX' OR sc.name = '原辅材料'
ORDER BY
(CASE WHEN sc.code = 'XSLMES_MATERIAL_RAW_AUX' THEN 0 WHEN sc.name = '原辅材料' THEN 1 ELSE 2 END),
sc.create_time DESC
LIMIT 1
);
-- 小类名称炭黑优先挂在大类下
SET @minor_category_id := (
SELECT sc.id
FROM sys_category sc
WHERE sc.name = '炭黑'
AND (
@major_category_id IS NULL
OR sc.pid = @major_category_id
OR sc.pid IS NULL
OR sc.pid = '0'
)
ORDER BY (CASE WHEN sc.pid = @major_category_id THEN 0 ELSE 1 END), sc.create_time DESC
LIMIT 1
);
DELETE FROM mes_mixer_material
WHERE material_code IN (
'110110001','110110002','110110003','110110004','110110005','110110006','110110007','110110008',
'110110009','110110010','110110011','110110012','110110013','110110014','110110015','110110016',
'110110017','110110018','110110019','110110020','110110021','110110022','110110023','110110024',
'110110025','110110026','110110027','110110028'
);
INSERT INTO mes_mixer_material (
id,
material_code,
material_name,
erp_code,
major_category_id,
minor_category_id,
material_desc,
alias_name,
feed_manage_status,
use_status,
specific_gravity,
shelf_life_days,
min_bake_minutes,
total_safety_stock_kg,
qualified_safety_stock_kg,
remark,
tenant_id,
sys_org_code,
create_by,
create_time,
del_flag
)
SELECT
REPLACE(UUID(), '-', '') AS id,
t.material_code,
t.material_name,
t.erp_code,
@major_category_id AS major_category_id,
@minor_category_id AS minor_category_id,
t.material_desc,
t.alias_name,
1 AS feed_manage_status,
1 AS use_status,
t.specific_gravity,
365 AS shelf_life_days,
t.min_bake_minutes,
NULL AS total_safety_stock_kg,
NULL AS qualified_safety_stock_kg,
'图片识别导入' AS remark,
NULL AS tenant_id,
NULL AS sys_org_code,
'image_import' AS create_by,
NOW() AS create_time,
0 AS del_flag
FROM (
-- material_code(9位), material_name, erp_code, material_desc, alias_name, specific_gravity, min_bake_minutes
SELECT '110110001' AS material_code, '炭黑-N220' AS material_name, '10201' AS erp_code, '炭黑-N220' AS material_desc, '炭黑-N220' AS alias_name, 1.82 AS specific_gravity, NULL AS min_bake_minutes
UNION ALL SELECT '110110002', '炭黑-N330', '10203', '炭黑-N330', '炭黑-N330', 1.82, NULL
UNION ALL SELECT '110110003', '炭黑-N660', '10205', '炭黑-N660', '炭黑-N660', 1.82, NULL
UNION ALL SELECT '110110004', '裂解炭黑', '10206', '裂解炭黑', '裂解炭黑', 1.95, NULL
UNION ALL SELECT '110110005', '陶土1', '10254', '填料-陶土1', '填料-陶土1', 2.60, NULL
UNION ALL SELECT '110110006', '碳酸钙', '10253', '填料-碳酸钙', '填料-碳酸钙', 2.70, NULL
UNION ALL SELECT '110110007', '硫酸钡', '10252', '填料-硫酸钡', '填料-硫酸钡', 4.20, NULL
UNION ALL SELECT '110110008', '二氧化钛中阳', '10251', '二氧化钛中阳', '二氧化钛中阳', 2.20, NULL
UNION ALL SELECT '110110009', '炭黑-N234', '10202', '炭黑-N234', '炭黑-N234', 1.85, NULL
UNION ALL SELECT '110110010', '炭黑 N339', '10204', '炭黑 N339', '炭黑 N339', 1.85, NULL
UNION ALL SELECT '110110011', '云母粉', '10255', '云母粉', '云母粉', 2.00, NULL
UNION ALL SELECT '110110012', '硬脂酸2', '10543', '硬脂酸2', '硬脂酸2', 0.85, 0
UNION ALL SELECT '110110013', 'FI-N339', '10204', 'FI-N339', 'FI-N339', 1.85, 4
UNION ALL SELECT '110110014', 'IL N330', '10203', 'IL N330', 'IL N330', 1.85, 4
UNION ALL SELECT '110110015', '卡博特N234', '11006', '卡博特N234', '卡博特N234', 1.10, 0
UNION ALL SELECT '110110016', '卡博特234', '11006', '卡博特234', '卡博特234', 1.80, 8
UNION ALL SELECT '110110017', '头条B-N220', '10201', '头条B-N220', '头条B-N220', 1.82, 0
UNION ALL SELECT '110110018', '集采B-N330', '10203', '集采B-N330', '集采B-N330', 1.82, 24
UNION ALL SELECT '110110019', '集采B-N660', '10205', '集采B-N660', '集采B-N660', 1.82, 24
UNION ALL SELECT '110110020', '集采B-裂解炭黑', '10206', '集采B-裂解炭黑', '集采B-裂解炭黑', 1.82, 24
UNION ALL SELECT '110110021', '集采B-碳酸钙', '10253', '集采B-碳酸钙', '集采B-碳酸钙', 1.82, 24
UNION ALL SELECT '110110022', '集采B-陶土', '10254', '集采B-陶土', '集采B-陶土', 1.82, 24
UNION ALL SELECT '110110023', '集采B-N234', '10204', '集采B-N234', '集采B-N234', 1.82, 24
UNION ALL SELECT '110110024', '集采B-N339', '10204', '集采B-N339', '集采B-N339', 1.82, 24
UNION ALL SELECT '110110025', '氧化锌2', '10256', '氧化锌2', '氧化锌2', 5.55, 0
UNION ALL SELECT '110110026', '炭黑-N550', '10209', '炭黑-N550', '炭黑-N550', 1.82, 0
UNION ALL SELECT '110110027', 'AH', '10606', 'AH', 'AH', 1.18, 0
UNION ALL SELECT '110110028', '旺格-N220', '10201', '旺格-N220', '旺格-N220', 1.82, 0
) t;
SET FOREIGN_KEY_CHECKS = 1;
-- 执行后可核对
-- SELECT @major_category_id AS major_category_id, @minor_category_id AS minor_category_id;
-- SELECT material_code, material_name, erp_code, major_category_id, minor_category_id, specific_gravity, min_bake_minutes
-- FROM mes_mixer_material
-- WHERE material_code BETWEEN '110110001' AND '110110028'
-- ORDER BY material_code;

View File

@@ -22,4 +22,9 @@ public class FillRuleConstant {
*/
public static final String CATEGORY = "category_code_rule";
/**
* MES 原料入场记录 条码/批次号
*/
public static final String MES_RAW_MATERIAL_BARCODE = "mes_raw_material_barcode_rule";
}

View File

@@ -203,6 +203,8 @@ public class ShiroConfig {
filterChainDefinitionMap.put("/xslmes/mesXslSupplier/anon/**", "anon");
// MES磅单管理免密接口供桌面端调用
filterChainDefinitionMap.put("/xslmes/mesXslWeightRecord/anon/**", "anon");
// MES原料入场记录免密接口供桌面端调用
filterChainDefinitionMap.put("/xslmes/mesXslRawMaterialEntry/anon/**", "anon");
// MES密炼物料管理免密接口供桌面端调用
filterChainDefinitionMap.put("/mes/material/mixerMaterial/anon/**", "anon");
// 系统分类字典免密接口(供桌面端调用)

View File

@@ -14,10 +14,12 @@ import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.common.util.oConvertUtils;
import org.jeecg.modules.xslmes.constant.MesXslCustomerBizStatus;
import org.jeecg.modules.xslmes.entity.MesXslCustomer;
import org.jeecg.modules.xslmes.entity.MesXslRawMaterialEntry;
import org.jeecg.modules.xslmes.entity.MesXslSupplier;
import org.jeecg.modules.xslmes.entity.MesXslVehicle;
import org.jeecg.modules.xslmes.entity.MesXslWeightRecord;
import org.jeecg.modules.xslmes.service.IMesXslCustomerService;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialEntryService;
import org.jeecg.modules.xslmes.service.IMesXslSupplierService;
import org.jeecg.modules.xslmes.service.IMesXslVehicleService;
import org.jeecg.modules.xslmes.service.IMesXslWeightRecordService;
@@ -26,6 +28,7 @@ import org.springframework.web.bind.annotation.*;
import java.util.Arrays;
import java.util.Objects;
import org.apache.commons.lang3.StringUtils;
/**
* 桌面端免密接口 — 统一入口
@@ -45,6 +48,7 @@ public class MesXslDesktopAnonController {
private final IMesXslCustomerService customerService;
private final IMesXslSupplierService supplierService;
private final IMesXslWeightRecordService weightRecordService;
private final IMesXslRawMaterialEntryService rawMaterialEntryService;
private final MesXslStompNotifyService stompNotify;
// ═══════════════════════════ 车辆管理 ═══════════════════════════
@@ -422,6 +426,82 @@ public class MesXslDesktopAnonController {
return Result.OK("批量删除成功!");
}
// ═══════════════════════════ 原料入场记录 ═══════════════════════════
@Operation(summary = "原料入场记录-免密分页列表查询")
@GetMapping("/xslmes/mesXslRawMaterialEntry/anon/list")
public Result<IPage<MesXslRawMaterialEntry>> rawMaterialEntryAnonList(
MesXslRawMaterialEntry entity,
@RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
@RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
HttpServletRequest req) {
QueryWrapper<MesXslRawMaterialEntry> qw = QueryGenerator.initQueryWrapper(entity, req.getParameterMap());
qw.orderByDesc("create_time");
IPage<MesXslRawMaterialEntry> page = rawMaterialEntryService.page(new Page<>(pageNo, pageSize), qw);
return Result.OK(page);
}
@Operation(summary = "原料入场记录-免密通过id查询")
@GetMapping("/xslmes/mesXslRawMaterialEntry/anon/queryById")
public Result<MesXslRawMaterialEntry> rawMaterialEntryAnonQueryById(@RequestParam(name = "id") String id) {
MesXslRawMaterialEntry entity = rawMaterialEntryService.getById(id);
return entity != null ? Result.OK(entity) : Result.error("未找到对应数据");
}
@Operation(summary = "原料入场记录-免密生成条码/批次号")
@GetMapping("/xslmes/mesXslRawMaterialEntry/anon/generateBarcode")
public Result<String> rawMaterialEntryAnonGenerateBarcode(
@RequestParam(name = "materialCode", defaultValue = "") String materialCode) {
return Result.OK(rawMaterialEntryService.generateBarcode(materialCode));
}
@Operation(summary = "原料入场记录-免密添加")
@PostMapping("/xslmes/mesXslRawMaterialEntry/anon/add")
public Result<String> rawMaterialEntryAnonAdd(@RequestBody MesXslRawMaterialEntry entity) {
// 条码/批次号为空时服务端自动生成
if (StringUtils.isBlank(entity.getBarcode())) {
String code = rawMaterialEntryService.generateBarcode(
StringUtils.defaultString(entity.getMaterialCode(), ""));
entity.setBarcode(code);
}
if (StringUtils.isBlank(entity.getBatchNo())) {
entity.setBatchNo(entity.getBarcode());
}
rawMaterialEntryService.save(entity);
stompNotify.publishRawMaterialEntryChanged("add", entity.getId());
return Result.OK("添加成功!");
}
@Operation(summary = "原料入场记录-免密编辑")
@RequestMapping(value = "/xslmes/mesXslRawMaterialEntry/anon/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> rawMaterialEntryAnonEdit(@RequestBody MesXslRawMaterialEntry entity) {
if (oConvertUtils.isEmpty(entity.getId())) {
return Result.error("主键不能为空");
}
boolean ok = rawMaterialEntryService.updateById(entity);
if (!ok) {
return Result.error("数据已被他人修改,请刷新后重试");
}
stompNotify.publishRawMaterialEntryChanged("edit", entity.getId());
return Result.OK("编辑成功!");
}
@Operation(summary = "原料入场记录-免密删除")
@DeleteMapping("/xslmes/mesXslRawMaterialEntry/anon/delete")
public Result<String> rawMaterialEntryAnonDelete(@RequestParam(name = "id") String id) {
rawMaterialEntryService.removeById(id);
stompNotify.publishRawMaterialEntryChanged("delete", id);
return Result.OK("删除成功!");
}
@Operation(summary = "原料入场记录-免密批量删除")
@DeleteMapping("/xslmes/mesXslRawMaterialEntry/anon/deleteBatch")
public Result<String> rawMaterialEntryAnonDeleteBatch(@RequestParam(name = "ids") String ids) {
rawMaterialEntryService.removeByIds(Arrays.asList(ids.split(",")));
stompNotify.publishRawMaterialEntryChanged("batchDelete", ids);
return Result.OK("批量删除成功!");
}
// ─────────────────────────── 车辆私有辅助 ────────────────────────────
private void applyWeightBillType(MesXslWeightRecord record) {

View File

@@ -7,6 +7,7 @@ import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.query.QueryGenerator;
import org.jeecg.modules.xslmes.entity.MesXslRawMaterialEntry;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialEntryService;
import org.jeecg.modules.xslmes.service.MesXslStompNotifyService;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
@@ -36,6 +37,8 @@ public class MesXslRawMaterialEntryController extends JeecgController<MesXslRawM
@Autowired
private IMesXslRawMaterialEntryService mesXslRawMaterialEntryService;
@Autowired
private MesXslStompNotifyService stompNotify;
@Operation(summary = "原料入场记录-分页列表查询")
@GetMapping(value = "/list")
@@ -55,6 +58,7 @@ public class MesXslRawMaterialEntryController extends JeecgController<MesXslRawM
@PostMapping(value = "/add")
public Result<String> add(@RequestBody MesXslRawMaterialEntry mesXslRawMaterialEntry) {
mesXslRawMaterialEntryService.save(mesXslRawMaterialEntry);
stompNotify.publishRawMaterialEntryChanged("add", mesXslRawMaterialEntry.getId());
return Result.OK("添加成功!");
}
@@ -64,6 +68,7 @@ public class MesXslRawMaterialEntryController extends JeecgController<MesXslRawM
@RequestMapping(value = "/edit", method = {RequestMethod.PUT, RequestMethod.POST})
public Result<String> edit(@RequestBody MesXslRawMaterialEntry mesXslRawMaterialEntry) {
mesXslRawMaterialEntryService.updateById(mesXslRawMaterialEntry);
stompNotify.publishRawMaterialEntryChanged("edit", mesXslRawMaterialEntry.getId());
return Result.OK("编辑成功!");
}
@@ -73,6 +78,7 @@ public class MesXslRawMaterialEntryController extends JeecgController<MesXslRawM
@DeleteMapping(value = "/delete")
public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
mesXslRawMaterialEntryService.removeById(id);
stompNotify.publishRawMaterialEntryChanged("delete", id);
return Result.OK("删除成功!");
}
@@ -82,6 +88,7 @@ public class MesXslRawMaterialEntryController extends JeecgController<MesXslRawM
@DeleteMapping(value = "/deleteBatch")
public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
this.mesXslRawMaterialEntryService.removeByIds(Arrays.asList(ids.split(",")));
stompNotify.publishRawMaterialEntryChanged("batchDelete", ids);
return Result.OK("批量删除成功!");
}

View File

@@ -57,6 +57,10 @@ public class MesXslRawMaterialEntry implements Serializable {
@Schema(description = "物料ID")
private String materialId;
@Excel(name = "物料编码", width = 20)
@Schema(description = "物料编码(用于生成条码/批次号)")
private String materialCode;
@Excel(name = "物料名称", width = 20)
@Schema(description = "物料名称")
private String materialName;

View File

@@ -0,0 +1,31 @@
package org.jeecg.modules.xslmes.rule;
import com.alibaba.fastjson.JSONObject;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.jeecg.common.handler.IFillRuleHandler;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialEntryService;
/**
* 填值规则:原料入场记录 条码/批次号生成
* 格式QH + 物料编码 + 日期(yyMMdd) + 当日序号(001起)
* rule_code: mes_raw_material_barcode_rule
*/
@Slf4j
public class RawMaterialBarcodeRule implements IFillRuleHandler {
@Override
public Object execute(JSONObject params, JSONObject formData) {
String materialCode = "";
if (formData != null && StringUtils.isNotBlank(formData.getString("materialCode"))) {
materialCode = formData.getString("materialCode").trim();
} else if (params != null && StringUtils.isNotBlank(params.getString("materialCode"))) {
materialCode = params.getString("materialCode").trim();
}
log.info("原料入场条码生成规则 materialCode={}", materialCode);
IMesXslRawMaterialEntryService service =
SpringContextUtils.getBean(IMesXslRawMaterialEntryService.class);
return service.generateBarcode(materialCode);
}
}

View File

@@ -10,4 +10,13 @@ import com.baomidou.mybatisplus.extension.service.IService;
* @Version: V1.0
*/
public interface IMesXslRawMaterialEntryService extends IService<MesXslRawMaterialEntry> {
/**
* 生成条码/批次号
* 格式QH + 物料编码 + 日期(yyMMdd) + 当日序号(001起)
*
* @param materialCode 物料编码
* @return 生成的条码字符串
*/
String generateBarcode(String materialCode);
}

View File

@@ -40,6 +40,11 @@ public class MesXslStompNotifyService {
publish("/topic/sync/mes-weight-records", "MES_WEIGHT_RECORD_CHANGED", "weightRecordId", weightRecordId, action);
}
/** 广播原料入场记录变更事件到 /topic/sync/mes-raw-material-entries */
public void publishRawMaterialEntryChanged(String action, String entryId) {
publish("/topic/sync/mes-raw-material-entries", "MES_RAW_MATERIAL_ENTRY_CHANGED", "entryId", entryId, action);
}
/** 广播密炼物料数据变更事件到 /topic/sync/mes-mixer-materials */
public void publishMixerMaterialChanged(String action, String mixerMaterialId) {
publish("/topic/sync/mes-mixer-materials", "MIXER_MATERIAL_CHANGED", "mixerMaterialId", mixerMaterialId, action);

View File

@@ -1,10 +1,14 @@
package org.jeecg.modules.xslmes.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.jeecg.modules.xslmes.entity.MesXslRawMaterialEntry;
import org.jeecg.modules.xslmes.mapper.MesXslRawMaterialEntryMapper;
import org.jeecg.modules.xslmes.service.IMesXslRawMaterialEntryService;
import org.springframework.stereotype.Service;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import java.text.SimpleDateFormat;
import java.util.Date;
/**
* @Description: 原料入场记录
@@ -13,5 +17,20 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
* @Version: V1.0
*/
@Service
public class MesXslRawMaterialEntryServiceImpl extends ServiceImpl<MesXslRawMaterialEntryMapper, MesXslRawMaterialEntry> implements IMesXslRawMaterialEntryService {
public class MesXslRawMaterialEntryServiceImpl
extends ServiceImpl<MesXslRawMaterialEntryMapper, MesXslRawMaterialEntry>
implements IMesXslRawMaterialEntryService {
@Override
public String generateBarcode(String materialCode) {
if (materialCode == null) materialCode = "";
String dateStr = new SimpleDateFormat("yyMMdd").format(new Date());
String prefix = "QH" + materialCode.trim() + dateStr;
LambdaQueryWrapper<MesXslRawMaterialEntry> qw = new LambdaQueryWrapper<>();
qw.likeRight(MesXslRawMaterialEntry::getBarcode, prefix);
long count = this.count(qw);
return prefix + String.format("%03d", count + 1);
}
}

View File

@@ -0,0 +1,30 @@
-- ============================================================
-- 1. 原料入场记录表补充 material_code
-- ============================================================
SET @col_exists := (
SELECT COUNT(*) FROM information_schema.COLUMNS
WHERE TABLE_SCHEMA = DATABASE()
AND TABLE_NAME = 'mes_xsl_raw_material_entry'
AND COLUMN_NAME = 'material_code'
);
SET @ddl := IF(@col_exists = 0,
'ALTER TABLE `mes_xsl_raw_material_entry` ADD COLUMN `material_code` varchar(100) DEFAULT NULL COMMENT ''物料编码'' AFTER `material_id`',
'SELECT 1'
);
PREPARE s FROM @ddl; EXECUTE s; DEALLOCATE PREPARE s;
-- ============================================================
-- 2. 注册填值规则 mes_raw_material_barcode_rule
-- ============================================================
INSERT INTO `sys_fill_rule` (`id`, `rule_name`, `rule_code`, `rule_class`, `rule_params`, `create_by`, `create_time`)
SELECT '1920000000000001001',
'MES原料入场条码/批次号规则',
'mes_raw_material_barcode_rule',
'org.jeecg.modules.xslmes.rule.RawMaterialBarcodeRule',
NULL,
'admin',
NOW()
FROM DUAL
WHERE NOT EXISTS (
SELECT 1 FROM `sys_fill_rule` WHERE `rule_code` = 'mes_raw_material_barcode_rule'
);