docs(business): 生成业务契约文档并重构MES客户端代码

- 创建案例.md文档,包含业务场景清单、业务流程、案例和回归测试三份完整文档
- WMS库房管理系统涵盖入库、出库、库存、检验、盘点等24个业务场景
- MES产线控制系统包含工单、排产、BOM、备料、质检、追溯等23个业务场景
- 工位终端系统支持上线、报工、下线、领料、巡检等15个现场作业场景
- 主链路从合同到成品入库,异常链路处理不合格、数量不符、退料等情况
- 删除MES客户端中的ScanRecord相关代码,精简客户端结构
- 更新客户端初始化逻辑,移除扫描记录相关的依赖注入配置
This commit is contained in:
SunYF
2026-09-20 18:25:44 +08:00
parent 5f68e77d5f
commit 8e6e8e1d20
46 changed files with 1052 additions and 3954 deletions
+60
View File
@@ -132,6 +132,16 @@ func (s *Service) ReportProcess(ctx context.Context, req ReportProcessReq, opera
if err != nil {
return errors.New("工件未进线登记")
}
// 严格校验(业务口径已确认):仅“在制”工件可报工,且必须按工序顺序流转,禁止跳站/漏站/重复报同一站。
// 在制 = ONLINE(已进线) / PROCESSING(在工位)DONE/REPAIR/SCRAPPED 一律拒绝。
if wp.Status != "ONLINE" && wp.Status != "PROCESSING" {
return errors.New("工件当前状态为「" + wp.Status + "」,非在制,不允许报工")
}
// 顺序流转:currentProcess 语义为“已报工完成的工序”(进线时=0),本工位必须是其下一道,即 processCode == currentProcess+1。
if req.ProcessCode != wp.CurrentProcess+1 {
return errors.New("工序顺序不符:工件已完成工序" + itoa(wp.CurrentProcess) +
",应在工位" + itoa(wp.CurrentProcess+1) + "报工,当前请求工位" + itoa(req.ProcessCode))
}
// 报工是"装机绑定→校验齐套→写实绩→写步骤考核→回写结果/工件状态"的多步写,必须整体事务化(方案 U3):
// 任一步失败全部回滚,杜绝"实绩已建但工件状态没推进/结果没落"的半成品脏数据;
// 校验(齐套/needCheck)也走同一 tx client,才能读到本事务内刚写入的绑定。
@@ -429,6 +439,56 @@ func (s *Service) Trace(ctx context.Context, sn string) (map[string]any, error)
}, nil
}
// ListProcessRecords 报工记录列表(分页):直接查真实报工表 workpiece_process
// 手动报工与工位终端报工都在此可见,形成报工闭环(取代已废弃的 scan_record 查询)。
func (s *Service) ListProcessRecords(ctx context.Context, sn, orderNo string, stationNo, page, pageSize int) ([]map[string]any, int, error) {
q := s.ctx.EntClient.WorkpieceProcess.Query()
if sn != "" {
q = q.Where(workpieceprocess.SnEqualFold(sn))
}
if orderNo != "" {
q = q.Where(workpieceprocess.OrderNoEqualFold(orderNo))
}
if stationNo > 0 {
q = q.Where(workpieceprocess.StationNo(itoa(stationNo)))
}
total, err := q.Count(ctx)
if err != nil {
return nil, 0, err
}
if page < 1 {
page = 1
}
if pageSize < 1 {
pageSize = 20
}
rows, err := q.Order(ent.Desc(workpieceprocess.FieldID)).
Offset((page - 1) * pageSize).Limit(pageSize).All(ctx)
if err != nil {
return nil, 0, err
}
list := make([]map[string]any, 0, len(rows))
for _, r := range rows {
ended := ""
if r.EndedAt != nil {
ended = r.EndedAt.Format("2006-01-02 15:04:05")
}
list = append(list, map[string]any{
"sn": r.Sn,
"orderNo": r.OrderNo,
"stationNo": r.StationNo,
"processCode": r.ProcessCode,
"processName": r.ProcessName,
"status": r.Status,
"result": r.Result,
"operator": r.Operator,
"durationSec": r.DurationSec,
"endedAt": ended,
})
}
return list, total, nil
}
func (s *Service) ListWorkpieces(ctx context.Context, sn, orderNo string) ([]*ent.Workpiece, error) {
q := s.ctx.EntClient.Workpiece.Query()
if sn != "" {