Files
pig-farm-controller/internal/infra/models/plan.go
2025-09-14 15:18:35 +08:00

150 lines
4.9 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 models
import (
"fmt"
"sort"
"gorm.io/datatypes"
"gorm.io/gorm"
)
// PlanExecutionType 定义了计划的执行类型
type PlanExecutionType string
const (
PlanExecutionTypeAutomatic PlanExecutionType = "automatic" // 自动执行 (包含定时和循环)
PlanExecutionTypeManual PlanExecutionType = "manual" // 手动执行
)
// PlanContentType 定义了计划包含的内容类型
type PlanContentType string
const (
PlanContentTypeSubPlans PlanContentType = "sub_plans" // 计划包含子计划
PlanContentTypeTasks PlanContentType = "tasks" // 计划包含任务
)
// TaskType 定义了任务的类型,每个类型可以对应 task 包中的一个具体动作
type TaskType string
const (
TaskTypeWaiting TaskType = "waiting" // 等待任务
)
// Plan 代表系统中的一个计划,可以包含子计划或任务
type Plan struct {
gorm.Model
Name string `gorm:"not null" json:"name"`
Description string `json:"description"`
ExecutionType PlanExecutionType `gorm:"not null" json:"execution_type"`
// 针对 PlanExecutionTypeAutomatic使用 Cron 表达式定义调度规则
CronExpression string `json:"cron_expression"`
// ContentType 标识此计划是包含子计划还是任务。
// 应用程序层应确保只设置其中一种类型的内容。
ContentType PlanContentType `gorm:"not null" json:"content_type"`
// SubPlans 直接与此计划关联的子计划。仅当 ContentType 为 PlanContentTypeSubPlans 时有效。
SubPlans []SubPlan `gorm:"foreignKey:ParentPlanID" json:"sub_plans"`
// Tasks 直接与此计划关联的任务。仅当 ContentType 为 PlanContentTypeTasks 时有效。
Tasks []Task `gorm:"foreignKey:PlanID" json:"tasks"`
}
// TableName 自定义 GORM 使用的数据库表名
func (Plan) TableName() string {
return "plans"
}
// ValidateExecutionOrder 校验计划中的步骤或子计划顺序不能有重复的
func (p Plan) ValidateExecutionOrder() error {
orderMap := make(map[int]bool)
switch p.ContentType {
case PlanContentTypeTasks:
for _, task := range p.Tasks {
if orderMap[task.ExecutionOrder] {
return fmt.Errorf("任务执行顺序重复: %d", task.ExecutionOrder)
}
orderMap[task.ExecutionOrder] = true
}
case PlanContentTypeSubPlans:
for _, subPlan := range p.SubPlans {
if orderMap[subPlan.ExecutionOrder] {
return fmt.Errorf("子计划执行顺序重复: %d", subPlan.ExecutionOrder)
}
orderMap[subPlan.ExecutionOrder] = true
}
}
return nil
}
// ReorderSteps 重新排序计划中的步骤(任务或子计划),使其 ExecutionOrder 从 1 开始且连续。
// 这个方法假设重复的顺序已经被其他方法验证过它只负责修复断层和不从1开始的序列。
func (p *Plan) ReorderSteps() {
switch p.ContentType {
case PlanContentTypeTasks:
if len(p.Tasks) == 0 {
return
}
// 1. 按当前的 ExecutionOrder 对任务进行排序
sort.Slice(p.Tasks, func(i, j int) bool {
return p.Tasks[i].ExecutionOrder < p.Tasks[j].ExecutionOrder
})
// 2. 重新分配连续的 ExecutionOrder
for i := range p.Tasks {
p.Tasks[i].ExecutionOrder = i + 1
}
case PlanContentTypeSubPlans:
if len(p.SubPlans) == 0 {
return
}
// 1. 按当前的 ExecutionOrder 对子计划进行排序
sort.Slice(p.SubPlans, func(i, j int) bool {
return p.SubPlans[i].ExecutionOrder < p.SubPlans[j].ExecutionOrder
})
// 2. 重新分配连续的 ExecutionOrder
for i := range p.SubPlans {
p.SubPlans[i].ExecutionOrder = i + 1
}
}
}
// SubPlan 代表作为另一个计划一部分的子计划,具有执行顺序
type SubPlan struct {
gorm.Model
ParentPlanID uint `gorm:"not null;index" json:"parent_plan_id"` // 父计划的ID
ChildPlanID uint `gorm:"not null;index" json:"child_plan_id"` // 子计划的ID (它本身也是一个 Plan)
ExecutionOrder int `gorm:"not null" json:"execution_order"` // 在父计划中的执行顺序
ChildPlan *Plan `gorm:"-" json:"child_plan"` // 完整子计划数据,仅内存中
}
// TableName 自定义 GORM 使用的数据库表名
func (SubPlan) TableName() string {
return "sub_plans"
}
// Task 代表计划中的一个任务,具有执行顺序
type Task struct {
gorm.Model
PlanID uint `gorm:"not null;index" json:"plan_id"` // 此任务所属计划的ID
Name string `gorm:"not null" json:"name"`
Description string `json:"description"`
ExecutionOrder int `gorm:"not null" json:"execution_order"` // 在计划中的执行顺序
Type TaskType `gorm:"not null" json:"type"` // 任务的类型,对应 task 包中的具体动作
Parameters datatypes.JSON `json:"parameters"` // 任务特定参数的JSON (例如: 设备ID, 值)
}
// TableName 自定义 GORM 使用的数据库表名
func (Task) TableName() string {
return "tasks"
}