refactor: 重构工艺工序相关命名与数据模型
1. 全局替换"工序"为"工艺"统一术语,包括页面文案、枚举、注释
2. 重构工单与工件工艺数据模型:
- 新增工艺组合表flow_material作为备料/齐套唯一源头
- 新增工位状态表station_state支持自主停单/恢复接单
- 移除station_process派工表,改用工单工艺组合作为路线唯一源头
- 替换processCode为flowId作为工艺关联标识
- 重构工件当前进度字段为currentStationNo
3. 删除冗余的静态备份资源文件
4. 调整物料选择组件默认启用仅显示激活物料
5. 优化工单创建/编辑逻辑,新增工艺组合校验与保存
This commit is contained in:
@@ -0,0 +1,144 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user