refactor: 清理MES端本地product_type冗余代码,对齐WMS主数据架构

1.  移除MES端本地product_type实体、schema及相关CRUD代码,改为通过WMS内部API代理获取物料主数据
2.  更新物料管理粒度逻辑,新增"其他"类型(3)支持,同步更新入库校验规则
3.  修复前端物料选择、库存筛选等页面的类型判断逻辑,统一使用manage_mode区分管理类型
4.  清理静态资源文件冗余的样式代码,调整前端页面展示逻辑
5.  更新帮助文档,修正物料类型的说明描述
This commit is contained in:
SunYF
2026-09-22 07:41:40 +08:00
parent 12ca493c61
commit 932700ca65
84 changed files with 698 additions and 3955 deletions
+45 -18
View File
@@ -6,6 +6,7 @@ import (
"time"
"bj_power_wms/ent"
"bj_power_wms/ent/inventory"
"bj_power_wms/ent/material"
"bj_power_wms/internal/svc"
@@ -31,7 +32,7 @@ func itemTypeLabel(t int) string {
// 新增/编辑表单除「说明」外全部必填)。返回空串表示通过,否则返回中文错误文案。
//
// 说明:图号 code 只在新增时必填(编辑不可改),由调用方单独校验;
// 「其他」类物料不做 SN,管理粒度由后端强制收敛为 1结构件),故不参与必填。
// 「类型」= 管理粒度 1结构件/2电气件/3其他,与「品类」相互独立,均必填。
func validateMaterialRequired(name, spec, unit string, itemType, manageMode int) string {
switch {
case strings.TrimSpace(name) == "":
@@ -42,8 +43,8 @@ func validateMaterialRequired(name, spec, unit string, itemType, manageMode int)
return "单位为必填项"
case itemType < 1 || itemType > invItemOther:
return "品类为必填项(原材料 / 半成品 / 成品 / 其他)"
case itemType != invItemOther && manageMode != 1 && manageMode != 2:
return "类型为必填项(结构件 / 电气件)"
case manageMode != 1 && manageMode != 2 && manageMode != invManageOther:
return "类型为必填项(结构件 / 电气件 / 其他"
}
return ""
}
@@ -89,13 +90,9 @@ func createMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return
}
// 品类/管理粒度已在上方校验,这里只做「其他类不做 SN」的业务收敛
// 品类/类型已在上方校验,原样落库(类型 1结构件/2电气件/3其他 相互独立,不再由品类收敛
manageMode := req.ManageMode
itemType := req.ItemType
// 其他类(辅料/工装/试验设备)只按数量管理,不做 SN
if itemType == invItemOther {
manageMode = 1
}
m, err := ctx.EntClient.Material.Create().
SetCode(req.Code).
@@ -104,7 +101,7 @@ func createMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
SetNillableUnit(strPtr(req.Unit)).
SetNillableDescription(strPtr(req.Description)).
SetManageMode(manageMode).
SetIsBatchManaged(manageMode == 1).
SetIsBatchManaged(manageMode == 1 || manageMode == invManageOther).
SetIsSerialManaged(manageMode == 2).
SetNillableTemplateCode(strPtr(req.TemplateCode)).
SetItemType(itemType).
@@ -151,9 +148,6 @@ func updateMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
manageMode := req.ManageMode
if req.ItemType == invItemOther {
manageMode = 1
}
m, err := ctx.EntClient.Material.UpdateOneID(req.ID).
SetName(req.Name).
SetSpec(req.Spec).
@@ -162,7 +156,7 @@ func updateMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
SetItemType(req.ItemType).
SetSafetyStock(req.SafetyStock).
SetManageMode(manageMode).
SetIsBatchManaged(manageMode == 1).
SetIsBatchManaged(manageMode == 1 || manageMode == invManageOther).
SetIsSerialManaged(manageMode == 2).
Save(ctx0())
if err != nil {
@@ -175,6 +169,36 @@ func updateMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
}
// deleteMaterialHandler 删除物料档案(全品类,供 MES 物料档案代理调用)
// 删除保护:库存仍引用该物料时禁删(与产品型号口径一致)。
func deleteMaterialHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
var req struct {
ID int `json:"id"`
}
if err := parseJSON(r, &req); err != nil || req.ID <= 0 {
fail(w, http.StatusBadRequest, "参数错误")
return
}
cur, err := ctx.EntClient.Material.Get(ctx0(), req.ID)
if err != nil {
fail(w, http.StatusNotFound, "物料不存在")
return
}
if n, _ := ctx.EntClient.Inventory.Query().Where(inventory.MaterialCodeEqualFold(cur.Code)).Count(ctx0()); n > 0 {
fail(w, http.StatusConflict, "该物料档案已有库存记录("+itoa(n)+"条),不可删除;建议停用(下架)")
return
}
if err := ctx.EntClient.Material.DeleteOneID(req.ID).Exec(ctx0()); err != nil {
fail(w, http.StatusInternalServerError, "删除物料失败:"+err.Error())
return
}
ctx.EventLog.Write(ctx0(), "material.delete", r.Header.Get("X-Username"), "material", cur.Code,
"删除物料档案 "+cur.Code, nil)
ok(w, nil)
}
}
// queryMaterialsHandler 分页查询物料
func queryMaterialsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
return func(w http.ResponseWriter, r *http.Request) {
@@ -446,8 +470,8 @@ func exportMaterialsHandler(ctx *svc.ServiceContext) http.HandlerFunc {
}
}
// parseManageMode 解析导入模板"类型"列:支持中文(结构件/电气件,含"(批次)/(SN)"后缀)
// 与数字格式(1/2)双向兼容;无法识别返回 0。
// parseManageMode 解析导入模板"类型"列:支持中文(结构件/电气件/其他,含"(批次)/(SN)"后缀)
// 与数字格式(1/2/3)双向兼容;无法识别返回 0。
func parseManageMode(s string) int {
if s == "" {
return 0
@@ -458,7 +482,10 @@ func parseManageMode(s string) int {
if strings.Contains(s, "结构") || strings.Contains(s, "批次") {
return 1
}
if n := atoi(s, 0); n == 1 || n == 2 {
if strings.Contains(s, "其他") {
return invManageOther
}
if n := atoi(s, 0); n >= 1 && n <= 3 {
return n
}
return 0
@@ -613,7 +640,7 @@ func excelMaterialImportHandler(ctx *svc.ServiceContext) http.HandlerFunc {
continue
}
if pr.manageMode == 0 {
errs = append(errs, importErr{pr.row, pr.code, "类型无法识别,请填写「结构件」或「电气件」(兼容 1/2"})
errs = append(errs, importErr{pr.row, pr.code, "类型无法识别,请填写「结构件/电气件/其他」(兼容 1/2/3"})
continue
}
if catCol >= 0 && cell(catCol) != "" && pr.itemType == 0 {
@@ -656,7 +683,7 @@ func excelMaterialImportHandler(ctx *svc.ServiceContext) http.HandlerFunc {
SetNillableUnit(strPtr(pr.unit)).
SetNillableDescription(strPtr(pr.description)).
SetManageMode(pr.manageMode).
SetIsBatchManaged(pr.manageMode == 1).
SetIsBatchManaged(pr.manageMode == 1 || pr.manageMode == invManageOther).
SetIsSerialManaged(pr.manageMode == 2)
if pr.itemType > 0 {
mc = mc.SetItemType(pr.itemType)