refactor: 重构产线工位与备料流程,移除冗余字段
1. 移除工单、工件、日排产中的冗余工位组合/接驳台字段 2. 新增工位接驳台编码字段与唯一约束,关联WMS接驳台主数据 3. 重构日排产为工位产量分配模式,替代原接驳台列表 4. 新增备料单工位级字段与分批出库支持 5. 移除定时同步可生产数量,改为WMS实时拉取接口 6. 过滤操作日志,排除登录/退出相关日志 7. 调整仪表盘工序展示逻辑为今日派工路线 8. 新增接驳台维护菜单与基础数据
This commit is contained in:
@@ -235,12 +235,16 @@ func (s *Service) validateStationBinds(ctx context.Context, client *ent.Client,
|
||||
|
||||
// validateAllProcessBinds 完工兜底:校验工件工艺路线中每个工序的装配物料齐套
|
||||
func (s *Service) validateAllProcessBinds(ctx context.Context, client *ent.Client, sn string) (string, error) {
|
||||
wp, _, err := s.workpieceProduct(ctx, client, sn)
|
||||
if _, _, err := s.workpieceProduct(ctx, client, sn); err != nil {
|
||||
return "", err
|
||||
}
|
||||
// 工艺路线由 station_process(按今日派工)派生:遍历今日启用的全部工序编号,逐一校验装配物料齐套
|
||||
codes, err := RouteProcessCodes(ctx, client, TodayStr(), "")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
missing := []string{}
|
||||
for _, code := range ParseProcessSeq(wp.ProcessSeq) {
|
||||
for _, code := range codes {
|
||||
msg, err := s.validateStationBinds(ctx, client, sn, code)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@@ -264,14 +268,27 @@ func (s *Service) ListWorkpieceBinds(ctx context.Context, sn string) ([]*ent.Wor
|
||||
return q.Order(ent.Asc(workpiecebind.FieldProcessCode), ent.Asc(workpiecebind.FieldID)).Limit(2000).All(ctx)
|
||||
}
|
||||
|
||||
// BindTraceVO 追溯页:装机绑定明细 + 每工序齐套状态
|
||||
// BindTraceVO 追溯页:装机绑定明细 + 每工序齐套状态 + 物料组成树
|
||||
type BindTraceVO struct {
|
||||
Binds []*ent.WorkpieceBind `json:"binds"`
|
||||
Complete bool `json:"complete"`
|
||||
Missing string `json:"missing"`
|
||||
BomTree []BindNode `json:"bomTree"` // 递归展开成品零部件到叶子的物料组成树
|
||||
}
|
||||
|
||||
// BuildBindTrace 组装某工件装机绑定追溯(含全工序齐套状态,供成品档案/追溯页展示)
|
||||
// BindNode 追溯用的物料组成节点(递归展开成品零部件,不依赖 WMS)
|
||||
type BindNode struct {
|
||||
MaterialCode string `json:"materialCode"`
|
||||
MaterialName string `json:"materialName"`
|
||||
Spec string `json:"spec"`
|
||||
Unit string `json:"unit"`
|
||||
ManageMode string `json:"manageMode"` // 1 批次(结构件) / 2 SN(电气件)
|
||||
Qty float64 `json:"qty"` // 折算到单台成品的用量
|
||||
Level int `json:"level"` // 0=顶层装配物料,1+=下级
|
||||
Children []BindNode `json:"children,omitempty"`
|
||||
}
|
||||
|
||||
// BuildBindTrace 组装某工件装机绑定追溯(含全工序齐套状态 + 物料组成树,供成品档案/追溯页展示)
|
||||
func (s *Service) BuildBindTrace(ctx context.Context, sn string) (*BindTraceVO, error) {
|
||||
binds, err := s.ListWorkpieceBinds(ctx, sn)
|
||||
if err != nil {
|
||||
@@ -281,7 +298,51 @@ func (s *Service) BuildBindTrace(ctx context.Context, sn string) (*BindTraceVO,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &BindTraceVO{Binds: binds, Complete: missing == "", Missing: missing}, nil
|
||||
// 物料组成树:递归展开成品零部件到叶子(不依赖 WMS),让追溯页能展示完整物料组成,
|
||||
// 避免成品作零部件被引用时只显示上层成品而漏下层料、追溯断链。
|
||||
var tree []BindNode
|
||||
if _, wo, perr := s.workpieceProduct(ctx, s.ctx.EntClient, sn); perr == nil && wo != nil {
|
||||
tree = s.expandBindBom(ctx, s.ctx.EntClient, wo.ProductCode, "", 1, 0, map[string]bool{})
|
||||
}
|
||||
return &BindTraceVO{Binds: binds, Complete: missing == "", Missing: missing, BomTree: tree}, nil
|
||||
}
|
||||
|
||||
// expandBindBom 递归展开某产品的物料组成树(成品/装配件若存在下级 BOM 则继续展开,叶子终止)。
|
||||
// 不依赖 WMS:用 BomItem 是否存在 productCode 记录判断是否有下级 BOM,避免 WMS 不可达时不展开。
|
||||
// 防环:同一条展开路径出现重复编码视为配置错误,跳过该分支。
|
||||
func (s *Service) expandBindBom(ctx context.Context, client *ent.Client, productCode, bomName string, qty float64, depth int, path map[string]bool) []BindNode {
|
||||
const maxDepth = 10
|
||||
if depth > maxDepth || productCode == "" {
|
||||
return nil
|
||||
}
|
||||
if path[productCode] {
|
||||
s.ctx.EventLog.Write(ctx, "bom.expand.cycle", "", "", "product_bom", productCode,
|
||||
"产品物料清单存在循环引用,已跳过", map[string]any{"depth": depth})
|
||||
return nil
|
||||
}
|
||||
items, err := client.BomItem.Query().
|
||||
Where(bomitem.ProductCode(productCode), bomitem.BomName(bomNameOrDefault(bomName))).All(ctx)
|
||||
if err != nil || len(items) == 0 {
|
||||
return nil
|
||||
}
|
||||
path[productCode] = true
|
||||
defer delete(path, productCode)
|
||||
out := make([]BindNode, 0, len(items))
|
||||
for _, it := range items {
|
||||
if it.MaterialCode == "" {
|
||||
continue
|
||||
}
|
||||
node := BindNode{
|
||||
MaterialCode: it.MaterialCode, MaterialName: it.MaterialName, Spec: it.Spec,
|
||||
Unit: it.Unit, ManageMode: it.ManageMode, Qty: it.UnitQty * qty, Level: depth,
|
||||
}
|
||||
// 该物料自身是否还有下级 BOM(成品/装配件):递归展开其子件
|
||||
if has, _ := client.BomItem.Query().Where(bomitem.ProductCode(it.MaterialCode)).Exist(ctx); has {
|
||||
node.Children = s.expandBindBom(ctx, client, it.MaterialCode, bomName, it.UnitQty*qty, depth+1, path)
|
||||
}
|
||||
out = append(out, node)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// BindRequiredItem 应绑清单条目(工位终端/手动报工展示引导 + 前端齐套计算)
|
||||
|
||||
Reference in New Issue
Block a user