from tortoise import fields from .base import BaseModel, TimestampMixin from .enums import TaskStatus, TaskType, ActionType, TaskStatus, ScenarioScope class Scenario(BaseModel, TimestampMixin): title = fields.CharField(max_length=255, description="场景标题", index=True) trigger = fields.JSONField(description="触发条件(事件/时间)") actions = fields.JSONField(default=list, description="执行动作模板列表") visible = fields.BooleanField(default=True, description="是否可见", index=True) notes = fields.TextField(null=True, description="备注") is_global = fields.BooleanField(default=True, description="是否全局场景", index=True) owner_user_id = fields.CharField(max_length=64, null=True, description="归属用户ID(非全局时有效)", index=True) enabled = fields.BooleanField(default=True, description="是否启用", index=True) scope = fields.CharEnumField(ScenarioScope, default=ScenarioScope.ALL, description="作用角色范围", index=True) due_days = fields.IntField(null=True, description="截止时间(天)") class Meta: table = "automation_scenario" indexes = [ ["is_global", "enabled"], ["owner_user_id", "enabled"], ] """ CREATE TABLE automation_scenario_trigger_index ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, scenario_id BIGINT NOT NULL, event_name VARCHAR(64) NOT NULL COMMENT '监听的事件名,如 group_chat_updated', enabled TINYINT(1) NOT NULL DEFAULT 1, is_global TINYINT(1) NOT NULL DEFAULT 1, owner_user_id VARCHAR(64) DEFAULT NULL, scope VARCHAR(8) NOT NULL DEFAULT 'all', PRIMARY KEY (id), KEY idx_event_enabled (event_name, enabled), KEY idx_scenario_id (scenario_id), CONSTRAINT fk_scenario_def FOREIGN KEY (scenario_id) REFERENCES automation_scenario(id) ON DELETE CASCADE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; """ class ScenarioTriggerIndex(BaseModel, TimestampMixin): scenario_id = fields.BigIntField(description="场景ID") type = fields.CharEnumField(TaskType, default=TaskType.EVENT, description="事件类型", index=True) event_name = fields.CharField(max_length=64, description="监听的事件名,如 group_chat_updated", index=True) enabled = fields.BooleanField(default=True, description="是否启用", index=True) is_global = fields.BooleanField(default=True, description="是否全局场景", index=True) owner_user_id = fields.CharField(max_length=64, null=True, description="归属用户ID(非全局时有效)", index=True) scope = fields.CharEnumField(ScenarioScope, default=ScenarioScope.ALL, description="作用角色范围") class Meta: table = "automation_scenario_trigger_index" class Task(BaseModel, TimestampMixin): title = fields.CharField(max_length=255, description="待办标题", index=True) event_data = fields.JSONField(default=dict, description="事件数据") notes = fields.TextField(null=True, description="备注") reason = fields.TextField(null=True, description="触发原因") completed_at = fields.DatetimeField(null=True, description="完成时间") # 关联字段 source_scenario = fields.ForeignKeyField( "models.Scenario", related_name="generated_tasks", null=True, on_delete=fields.SET_NULL, description="来源场景" ) related_order_id = fields.CharField(max_length=64, null=True, description="关联订单ID", index=True) owner_user_id = fields.CharField(max_length=64, null=True, description="归属用户ID", index=True) # 分配与状态 assignee_user_id = fields.CharField(max_length=64, null=True, description="指派人用户ID", index=True) assignee_username = fields.CharField(max_length=64, null=True, description="指派人用户名", index=True) status = fields.CharEnumField(TaskStatus, default=TaskStatus.PENDING, description="任务状态", index=True) # 自动化控制 due_at = fields.DatetimeField(null=True, description="截止时间") auto_closeable = fields.BooleanField(default=True, description="是否允许自动消除") closed_by = fields.CharField(max_length=32, null=True, description="关闭方式: manual/auto/expired", index=True) class Meta: table = "automation_task" indexes = [ ["assignee_user_id", "status"], ] class Action(BaseModel, TimestampMixin): type = fields.CharEnumField(ActionType, null=True, description="操作类型", index=True) detail = fields.JSONField(default={}, description="操作详情") done = fields.BooleanField(default=False, description="是否已完成", index=True) done_at = fields.DatetimeField(null=True, description="完成时间") result = fields.JSONField(default={}, description="操作结果") userid = fields.CharField(max_length=64, null=True, description="操作用户ID", index=True) username = fields.CharField(max_length=64, null=True, description="操作用户名称", index=True) notes = fields.TextField(null=True, description="操作备注") # 硬外键:必须属于一个 Task task = fields.ForeignKeyField( "models.Task", related_name="actions", null=True, # ← 允许为空 on_delete=fields.SET_NULL, # ← 注意:CASCADE 不能和 null=True 同时用于 SET_NULL description="所属任务" ) # 可选:记录来自哪个动作模板(场景中的定义) action_template_id = fields.CharField(max_length=64, null=True, description="操作模板ID", index=True) class Meta: table = "automation_action" indexes = [ ["task_id", "done"], # 优化查询未完成动作 ["type", "done"], ]