155 lines
5.1 KiB
Go
155 lines
5.1 KiB
Go
package models
|
||
|
||
import (
|
||
"fmt"
|
||
"sort"
|
||
"time"
|
||
|
||
"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;constraint:OnDelete:CASCADE;" 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 {
|
||
// 手动定义字段以将 ID 类型设置为 int,以匹配 TaskExecutionLog 中的 TaskID
|
||
ID int `gorm:"primarykey"`
|
||
CreatedAt time.Time
|
||
UpdatedAt time.Time
|
||
DeletedAt gorm.DeletedAt `gorm:"index"` // 保持软删除功能
|
||
|
||
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"
|
||
}
|