package logic import ( "context" "errors" "fmt" "strings" "bj_power_mes/ent" "bj_power_mes/ent/stationstate" "bj_power_mes/ent/workorder" ) // ---------- 工位停单(station_state,只认当天) ---------- // SetStationPause 工人自主停单/恢复(某工位当天停止/恢复接单)。 // upsert:stationNo+date 唯一;恢复=标记可用即续走,工单/组合/排产三要素零变动。 // 停单瞬间做「工艺全停」判定:某工艺绑定的全部工位当天都停单 → 报警(flow_all_paused)+事件日志。 func (s *Service) SetStationPause(ctx context.Context, stationNo int, paused bool, reason, operator string) error { if stationNo <= 0 { return errors.New("stationNo 必填") } date := TodayStr() exist, err := s.ctx.EntClient.StationState.Query(). Where(stationstate.StationNo(stationNo), stationstate.Date(date)).Only(ctx) if err != nil && !ent.IsNotFound(err) { return err } if exist == nil { if err := s.ctx.EntClient.StationState.Create(). SetStationNo(stationNo).SetDate(date).SetPaused(paused). SetReason(reason).SetOperator(operator).Exec(ctx); err != nil { return err } } else { if err := s.ctx.EntClient.StationState.UpdateOneID(exist.ID). SetPaused(paused).SetReason(reason).SetOperator(operator).Exec(ctx); err != nil { return err } } action := "工位恢复接单" eventType := "station.respawn" if paused { action = "工位停止接单(停单)" eventType = "station.pause" } s.ctx.EventLog.Write(ctx, eventType, "", operator, "station_state", itoa(stationNo), fmt.Sprintf("%s(工位%d,%s)", action, stationNo, date), map[string]any{"stationNo": stationNo, "date": date, "paused": paused, "reason": reason}) if paused { s.checkAllPausedFlows(ctx, operator) } return nil } // checkAllPausedFlows 工艺全停判定:执行中工单的组合里,某工艺涉及的全部工位当天都停单 → 报警+日志。 // (上位机在该工艺全停期间不下发流转指令;恢复=任一工位恢复即续走。) func (s *Service) checkAllPausedFlows(ctx context.Context, operator string) { wos, err := s.ctx.EntClient.WorkOrder.Query(). Where(workorder.Status("IN_PROGRESS")).All(ctx) if err != nil { return } for _, wo := range wos { items, _ := RouteStationsFromWO(ctx, s.ctx.EntClient, wo) if len(items) == 0 { continue } byFlow := map[int][]int{} for _, it := range items { byFlow[it.FlowId] = append(byFlow[it.FlowId], it.StationNo) } for flowId, stations := range byFlow { allPaused := len(stations) > 0 parts := make([]string, 0, len(stations)) for _, no := range stations { parts = append(parts, itoa(no)) if !s.GetStationPaused(ctx, no) { allPaused = false } } if !allPaused { continue } content := fmt.Sprintf("工艺「%s」的全部工位(%s)已停单,上位机不下发流转指令", s.flowNameById(ctx, flowId), strings.Join(parts, ",")) _, _ = s.ctx.EntClient.Alert.Create(). SetRuleId(0).SetType("flow_all_paused").SetTitle("工艺全停"). SetContent(content).SetRefType("process_flow").SetRefId(fmt.Sprintf("%d", flowId)). SetOrderNo(wo.WorkOrderNo).SetReceiver("").SetStatus("UNREAD").Save(ctx) s.ctx.EventLog.Write(ctx, "flow.all_paused", wo.WorkOrderNo, operator, "process_flow", itoa(flowId), content, map[string]any{"flowId": flowId, "stations": stations}) } } } // GetStationPaused 某工位当天是否停单(无记录=未停单) func (s *Service) GetStationPaused(ctx context.Context, stationNo int) bool { if stationNo <= 0 { return false } rows, err := s.ctx.EntClient.StationState.Query(). Where(stationstate.StationNo(stationNo), stationstate.Date(TodayStr()), stationstate.Paused(true)). Limit(1).All(ctx) return err == nil && len(rows) > 0 } // ListStationStates 查询停单状态列表(date 空取当天) func (s *Service) ListStationStates(ctx context.Context, date string) ([]*ent.StationState, error) { if date == "" { date = TodayStr() } return s.ctx.EntClient.StationState.Query(). Where(stationstate.Date(date)). Order(ent.Asc(stationstate.FieldStationNo)).All(ctx) }