feat: 新增装机绑定功能与权限、BOM工序配置

1.  新增装机绑定实体与相关CRUD逻辑,支持工件工序物料绑定/解绑
2.  为BOM物料新增装配工序字段,支持按工序校验绑定
3.  扩展权限表,新增父权限码字段支持菜单按钮关联
4.  统一各页面帮助弹窗参数,新增角色管理帮助文档
5.  新增公共格式化工具函数,优化侧边栏菜单展开逻辑
6.  新增工位终端绑定代理接口与MES内部绑定API
7.  修复主入口数据库连接与schema初始化逻辑,新增一键迁移工具
This commit is contained in:
SunYF
2026-09-07 11:58:19 +08:00
parent 92f0439d89
commit 6ee131a4bd
70 changed files with 6966 additions and 365 deletions
+26 -2
View File
@@ -100,9 +100,12 @@ type ReportProcessReq struct {
ProcessCode int `json:"processCode"`
StationNo int `json:"stationNo"`
Steps []StepDataReq `json:"steps"`
Binds []BindItemReq `json:"binds"` // 装机绑定(本工序装配物料:结构件批次/精密件SN),随报工原子提交
}
// ReportProcess 工位报工:写报工实绩 + 步骤考核(step_data,扭矩在RANGE自动判定 OK/NG
// ReportProcess 工位报工:先应用装机绑定并做强校验(齐套才放行),再写报工实绩 + 步骤考核。
// 绑料是"落到工艺流程"的强约束:产品 BOM 中标记为本工序(processCode)的物料必须绑齐,
// 精密件按单台用量逐颗SN、结构件至少一个批次号;缺料直接拒绝报工并返回缺料清单。
func (s *Service) ReportProcess(ctx context.Context, req ReportProcessReq, operator string) error {
if req.Sn == "" || req.ProcessCode == 0 {
return errors.New("sn 与 processCode 必填")
@@ -111,6 +114,19 @@ func (s *Service) ReportProcess(ctx context.Context, req ReportProcessReq, opera
if err != nil {
return errors.New("工件未进线登记")
}
// 阶段1:装机绑定(随报工提交)→ 落库后强校验齐套
stationNo := ""
if req.StationNo > 0 {
stationNo = itoa(req.StationNo)
}
if _, err := s.applyBinds(ctx, req.Sn, wp.OrderNo, req.ProcessCode, stationNo, operator, req.Binds); err != nil {
return err
}
if miss, err := s.validateStationBinds(ctx, req.Sn, req.ProcessCode); err != nil {
return err
} else if miss != "" {
return errors.New(miss)
}
now := time.Now()
proc, err := s.ctx.EntClient.WorkpieceProcess.Create().
SetSn(req.Sn).SetProcessCode(req.ProcessCode).
@@ -177,12 +193,18 @@ type DoneReq struct {
SerialItems []string `json:"serialItems"` // 精密件SN
}
// DoneWorkpiece 完工:登记成品并生成关联追溯
// DoneWorkpiece 完工:先兜底校验全部工序装配物料齐套(工艺流程强校验),再登记成品并生成关联追溯
func (s *Service) DoneWorkpiece(ctx context.Context, req DoneReq, operator string) error {
wp, err := s.ctx.EntClient.Workpiece.Query().Where(workpiece.Sn(req.Sn)).First(ctx)
if err != nil {
return errors.New("工件不存在")
}
// 兜底强校验:工艺路线中每个工序的装配物料都须绑齐(BOM 未配置工序时自动放行)
if miss, err := s.validateAllProcessBinds(ctx, req.Sn); err != nil {
return err
} else if miss != "" {
return errors.New("完工前必须绑齐全部装配物料:" + miss)
}
now := time.Now()
_, _ = s.ctx.EntClient.Workpiece.UpdateOneID(wp.ID).
SetStatus("DONE").SetDoneAt(now).Save(ctx)
@@ -222,6 +244,7 @@ func (s *Service) Trace(ctx context.Context, sn string) (map[string]any, error)
Where(associationtrace.FinishedSn(sn)).First(ctx)
torque, _ := s.ctx.EntClient.TorqueRecord.Query().
Where(torquerecord.Sn(sn)).Order(ent.Desc(torquerecord.FieldTime)).Limit(200).All(ctx)
bindVO, _ := s.BuildBindTrace(ctx, sn)
return map[string]any{
"workpiece": wp,
@@ -229,6 +252,7 @@ func (s *Service) Trace(ctx context.Context, sn string) (map[string]any, error)
"stepData": steps,
"associationTrace": assoc,
"torqueRecords": torque,
"bindTrace": bindVO,
}, nil
}