chore: 批量完成项目多模块迭代优化

1. 废弃半成品库存表并统一库存主表
2. 修复列表排序与搜索大小写不敏感问题
3. 新增用户最近登录时间、工单BOM名称字段
4. 完善角色管理、工位选择器功能
5. 增加拧紧数据补录、成品自动回流WMS能力
6. 统一导出时间范围校验规则
7. 丰富物料/备料单筛选条件
8. 调整菜单与权限命名适配产品型号业务
This commit is contained in:
SunYF
2026-09-08 11:44:04 +08:00
parent 06689970e2
commit e852c7cd37
96 changed files with 4528 additions and 542 deletions
+18 -16
View File
@@ -81,26 +81,27 @@ type bindTarget struct {
UnitQty float64
}
// workpieceProduct 解析工件所属产品编码(sn → workpiece → workOrder → productCode
func (s *Service) workpieceProduct(ctx context.Context, sn string) (*ent.Workpiece, string, error) {
// workpieceProduct 解析工件所属产品编码与工单锁定的 BOM 名称sn → workpiece → workOrder
func (s *Service) workpieceProduct(ctx context.Context, sn string) (*ent.Workpiece, *ent.WorkOrder, error) {
wp, err := s.ctx.EntClient.Workpiece.Query().Where(workpiece.Sn(sn)).First(ctx)
if err != nil {
return nil, "", errors.New("工件未进线登记")
return nil, nil, errors.New("工件未进线登记")
}
if wp.WorkOrderId <= 0 {
return wp, "", errors.New("工件未关联工单")
return wp, nil, errors.New("工件未关联工单")
}
wo, err := s.ctx.EntClient.WorkOrder.Get(ctx, wp.WorkOrderId)
if err != nil || wo == nil {
return wp, "", errors.New("工件所属工单不存在")
return wp, nil, errors.New("工件所属工单不存在")
}
return wp, wo.ProductCode, nil
return wp, wo, nil
}
// stationBindTargets 取某产品在某工序(processCode>0)要求装配的物料清单
func (s *Service) stationBindTargets(ctx context.Context, productCode string, processCode int) ([]bindTarget, error) {
// stationBindTargets 取某工单(产品+BOM)在某工序(processCode>0)要求装配的物料清单
// 一型号多份 BOM 并存,必须按工单锁定的 bomName 过滤,否则不同厂家料单互相串。
func (s *Service) stationBindTargets(ctx context.Context, productCode, bomName string, processCode int) ([]bindTarget, error) {
items, err := s.ctx.EntClient.BomItem.Query().
Where(bomitem.ProductCode(productCode), bomitem.ProcessCode(processCode)).All(ctx)
Where(bomitem.ProductCode(productCode), bomitem.BomName(bomNameOrDefault(bomName)), bomitem.ProcessCode(processCode)).All(ctx)
if err != nil {
return nil, err
}
@@ -123,17 +124,18 @@ func (s *Service) applyBinds(ctx context.Context, sn, orderNo string, processCod
if len(items) == 0 {
return 0, nil
}
wp, productCode, err := s.workpieceProduct(ctx, sn)
wp, wo, err := s.workpieceProduct(ctx, sn)
if err != nil {
return 0, err
}
productCode := wo.ProductCode
if wp.Status == "DONE" || wp.Status == "SCRAPPED" {
return 0, errors.New("已完工/报废工件不能再绑定物料")
}
// 产品 BOM 全量索引:materialCode → target(校验料合法性 + 取物料快照)
// 工单锁定 BOM 全量索引:materialCode → target(校验料合法性 + 取物料快照)
bomMap := map[string]*ent.BomItem{}
allBom, _ := s.ctx.EntClient.BomItem.Query().
Where(bomitem.ProductCode(productCode)).All(ctx)
Where(bomitem.ProductCode(productCode), bomitem.BomName(bomNameOrDefault(wo.BomName))).All(ctx)
for _, b := range allBom {
bomMap[b.MaterialCode] = b
}
@@ -186,11 +188,11 @@ func (s *Service) applyBinds(ctx context.Context, sn, orderNo string, processCod
// 返回缺料明细(空串=齐套)。判定:精密件(SN) 绑定的不同SN数 ≥ 单台用量;结构件(批次) 至少绑定1个批次号。
// 若该产品该工序未配置任何装配物料(processCode未配置),视为不启用绑定校验,放行。
func (s *Service) validateStationBinds(ctx context.Context, sn string, processCode int) (string, error) {
_, productCode, err := s.workpieceProduct(ctx, sn)
_, wo, err := s.workpieceProduct(ctx, sn)
if err != nil {
return "", err
}
targets, err := s.stationBindTargets(ctx, productCode, processCode)
targets, err := s.stationBindTargets(ctx, wo.ProductCode, wo.BomName, processCode)
if err != nil {
return "", err
}
@@ -310,11 +312,11 @@ type StationBindPanel struct {
// StationBindPanelData 供工位终端/手动报工页在报工前拉取:本工件本工序该装什么、已装什么
func (s *Service) StationBindPanelData(ctx context.Context, sn string, processCode int) (*StationBindPanel, error) {
_, productCode, err := s.workpieceProduct(ctx, sn)
_, wo, err := s.workpieceProduct(ctx, sn)
if err != nil {
return nil, err
}
targets, err := s.stationBindTargets(ctx, productCode, processCode)
targets, err := s.stationBindTargets(ctx, wo.ProductCode, wo.BomName, processCode)
if err != nil {
return nil, err
}