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

187 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.
// 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
}