feat(mes): 添加定时同步可生产数量到WMS及BOM项相关标准字段

- 在main.go中添加定时任务每10分钟同步可生产数量到WMS系统
- 为BomItem实体添加relatedStandard字段及相关CRUD方法
- 为InspectionRecord实体添加reportNo、materialCode、materialName等字段
- 更新ent schema确保新字段的验证和默认值设置
- 添加必要的数据库迁移和字段映射逻辑
This commit is contained in:
SunYF
2026-09-17 12:49:07 +08:00
parent b4b274301d
commit 1cc93795ce
191 changed files with 24504 additions and 1250 deletions
+39 -26
View File
@@ -165,7 +165,8 @@ func (s *Service) SaveFlow(ctx context.Context, req FlowReq, operator string) er
}
rec, err := s.ctx.EntClient.ProcessStep.Create().
SetFlowId(flowID).SetSeq(st.Seq).SetName(st.Name).
SetCollectType(st.CollectType).SetIsTorque(st.IsTorque).SetNeedCheck(st.NeedCheck).SetRemark(st.Remark).Save(ctx)
SetCollectType(st.CollectType).SetIsTorque(st.IsTorque).SetNeedCheck(st.NeedCheck).
SetRemark(st.Remark).SetAttachment(st.Attachment).Save(ctx)
if err != nil {
return err
}
@@ -221,7 +222,7 @@ func (s *Service) flowSteps(ctx context.Context, flowId int) []*ProcessStepTempl
t := &ProcessStepTemplate{
ID: st.ID, Seq: st.Seq,
Name: st.Name, CollectType: st.CollectType, IsTorque: st.IsTorque, NeedCheck: st.NeedCheck,
Remark: st.Remark, Criteria: []CriterionVO{},
Remark: st.Remark, Attachment: st.Attachment, Criteria: []CriterionVO{},
}
crits, _ := s.ctx.EntClient.StepCriterion.Query().
Where(stepcriterion.StepId(st.ID)).All(ctx)
@@ -385,15 +386,30 @@ func (s *Service) StationTask(ctx context.Context, stationNo int) (map[string]an
}
// WorkloadRow 绩效/工作量聚合行(按人/按工位/明细三视图共用)
// 前端按 camelCase 读取,必须显式标注 json tag(否则 Go 默认序列化为 PascalCase 导致列空白)
type WorkloadRow struct {
Operator string
StationNo string
Date string
ProcessCode int
ProcessName string
DoneCount int
OkCount int
NgCount int
Operator string `json:"operator"`
StationNo string `json:"stationNo"`
Date string `json:"date"`
ProcessCode int `json:"processCode"`
ProcessName string `json:"processName"`
DoneCount int `json:"doneCount"`
OkCount int `json:"okCount"`
NgCount int `json:"ngCount"`
// Item M 绩效效率:作业时长取自 workpiece_process.duration_sec
TotalDurationSec int `json:"totalDurationSec"` // 累计作业时长(秒)
AvgDurationSec int `json:"avgDurationSec"` // 平均作业时长(秒)=累计/完成数
Efficiency float64 `json:"efficiency"` // 效率(件/小时)=完成数/(累计时长/3600)
}
// finalizeWorkloadRow 由累计作业时长与完成数派生平均作业时长与效率
func finalizeWorkloadRow(r *WorkloadRow) {
if r.DoneCount > 0 {
r.AvgDurationSec = r.TotalDurationSec / r.DoneCount
}
if r.TotalDurationSec > 0 {
r.Efficiency = float64(r.DoneCount) / (float64(r.TotalDurationSec) / 3600.0)
}
}
func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to string,
@@ -432,6 +448,7 @@ func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to st
agg[k] = row
}
row.DoneCount++
row.TotalDurationSec += r.DurationSec
if r.Result == "OK" {
row.OkCount++
} else {
@@ -464,30 +481,20 @@ func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to st
o.DoneCount += v.DoneCount
o.OkCount += v.OkCount
o.NgCount += v.NgCount
o.TotalDurationSec += v.TotalDurationSec
} else {
byOpAgg[opKey] = &WorkloadRow{Operator: v.Operator, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount}
byOpAgg[opKey] = &WorkloadRow{Operator: v.Operator, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount, TotalDurationSec: v.TotalDurationSec}
}
stKey := v.StationNo
if o, ok := byStAgg[stKey]; ok {
o.DoneCount += v.DoneCount
o.OkCount += v.OkCount
o.NgCount += v.NgCount
o.TotalDurationSec += v.TotalDurationSec
} else {
byStAgg[stKey] = &WorkloadRow{StationNo: v.StationNo, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount}
byStAgg[stKey] = &WorkloadRow{StationNo: v.StationNo, DoneCount: v.DoneCount, OkCount: v.OkCount, NgCount: v.NgCount, TotalDurationSec: v.TotalDurationSec}
}
}
paginateRows := func(all []*ent.WorkpieceProcess, page, size int) (int, []*ent.WorkpieceProcess) {
total := len(all)
start := (page - 1) * size
if start > total {
start = total
}
end := start + size
if end > total {
end = total
}
return total, all[start:end]
}
paginate := func(all []*WorkloadRow, page, size int) (int, []*WorkloadRow) {
total := len(all)
start := (page - 1) * size
@@ -503,22 +510,28 @@ func (s *Service) Workload(ctx context.Context, operator, stationNo, from, to st
byOpList := make([]*WorkloadRow, 0, len(byOpAgg))
for _, v := range byOpAgg {
finalizeWorkloadRow(v)
byOpList = append(byOpList, v)
}
sort.Slice(byOpList, func(i, j int) bool { return byOpList[i].Operator < byOpList[j].Operator })
byStList := make([]*WorkloadRow, 0, len(byStAgg))
for _, v := range byStAgg {
finalizeWorkloadRow(v)
byStList = append(byStList, v)
}
sort.Slice(byStList, func(i, j int) bool { return byStList[i].StationNo < byStList[j].StationNo })
// 明细视图:按 (操作人,工位,日期,工序) 聚合,与前端明细表列(date/doneCount/okCount/ngCount)对齐
for _, v := range list {
finalizeWorkloadRow(v)
}
opTotal, byOpPage := paginate(byOpList, opPage, opSize)
stTotal, byStPage := paginate(byStList, stPage, stSize)
detTotal, detRowsPage := paginateRows(rows, detPage, detSize)
detTotal, detList := paginate(list, detPage, detSize)
return map[string]any{
"byOperator": map[string]any{"total": opTotal, "list": byOpPage},
"byStation": map[string]any{"total": stTotal, "list": byStPage},
"detail": map[string]any{"total": detTotal, "list": detRowsPage},
"detail": map[string]any{"total": detTotal, "list": detList},
}, nil
}