1. 移除所有多字段关键字混搜,改为各筛选字段独立查询 2. 调整excel导出相关逻辑,优化文件名处理与导入模板 3. 修复物料导入的类型解析与token获取逻辑 4. 更新依赖与前端页面文案、筛选参数
153 lines
5.3 KiB
Go
153 lines
5.3 KiB
Go
package logic
|
||
|
||
import (
|
||
"context"
|
||
"errors"
|
||
"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"
|
||
)
|
||
|
||
// 产品型号(成品档案):编码主数据单一来源 = WMS(materials item_type=3)。
|
||
// MES 本页改为实时代理 WMS;WMS 不可达时降级读本地 product_types 只读缓存(仅查询,
|
||
// 写操作必须 WMS 可用),前端以 wmsOnline 标识提示。
|
||
|
||
type ProductTypeReq struct {
|
||
Id int `json:"id"`
|
||
Name string `json:"name"`
|
||
Code string `json:"code"`
|
||
Category string `json:"category"`
|
||
Remark string `json:"remark"`
|
||
IsActive bool `json:"isActive"`
|
||
}
|
||
|
||
func (s *Service) CreateProductType(ctx context.Context, req ProductTypeReq) error {
|
||
active := req.IsActive
|
||
if !req.IsActive {
|
||
active = true
|
||
}
|
||
if err := s.ctx.Wms.CreateProductType(ctx, req.Code, req.Name, req.Category, req.Remark, active); err != nil {
|
||
return errors.New("WMS 不可达或拒绝写入(编码主数据以 WMS 为单一来源):" + err.Error())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func (s *Service) UpdateProductType(ctx context.Context, req ProductTypeReq) error {
|
||
if req.Id == 0 {
|
||
return errors.New("缺少 id")
|
||
}
|
||
if err := s.ctx.Wms.UpdateProductType(ctx, req.Id, req.Name, req.Category, req.Remark, req.IsActive); err != nil {
|
||
return errors.New("WMS 不可达或拒绝写入:" + err.Error())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// DeleteProductType 删除保护:被工单/BOM 引用过的型号禁删(MES 侧引用校验,
|
||
// WMS 侧库存引用由 WMS 内部接口再校验一层)
|
||
func (s *Service) DeleteProductType(ctx context.Context, id int) error {
|
||
row, err := s.productTypeByID(ctx, id)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
woCnt, _ := s.ctx.EntClient.WorkOrder.Query().Where(workorder.ProductCode(row.Code)).Count(ctx)
|
||
if woCnt > 0 {
|
||
return fmt.Errorf("该产品型号已被 %d 张工单引用,不可删除;建议停用(下架)", woCnt)
|
||
}
|
||
bomCnt, _ := s.ctx.EntClient.BomItem.Query().Where(bomitem.ProductCode(row.Code)).Count(ctx)
|
||
if bomCnt > 0 {
|
||
return fmt.Errorf("该产品型号在物料清单中有 %d 条配置,不可删除;建议停用(下架)", bomCnt)
|
||
}
|
||
if err := s.ctx.Wms.DeleteProductType(ctx, id); err != nil {
|
||
return errors.New("WMS 不可达或拒绝删除:" + err.Error())
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// ListProductTypes 全量列表(下拉/兼容形态,id asc 新建在底部)。
|
||
// degraded=false 表示 WMS 不可达、数据来自本地只读缓存。
|
||
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
|
||
}
|
||
fallback, ferr := s.localProductTypes(ctx, "", "", "")
|
||
if ferr != nil {
|
||
return nil, false, errors.New("WMS 不可达且本地缓存读取失败")
|
||
}
|
||
return fallback, false, nil
|
||
}
|
||
|
||
// ListProductTypesPage 分页+搜索(管理页真分页)。
|
||
// 2026-09-08 禁止关键字混搜:编码/名称/类别各自独立模糊。
|
||
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
|
||
}
|
||
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
|
||
}
|
||
|
||
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 &wmsclient.ProductTypeRow{ID: pt.ID, Code: pt.Code, Name: pt.Name}, nil
|
||
}
|
||
|
||
// 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)
|
||
if err != nil {
|
||
return nil, err
|
||
}
|
||
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
|
||
}
|
||
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, Category: p.Category,
|
||
Remark: p.Remark, IsActive: p.IsActive,
|
||
CreatedAt: p.CreatedAt.Unix(),
|
||
})
|
||
}
|
||
return rows, nil
|
||
}
|