Files
bj_power/bj_power_mes/cmd/mockrun/main.go
T

187 lines
4.7 KiB
Go
Raw Normal View History

// mockrun: 使用 Mock PLC + Mock Marking 完整模拟订单执行流程。
// 用法: go run cmd/mockrun/main.go -jobs 4 -docks 1,2 -product 2
package main
import (
"context"
"flag"
"fmt"
"log/slog"
"os"
"strconv"
"strings"
"time"
xlog "bj_power_mes/common/logx"
"bj_power_mes/constants"
"bj_power_mes/ent/job"
"bj_power_mes/ent/recipestep"
"bj_power_mes/internal/config"
"bj_power_mes/internal/svc"
"github.com/zeromicro/go-zero/core/conf"
)
var (
flagJobs = flag.Int("jobs", 12, "工件数量")
flagProduct = flag.Int("product", 1, "产品类型 ID")
flagStep = flag.Int("step", 0, "初始步骤索引(0=从第一步开始,4=从清洗机上料开始)")
flagTimeout = flag.Duration("timeout", 120*time.Minute, "超时时间")
)
func main() {
flag.Parse()
slog.Info("=== Mock 订单模拟启动 ===",
"jobs", *flagJobs, "product", *flagProduct)
// 1. 加载配置
var c config.Config
conf.MustLoad("etc/bj_power_mes-api.yaml", &c)
logger := xlog.NewLogger(c.Logger)
xlog.SetDefault(logger)
//if !c.Mock.Enable {
// fmt.Println("错误: Mock.Enable 必须为 true")
// os.Exit(1)
//}
c.Mock.MockRun = true
// 2. 创建 ServiceContextMock 模式下已自动清空旧数据)
fmt.Println("正在初始化 ServiceContext...")
svcCtx := svc.NewServiceContext(c)
time.Sleep(2 * time.Second)
ctx := context.Background()
// 3. 加载工艺路线
recipe, err := svcCtx.RecipeLoader.Load(ctx, *flagProduct)
if err != nil {
slog.Error("加载工艺路线失败", "error", err)
os.Exit(1)
}
fmt.Printf("工艺路线: %s (%d步)\n", recipe.RecipeCode, recipe.TotalSteps)
firstStepIdx := recipe.Steps[0].StepIndex
// 4. 创建工单 + 工件
order, err := svcCtx.EntClient.WorkOrder.Create().
SetProductTypeId(*flagProduct).
SetQuantity(*flagJobs).
SetStatus(constants.WorkOrderStatus_Created).
Save(ctx)
if err != nil {
slog.Error("创建工单失败", "error", err)
os.Exit(1)
}
fmt.Printf("工单已创建: id=%d\n", order.ID)
// 确定初始步骤索引
initialStepIdx := firstStepIdx
if *flagStep > 0 {
initialStepIdx = *flagStep
}
initialStepID := ""
if step, err := svcCtx.EntClient.RecipeStep.Query().
Where(recipestep.RecipeIdEQ(recipe.RecipeID), recipestep.StepIndexEQ(initialStepIdx)).
First(ctx); err == nil {
initialStepID = step.StepId
}
for i := 1; i <= *flagJobs; i++ {
dockNo := (i-1)/9 + 1
slotIdx := (i-1)%9 + 1
jobCreate := svcCtx.EntClient.Job.Create().
SetWorkOrderId(order.ID).
SetProductTypeId(*flagProduct).
SetRecipeID(recipe.RecipeID).
SetCurrentStepId(initialStepID)
if *flagStep > 0 && i <= 8 {
// 跳过前置步骤:工件在暂存台,状态为 Processing
jobCreate = jobCreate.
SetPositionType(constants.PositionType_OnBuffer).
SetPositionRefId(fmt.Sprintf("%d", i)).
SetTempSlotNo(i).
SetStatus(constants.JobStatus_Processing)
} else {
// 正常流程:工件在接驳台
jobCreate = jobCreate.
SetPositionType(constants.PositionType_OnDock).
SetPositionRefId(fmt.Sprintf("%d:%d", dockNo, slotIdx)).
SetDockNo(dockNo).
SetDockSlotNo(slotIdx).
SetStatus(constants.JobStatus_Created)
}
_, err = jobCreate.Save(ctx)
if err != nil {
slog.Error("创建工件失败", "id", i, "error", err)
os.Exit(1)
}
}
if *flagStep > 0 {
fmt.Printf("已创建 %d 个工件(跳过前置步骤,从 step %d 开始,暂存台位置)\n", *flagJobs, *flagStep)
} else {
fmt.Printf("已创建 %d 个工件 \n",
*flagJobs)
}
// 6. 启动工单
if err := svcCtx.OrderProcessor.StartOrder(ctx, order.ID); err != nil {
slog.Error("启动工单失败", "error", err)
os.Exit(1)
}
slog.Info("工单已启动", "orderId", order.ID)
// 7. 轮询直到全部完成
deadline := time.Now().Add(*flagTimeout)
ticker := time.NewTicker(30 * time.Second)
defer ticker.Stop()
done := false
for !done && time.Now().Before(deadline) {
<-ticker.C
jobs, err := svcCtx.EntClient.Job.Query().
Where(job.WorkOrderIdEQ(order.ID)).
All(ctx)
if err != nil {
continue
}
allDone := true
for _, j := range jobs {
if string(j.Status) != string(constants.JobStatus_Completed) &&
string(j.Status) != string(constants.JobStatus_Scrapped) {
allDone = false
}
}
if allDone {
done = true
}
}
if !done {
fmt.Println("超时!")
} else {
fmt.Println("\n===== 全部完成 =====")
}
fmt.Printf("共运行 %d 个工件\n", *flagJobs)
}
// parseIntList 解析逗号分隔的整数列表
func parseIntList(s string) []int {
parts := strings.Split(s, ",")
var result []int
for _, p := range parts {
p = strings.TrimSpace(p)
if n, err := strconv.Atoi(p); err == nil && n > 0 {
result = append(result, n)
}
}
return result
}