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
+4 -5
View File
@@ -11,7 +11,6 @@ import (
"time"
"bj_power_mes/ent/dailyplan"
"bj_power_mes/ent/producttype"
"bj_power_mes/ent/workorder"
"bj_power_mes/internal/wmsclient"
)
@@ -100,8 +99,8 @@ func (s *Service) ComputeProducible(ctx context.Context) (*ProducibleResult, err
// 4) 产品名称映射(product_type 优先,work_order 兜底)
nameMap := map[string]string{}
if pts, e := s.ctx.EntClient.ProductType.Query().All(ctx); e == nil {
for _, p := range pts {
if rows, e := s.ctx.Wms.ProductTypes(ctx, ""); e == nil {
for _, p := range rows {
nameMap[p.Code] = p.Name
}
}
@@ -185,11 +184,11 @@ func (s *Service) dropInactiveProducts(ctx context.Context, chosen map[string][]
if len(chosen) == 0 {
return
}
pts, err := s.ctx.EntClient.ProductType.Query().Where(producttype.IsActiveEQ(false)).All(ctx)
rows, err := s.ctx.Wms.ProductTypes(ctx, "false")
if err != nil {
return
}
for _, p := range pts {
for _, p := range rows {
delete(chosen, p.Code)
}
}
+28 -64
View File
@@ -6,16 +6,14 @@ import (
"fmt"
"strings"
"bj_power_mes/ent"
"bj_power_mes/ent/bomitem"
"bj_power_mes/ent/producttype"
"bj_power_mes/ent/workorder"
"bj_power_mes/internal/wmsclient"
)
// 产品型号(成品档案):编码主数据单一来源 = WMSmaterials item_type=3)。
// MES 本页改为实时代理 WMSWMS 不可达时降级读本地 product_types 只读缓存(仅查询
// 写操作必须 WMS 可用),前端以 wmsOnline 标识提示
// MES 本页实时代理 WMS不再保留本地 product_types 缓存/双写(方案 A:WMS 不可达即报错
// 不降级读本地缓存,避免给界面喂空/陈旧数据)
type ProductTypeReq struct {
Id int `json:"id"`
@@ -69,7 +67,7 @@ func (s *Service) UpdateProductType(ctx context.Context, req ProductTypeReq) err
// DeleteProductType 删除保护:被工单/BOM 引用过的型号禁删(MES 侧引用校验,
// WMS 侧库存引用由 WMS 内部接口再校验一层)
func (s *Service) DeleteProductType(ctx context.Context, id int) error {
row, err := s.productTypeByID(ctx, id)
row, err := s.ProductTypeByID(ctx, id)
if err != nil {
return err
}
@@ -88,84 +86,50 @@ func (s *Service) DeleteProductType(ctx context.Context, id int) error {
}
// ListProductTypes 全量列表(下拉/兼容形态,id asc 新建在底部)。
// degraded=false 表示 WMS 不可达、数据来自本地只读缓存
// 纯 WMS 代理:WMS 不可达直接报错(不再降级本地缓存)。degraded 恒为 true(仅兼容前端字段)
func (s *Service) ListProductTypes(ctx context.Context) ([]wmsclient.ProductTypeRow, bool, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, "")
if err == nil {
return list, true, nil
if err != nil {
return nil, false, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
fallback, ferr := s.localProductTypes(ctx, "", "", "")
if ferr != nil {
return nil, false, errors.New("WMS 不可达且本地缓存读取失败")
}
return fallback, false, nil
return list, true, nil
}
// ListProductTypesPage 分页+搜索(管理页真分页)。
// 2026-09-08 禁止关键字混搜:编码/名称/类别各自独立模糊。
// 纯 WMS 代理:WMS 不可达直接报错。wmsOnline 恒为 true(仅兼容前端字段)。
func (s *Service) ListProductTypesPage(ctx context.Context, code, name, category, isActive string, page, pageSize int) (int64, []wmsclient.ProductTypeRow, bool, error) {
total, list, err := s.ctx.Wms.ProductTypePage(ctx, code, name, category, isActive, page, pageSize)
if err == nil {
return total, list, true, nil
if err != nil {
return 0, nil, false, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
fallback, ferr := s.localProductTypes(ctx, code, name, category)
if ferr != nil {
return 0, nil, false, errors.New("WMS 不可达且本地缓存读取失败")
}
start := (page - 1) * pageSize
if start > len(fallback) {
start = len(fallback)
}
end := start + pageSize
if end > len(fallback) {
end = len(fallback)
}
return int64(len(fallback)), fallback[start:end], false, nil
return total, list, true, nil
}
func (s *Service) productTypeByID(ctx context.Context, id int) (*wmsclient.ProductTypeRow, error) {
// ProductTypeByID 从 WMS 取成品档案(item_type=3)按 idWMS 不可达即报错。
func (s *Service) ProductTypeByID(ctx context.Context, id int) (*wmsclient.ProductTypeRow, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, "")
if err == nil {
for i := range list {
if list[i].ID == id {
return &list[i], nil
}
}
return nil, errors.New("物料档案不存在")
}
// 降级:本地缓存
pt, err := s.ctx.EntClient.ProductType.Get(ctx, id)
if err != nil {
return nil, errors.New("物料档案不存在(WMS 不可达,无法校验引用)")
return nil, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
return &wmsclient.ProductTypeRow{ID: pt.ID, Code: pt.Code, Name: pt.Name}, nil
for i := range list {
if list[i].ID == id {
return &list[i], nil
}
}
return nil, errors.New("物料档案不存在")
}
// localProductTypes 本地只读缓存过滤(降级用):编码/名称/类别各自独立模糊匹配
func (s *Service) localProductTypes(ctx context.Context, code, name, category string) ([]wmsclient.ProductTypeRow, error) {
list, err := s.ctx.EntClient.ProductType.Query().Order(ent.Asc(producttype.FieldID)).All(ctx)
// ProductTypeByCode 从 WMS 取成品档案按 code。
func (s *Service) ProductTypeByCode(ctx context.Context, code string) (*wmsclient.ProductTypeRow, error) {
list, err := s.ctx.Wms.ProductTypes(ctx, "")
if err != nil {
return nil, err
return nil, errors.New("WMS 不可达,无法读取成品档案:" + err.Error())
}
codeKw := strings.ToLower(strings.TrimSpace(code))
nameKw := strings.ToLower(strings.TrimSpace(name))
catKw := strings.ToLower(strings.TrimSpace(category))
rows := make([]wmsclient.ProductTypeRow, 0, len(list))
for _, p := range list {
if codeKw != "" && !strings.Contains(strings.ToLower(p.Code), codeKw) {
continue
for i := range list {
if list[i].Code == code {
return &list[i], nil
}
if nameKw != "" && !strings.Contains(strings.ToLower(p.Name), nameKw) {
continue
}
if catKw != "" && !strings.Contains(strings.ToLower(p.Category), catKw) {
continue
}
rows = append(rows, wmsclient.ProductTypeRow{
ID: p.ID, Code: p.Code, Name: p.Name, Spec: p.Spec, Unit: p.Unit,
Category: p.Category, IsActive: p.IsActive,
CreatedAt: p.CreatedAt.Unix(),
})
}
return rows, nil
return nil, errors.New("物料档案不存在")
}