refactor: 重构产线工位与备料流程,移除冗余字段
1. 移除工单、工件、日排产中的冗余工位组合/接驳台字段 2. 新增工位接驳台编码字段与唯一约束,关联WMS接驳台主数据 3. 重构日排产为工位产量分配模式,替代原接驳台列表 4. 新增备料单工位级字段与分批出库支持 5. 移除定时同步可生产数量,改为WMS实时拉取接口 6. 过滤操作日志,排除登录/退出相关日志 7. 调整仪表盘工序展示逻辑为今日派工路线 8. 新增接驳台维护菜单与基础数据
This commit is contained in:
@@ -4,12 +4,11 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"bj_power_mes/ent"
|
||||
"bj_power_mes/ent/dailyplan"
|
||||
"bj_power_mes/ent/station"
|
||||
"bj_power_mes/ent/workorder"
|
||||
"bj_power_mes/ent/workpiece"
|
||||
)
|
||||
@@ -23,13 +22,13 @@ func parseDate(v string) (time.Time, error) {
|
||||
}
|
||||
|
||||
type DailyPlanReq struct {
|
||||
Id int `json:"id"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
PlanDate string `json:"planDate"`
|
||||
PlanQty int `json:"planQty"`
|
||||
CompletedQty int `json:"completedQty"`
|
||||
Status string `json:"status"`
|
||||
DockCodes []string `json:"dockCodes"`
|
||||
Id int `json:"id"`
|
||||
OrderNo string `json:"orderNo"`
|
||||
PlanDate string `json:"planDate"`
|
||||
PlanQty int `json:"planQty"`
|
||||
CompletedQty int `json:"completedQty"`
|
||||
Status string `json:"status"`
|
||||
StationPlanQty map[string]int `json:"stationPlanQty"` // 工位号(字符串键)→计划产量分配;缺省按路线均分
|
||||
// 批量排产(新建时与 PlanDate 二选一):日期范围 [start,end] + 分摊模式
|
||||
PlanRange []string `json:"planRange"` // [start,end] yyyy-MM-dd,批量生成多条日排产
|
||||
Mode string `json:"mode"` // AVG(平均分摊)/FIXED(固定日产);单条保存时忽略
|
||||
@@ -60,6 +59,10 @@ func (s *Service) SaveDailyPlan(ctx context.Context, req DailyPlanReq, operator
|
||||
if req.PlanDate == "" {
|
||||
return errors.New("排产日期必填")
|
||||
}
|
||||
spq := req.StationPlanQty
|
||||
if spq == nil {
|
||||
spq = map[string]int{}
|
||||
}
|
||||
cur, err := s.ctx.EntClient.DailyPlan.Query().
|
||||
Where(dailyplan.OrderNo(req.OrderNo)).All(ctx)
|
||||
if err != nil {
|
||||
@@ -101,24 +104,19 @@ func (s *Service) SaveDailyPlan(ctx context.Context, req DailyPlanReq, operator
|
||||
status = exist.Status
|
||||
}
|
||||
_, err = s.ctx.EntClient.DailyPlan.UpdateOneID(exist.ID).
|
||||
SetOrderNo(req.OrderNo).SetPlanDate(req.PlanDate).SetPlanQty(req.PlanQty).SetStatus(status).
|
||||
SetDockCodes(dockCodes(req.DockCodes)).Save(ctx)
|
||||
SetOrderNo(req.OrderNo).SetPlanDate(req.PlanDate).SetPlanQty(req.PlanQty).SetStatus(status).SetStationPlanQty(spq).Save(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
_, err = s.ctx.EntClient.DailyPlan.Create().
|
||||
SetOrderNo(req.OrderNo).SetPlanDate(req.PlanDate).SetPlanQty(req.PlanQty).
|
||||
SetStatus(status).SetOperator(operator).SetDockCodes(dockCodes(req.DockCodes)).Save(ctx)
|
||||
SetStatus(status).SetStationPlanQty(spq).SetOperator(operator).Save(ctx)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
// 记录该工单本次使用的接驳台到工单 context,供下次排产默认推荐
|
||||
if len(dockCodes(req.DockCodes)) > 0 {
|
||||
s.rememberOrderDocks(ctx, req.OrderNo, dockCodes(req.DockCodes))
|
||||
}
|
||||
s.ctx.EventLog.Write(ctx, "daily.plan.save", req.OrderNo, operator, "daily_plan", req.OrderNo, "保存日排产", map[string]any{"planDate": req.PlanDate, "planQty": req.PlanQty, "dockCodes": req.DockCodes})
|
||||
s.ctx.EventLog.Write(ctx, "daily.plan.save", req.OrderNo, operator, "daily_plan", req.OrderNo, "保存日排产", map[string]any{"planDate": req.PlanDate, "planQty": req.PlanQty})
|
||||
s.notifyDashboard()
|
||||
return nil
|
||||
}
|
||||
@@ -188,82 +186,42 @@ func (s *Service) saveDailyPlanBatch(ctx context.Context, req DailyPlanReq, oper
|
||||
continue
|
||||
}
|
||||
_, err = s.ctx.EntClient.DailyPlan.UpdateOneID(existOne.ID).
|
||||
SetPlanQty(q).SetStatus("PENDING").SetOperator(operator).Save(ctx)
|
||||
SetPlanQty(q).SetStatus("PENDING").SetStationPlanQty(map[string]int{}).SetOperator(operator).Save(ctx)
|
||||
} else {
|
||||
_, err = s.ctx.EntClient.DailyPlan.Create().
|
||||
SetOrderNo(req.OrderNo).SetPlanDate(ds).SetPlanQty(q).
|
||||
SetStatus("PENDING").SetOperator(operator).SetDockCodes(dockCodes(req.DockCodes)).Save(ctx)
|
||||
SetStatus("PENDING").SetStationPlanQty(map[string]int{}).SetOperator(operator).Save(ctx)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if len(dockCodes(req.DockCodes)) > 0 {
|
||||
s.rememberOrderDocks(ctx, req.OrderNo, dockCodes(req.DockCodes))
|
||||
}
|
||||
s.ctx.EventLog.Write(ctx, "daily.plan.batch", req.OrderNo, operator, "daily_plan", req.OrderNo,
|
||||
"日排产批量生成", map[string]any{"days": days, "total": sum, "mode": req.Mode, "quota": quota})
|
||||
s.notifyDashboard()
|
||||
return nil
|
||||
}
|
||||
|
||||
// dockCodes 规范化接驳台列表:仅保留 DOCK01..DOCK20 / DOCK21,去重、保持顺序
|
||||
func dockCodes(codes []string) []string {
|
||||
seen := map[string]bool{}
|
||||
out := []string{}
|
||||
for _, c := range codes {
|
||||
c = strings.TrimSpace(c)
|
||||
if !validDockCode(c) || seen[c] {
|
||||
continue
|
||||
}
|
||||
seen[c] = true
|
||||
out = append(out, c)
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// validDockCode DOCK01..DOCK21
|
||||
func validDockCode(c string) bool {
|
||||
if len(c) != 6 || !strings.HasPrefix(c, "DOCK") {
|
||||
return false
|
||||
}
|
||||
n, err := strconv.Atoi(c[4:])
|
||||
return err == nil && n >= 1 && n <= 21
|
||||
}
|
||||
|
||||
// rememberOrderDocks 把工单「上次使用的接驳台」写入 work_order.context,供下次排产默认推荐
|
||||
func (s *Service) rememberOrderDocks(ctx context.Context, orderNo string, docks []string) {
|
||||
if len(docks) == 0 {
|
||||
return
|
||||
}
|
||||
wo, err := s.ctx.EntClient.WorkOrder.Query().Where(workorder.WorkOrderNo(orderNo)).Only(ctx)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
c := wo.Context
|
||||
if c == nil {
|
||||
c = map[string]any{}
|
||||
}
|
||||
c["lastDockCodes"] = docks
|
||||
_ = s.ctx.EntClient.WorkOrder.UpdateOneID(wo.ID).SetContext(c).Exec(ctx)
|
||||
}
|
||||
|
||||
// SuggestedDockCodes 查某工单「上次使用的接驳台」,供排产默认推荐
|
||||
// SuggestedDockCodes 查今日工位派工(station_process)路线覆盖的接驳台编码(DOCKxx),供排产/备料默认推荐。
|
||||
// 路线由工位派工定义,接驳台由各派工工位引用(station.dockCode),因此可直接由路线派生。
|
||||
func (s *Service) SuggestedDockCodes(ctx context.Context, orderNo string) []string {
|
||||
wo, err := s.ctx.EntClient.WorkOrder.Query().Where(workorder.WorkOrderNo(orderNo)).Only(ctx)
|
||||
route, err := RouteStations(ctx, s.ctx.EntClient, TodayStr(), "")
|
||||
if err != nil || len(route) == 0 {
|
||||
return nil
|
||||
}
|
||||
sts, err := s.ctx.EntClient.Station.Query().Where(station.StationNoIn(route...)).All(ctx)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
if v, ok := wo.Context["lastDockCodes"].([]any); ok {
|
||||
out := []string{}
|
||||
for _, x := range v {
|
||||
if s2, ok := x.(string); ok {
|
||||
out = append(out, s2)
|
||||
}
|
||||
seen := map[string]bool{}
|
||||
out := []string{}
|
||||
for _, st := range sts {
|
||||
if st.DockCode != "" && !seen[st.DockCode] {
|
||||
seen[st.DockCode] = true
|
||||
out = append(out, st.DockCode)
|
||||
}
|
||||
return out
|
||||
}
|
||||
return nil
|
||||
return out
|
||||
}
|
||||
|
||||
// syncPlansByOrderStatus 工单状态联动日排产:
|
||||
|
||||
Reference in New Issue
Block a user