Files
bj_power/bj_power_mes/internal/logic/route.go
T
SunYF d609ff8a9e refactor: 重构工艺工序相关命名与数据模型
1.  全局替换"工序"为"工艺"统一术语,包括页面文案、枚举、注释
2.  重构工单与工件工艺数据模型:
    - 新增工艺组合表flow_material作为备料/齐套唯一源头
    - 新增工位状态表station_state支持自主停单/恢复接单
    - 移除station_process派工表,改用工单工艺组合作为路线唯一源头
    - 替换processCode为flowId作为工艺关联标识
    - 重构工件当前进度字段为currentStationNo
3.  删除冗余的静态备份资源文件
4.  调整物料选择组件默认启用仅显示激活物料
5.  优化工单创建/编辑逻辑,新增工艺组合校验与保存
2026-09-22 11:32:29 +08:00

145 lines
4.7 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logic
import (
"context"
"errors"
"fmt"
"sort"
"strconv"
"strings"
"time"
"bj_power_mes/ent"
"bj_power_mes/ent/station"
)
// ---------- 工单工艺组合(work_order.flow_combination)路线派生 ----------
// TodayStr 当天日期 yyyy-MM-dd(工位停单只认当天)
func TodayStr() string { return time.Now().Format("2006-01-02") }
// FlowItem 工单工艺组合条目:工艺 + 工位(工位号即顺序号,按工位号升序执行)
type FlowItem struct {
FlowId int `json:"flowId"`
StationNo int `json:"stationNo"`
}
// RouteStationsFromWO 解析工单 flow_combination → 组合条目(按工位号升序;空组合返回空切片)
func RouteStationsFromWO(ctx context.Context, client *ent.Client, wo *ent.WorkOrder) ([]FlowItem, error) {
if wo == nil {
return nil, nil
}
items := flowMapsToItems(wo.FlowCombination)
sort.SliceStable(items, func(i, j int) bool { return items[i].StationNo < items[j].StationNo })
return items, nil
}
// flowMapsToItems jsonb 原始值 → 组合条目(过滤 flowId/stationNo 非正的脏条目)
func flowMapsToItems(raw []map[string]int) []FlowItem {
items := make([]FlowItem, 0, len(raw))
for _, m := range raw {
flowId, no := m["flowId"], m["stationNo"]
if flowId > 0 && no > 0 {
items = append(items, FlowItem{FlowId: flowId, StationNo: no})
}
}
return items
}
// flowItemsToMaps 组合条目 → jsonb 存储结构
func flowItemsToMaps(items []FlowItem) []map[string]int {
out := make([]map[string]int, 0, len(items))
for _, it := range items {
out = append(out, map[string]int{"flowId": it.FlowId, "stationNo": it.StationNo})
}
return out
}
// RouteStationsOfWO 组合条目 → 工位号列表(升序;未选工位即跳过)
func RouteStationsOfWO(items []FlowItem) []int {
out := make([]int, 0, len(items))
for _, it := range items {
out = append(out, it.StationNo)
}
return out
}
// RouteStationsStrOfWO 组合条目 → 路线串 "2,5,6,8"
func RouteStationsStrOfWO(items []FlowItem) string {
parts := make([]string, 0, len(items))
for _, it := range items {
parts = append(parts, strconv.Itoa(it.StationNo))
}
return strings.Join(parts, ",")
}
// StationFlowMapOfWO 组合条目 → 工位号→工艺ID
func StationFlowMapOfWO(items []FlowItem) map[int]int {
m := make(map[int]int, len(items))
for _, it := range items {
m[it.StationNo] = it.FlowId
}
return m
}
// ValidateFlowCombination 保存工单时校验工艺组合:
// 非空、工艺存在且启用(ACTIVE)、工位存在、工位号不重复;返回按工位号升序的条目。
func (s *Service) ValidateFlowCombination(ctx context.Context, raw []map[string]int) ([]FlowItem, error) {
items := flowMapsToItems(raw)
if len(items) == 0 {
return nil, errors.New("请先选择工艺组合(至少一条 工艺+工位)")
}
sort.SliceStable(items, func(i, j int) bool { return items[i].StationNo < items[j].StationNo })
seen := map[int]bool{}
for _, it := range items {
if seen[it.StationNo] {
return nil, fmt.Errorf("工位 %d 在工艺组合中重复", it.StationNo)
}
seen[it.StationNo] = true
flow, err := s.ctx.EntClient.ProcessFlow.Get(ctx, it.FlowId)
if err != nil {
return nil, fmt.Errorf("工艺不存在(ID=%d", it.FlowId)
}
if flow.Status != "ACTIVE" {
return nil, fmt.Errorf("工艺「%s」已停用", flow.Name)
}
exist, err := s.ctx.EntClient.Station.Query().Where(station.StationNo(it.StationNo)).Exist(ctx)
if err != nil {
return nil, err
}
if !exist {
return nil, fmt.Errorf("工位 %d 不存在", it.StationNo)
}
}
return items, nil
}
// ValidateWOCombinationForSchedule 排产前校验(工单组合是唯一路线源头,排产只继承不可改):
// 组合为空不可排产;组合里每个工位当前绑定工艺必须与工单一致且工位启用。
func (s *Service) ValidateWOCombinationForSchedule(ctx context.Context, wo *ent.WorkOrder) error {
items, _ := RouteStationsFromWO(ctx, s.ctx.EntClient, wo)
if len(items) == 0 {
return errors.New("请先在工单中选择工艺组合,才能排产")
}
for _, it := range items {
st, err := s.ctx.EntClient.Station.Query().Where(station.StationNo(it.StationNo)).First(ctx)
if err != nil {
return fmt.Errorf("工位 %d 不存在", it.StationNo)
}
if st.FlowId != it.FlowId || st.Status != "ENABLED" {
return fmt.Errorf("工位%d当前工艺与工单不匹配", it.StationNo)
}
}
return nil
}
// flowNameById 工艺名称(查不到回退「工艺{id}」)
func (s *Service) flowNameById(ctx context.Context, id int) string {
if id > 0 {
if f, err := s.ctx.EntClient.ProcessFlow.Get(ctx, id); err == nil && f.Name != "" {
return f.Name
}
}
return "工艺" + strconv.Itoa(id)
}