424 lines
15 KiB
Python
424 lines
15 KiB
Python
|
|
#!/usr/bin/env python3
|
|||
|
|
"""
|
|||
|
|
数据模型和 ORM 定义
|
|||
|
|
使用 SQLAlchemy 定义数据库表结构
|
|||
|
|
"""
|
|||
|
|
import threading
|
|||
|
|
from datetime import datetime
|
|||
|
|
from sqlalchemy import create_engine, Column, Integer, String, Float, DateTime, Boolean, JSON, Enum, Text
|
|||
|
|
from sqlalchemy.ext.declarative import declarative_base
|
|||
|
|
from sqlalchemy.orm import sessionmaker
|
|||
|
|
from typing import Callable, Dict, List, Any, Optional
|
|||
|
|
import enum
|
|||
|
|
import json
|
|||
|
|
|
|||
|
|
# 创建基类
|
|||
|
|
Base = declarative_base()
|
|||
|
|
db_lock = threading.RLock()
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WorkflowStatus(enum.Enum):
|
|||
|
|
"""工作流状态"""
|
|||
|
|
READY = "ready" # 就绪
|
|||
|
|
RUNNING = "running" # 运行中
|
|||
|
|
PAUSED = "paused" # 暂停
|
|||
|
|
COMPLETED = "completed" # 已完成
|
|||
|
|
FAILED = "failed" # 失败
|
|||
|
|
CANCELLED = "cancelled" # 已取消
|
|||
|
|
|
|||
|
|
|
|||
|
|
class TaskStatus(enum.Enum):
|
|||
|
|
"""任务状态"""
|
|||
|
|
PENDING = "pending" # 待处理
|
|||
|
|
RUNNING = "running" # 运行中
|
|||
|
|
COMPLETED = "completed" # 已完成
|
|||
|
|
FAILED = "failed" # 失败
|
|||
|
|
SKIPPED = "skipped" # 已跳过
|
|||
|
|
CANCELLED = "cancelled" # 已取消
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
# 系统配置表
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class SystemConfig(Base):
|
|||
|
|
"""系统配置"""
|
|||
|
|
__tablename__ = "system_config"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
key = Column(String(100), unique=True, nullable=False, index=True)
|
|||
|
|
value = Column(Text, nullable=False)
|
|||
|
|
description = Column(String(500))
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<SystemConfig {self.key}={self.value[:50]}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"key": self.key,
|
|||
|
|
"value": self.value,
|
|||
|
|
"description": self.description,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
class Project(Base):
|
|||
|
|
"""项目表"""
|
|||
|
|
__tablename__ = "project_table"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
#任务名称
|
|||
|
|
name = Column(String(500),default="")
|
|||
|
|
#任务创建者
|
|||
|
|
creator= Column(String(500),default="")
|
|||
|
|
#任务描述
|
|||
|
|
description= Column(String(1000),default="")
|
|||
|
|
#工作流+草稿+作者,组成一个项目。此处保存工作流的UUID和草稿的UUID
|
|||
|
|
corr_workflow= Column(String(500),default="")
|
|||
|
|
corr_draft= Column(String(500),default="")
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<Project {self.name}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"name": self.name,
|
|||
|
|
"creator": self.creator,
|
|||
|
|
"description": self.description,
|
|||
|
|
"corr_workflow": self.corr_workflow,
|
|||
|
|
"corr_draft": self.corr_draft,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
class WorkFlow(Base):
|
|||
|
|
"""任务表"""
|
|||
|
|
__tablename__ = "workflow_table"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
#工作流UUID
|
|||
|
|
uuid= Column(String(500),default="")
|
|||
|
|
#工作流名称
|
|||
|
|
name = Column(String(500),default="")
|
|||
|
|
#任务创建者
|
|||
|
|
creator= Column(String(500),default="")
|
|||
|
|
#工作流描述
|
|||
|
|
description= Column(String(1000),default="")
|
|||
|
|
#具体工作流内容,JSON格式保存
|
|||
|
|
content= Column(JSON, default=dict)
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<WorkFlow {self.name}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"name": self.name,
|
|||
|
|
"creator": self.creator,
|
|||
|
|
"description": self.description,
|
|||
|
|
"content": self.content,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
class Draft(Base):
|
|||
|
|
"""草稿表"""
|
|||
|
|
__tablename__ = "draft_table"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
#草稿UUID
|
|||
|
|
uuid= Column(String(500),default="")
|
|||
|
|
#草稿名称
|
|||
|
|
name = Column(String(500),default="")
|
|||
|
|
#草稿创建者
|
|||
|
|
creator= Column(String(500),default="")
|
|||
|
|
#草稿描述
|
|||
|
|
description= Column(String(1000),default="")
|
|||
|
|
#具体草稿内容,JSON格式保存
|
|||
|
|
content= Column(JSON, default=dict)
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<Draft {self.name}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"name": self.name,
|
|||
|
|
"creator": self.creator,
|
|||
|
|
"discription": self.discription,
|
|||
|
|
"content": self.content,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
class User(Base):
|
|||
|
|
"""用户表"""
|
|||
|
|
__tablename__ = "user_table"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
username = Column(String(500),default="")
|
|||
|
|
password= Column(String(500),default="")
|
|||
|
|
role= Column(String(500),default="") #admin/user/guest
|
|||
|
|
discription= Column(String(1000),default="")
|
|||
|
|
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<User {self.username}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"username": self.username,
|
|||
|
|
"password": self.password,
|
|||
|
|
"role": self.role,
|
|||
|
|
"discription": self.discription,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
# 工作流执行实例表
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class WorkflowInstance(Base):
|
|||
|
|
"""工作流执行实例"""
|
|||
|
|
__tablename__ = "workflow_instances"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
workflow_uuid = Column(String(500))
|
|||
|
|
workflow_name = Column(String(500))
|
|||
|
|
|
|||
|
|
status = Column(Enum(WorkflowStatus), default=WorkflowStatus.READY)
|
|||
|
|
|
|||
|
|
# 执行参数
|
|||
|
|
parameters = Column(JSON, default=dict)
|
|||
|
|
|
|||
|
|
# 执行结果和输出
|
|||
|
|
result = Column(JSON, default=dict)
|
|||
|
|
|
|||
|
|
#临时数据区
|
|||
|
|
temp_data=Column(JSON, default=dict)
|
|||
|
|
|
|||
|
|
# 当前步骤
|
|||
|
|
current_step_params = Column(JSON, default=dict)
|
|||
|
|
current_step_index = Column(Integer, default=0)
|
|||
|
|
current_step_content = Column(JSON, default=dict)
|
|||
|
|
current_step_result = Column(JSON, default=dict)
|
|||
|
|
|
|||
|
|
# 已完成的步骤
|
|||
|
|
completed_steps = Column(JSON, default=list)
|
|||
|
|
|
|||
|
|
# 失败信息
|
|||
|
|
error_message = Column(Text)
|
|||
|
|
error_traceback = Column(Text)
|
|||
|
|
|
|||
|
|
# 重试次数
|
|||
|
|
retry_count = Column(Integer, default=0)
|
|||
|
|
max_retries = Column(Integer, default=3)
|
|||
|
|
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
started_at = Column(DateTime)
|
|||
|
|
completed_at = Column(DateTime)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<WorkflowInstance {self.workflow_name} #{self.id}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"workflow_uuid": self.workflow_uuid,
|
|||
|
|
"workflow_name": self.workflow_name,
|
|||
|
|
"status": self.status.value if self.status else None,
|
|||
|
|
"parameters": self.parameters,
|
|||
|
|
"result": self.result,
|
|||
|
|
"temp_data": self.temp_data,
|
|||
|
|
"current_step_params": self.current_step_params,
|
|||
|
|
"current_step_index": self.current_step_index,
|
|||
|
|
"current_step_content": self.current_step_content,
|
|||
|
|
"current_step_result": self.current_step_result,
|
|||
|
|
"completed_steps": self.completed_steps,
|
|||
|
|
"error_message": self.error_message,
|
|||
|
|
"error_traceback": self.error_traceback,
|
|||
|
|
"retry_count": self.retry_count,
|
|||
|
|
"max_retries": self.max_retries,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"started_at": self.started_at.isoformat() if self.started_at else None,
|
|||
|
|
"completed_at": self.completed_at.isoformat() if self.completed_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
# 操作日志表
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class OperationLog(Base):
|
|||
|
|
"""操作日志"""
|
|||
|
|
__tablename__ = "operation_logs"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
|
|||
|
|
# 操作类型: "create", "update", "delete", "execute", etc.
|
|||
|
|
operation_type = Column(String(50), nullable=False, index=True)
|
|||
|
|
|
|||
|
|
# 操作对象: "workflow", "task", etc.
|
|||
|
|
object_type = Column(String(50), nullable=False)
|
|||
|
|
object_id = Column(Integer)
|
|||
|
|
object_name = Column(String(100))
|
|||
|
|
|
|||
|
|
# 操作详情
|
|||
|
|
details = Column(JSON, default=dict)
|
|||
|
|
|
|||
|
|
# 操作者 (用户或系统)
|
|||
|
|
operator = Column(String(100), default="system")
|
|||
|
|
|
|||
|
|
# 操作结果
|
|||
|
|
status = Column(String(50)) # "success", "failure"
|
|||
|
|
error_message = Column(Text)
|
|||
|
|
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow, index=True)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<OperationLog {self.operation_type} {self.object_type} #{self.object_id}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"operation_type": self.operation_type,
|
|||
|
|
"object_type": self.object_type,
|
|||
|
|
"object_id": self.object_id,
|
|||
|
|
"object_name": self.object_name,
|
|||
|
|
"details": self.details,
|
|||
|
|
"operator": self.operator,
|
|||
|
|
"status": self.status,
|
|||
|
|
"error_message": self.error_message,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
# 测试表
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class Test(Base):
|
|||
|
|
"""测试表"""
|
|||
|
|
__tablename__ = "test_tb"
|
|||
|
|
|
|||
|
|
id = Column(Integer, primary_key=True)
|
|||
|
|
name = Column(String(500),default="")
|
|||
|
|
value = Column(String(500),default="")
|
|||
|
|
|
|||
|
|
|
|||
|
|
created_at = Column(DateTime, default=datetime.utcnow)
|
|||
|
|
updated_at = Column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
|
|||
|
|
|
|||
|
|
def __repr__(self):
|
|||
|
|
return f"<Workflow {self.value}>"
|
|||
|
|
|
|||
|
|
def to_dict(self):
|
|||
|
|
return {
|
|||
|
|
"id": self.id,
|
|||
|
|
"name": self.name,
|
|||
|
|
"value": self.value,
|
|||
|
|
"created_at": self.created_at.isoformat() if self.created_at else None,
|
|||
|
|
"updated_at": self.updated_at.isoformat() if self.updated_at else None,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
# 数据库初始化和会话管理
|
|||
|
|
# ═══════════════════════════════════════════════════════════════════════════
|
|||
|
|
|
|||
|
|
class DatabaseManager:
|
|||
|
|
"""数据库管理器"""
|
|||
|
|
|
|||
|
|
def __init__(self, database_url: str = "sqlite:///hy02d_system.db"):
|
|||
|
|
"""
|
|||
|
|
初始化数据库管理器
|
|||
|
|
|
|||
|
|
Args:
|
|||
|
|
database_url: 数据库连接字符串
|
|||
|
|
- SQLite: "sqlite:///path/to/db.db"
|
|||
|
|
- MySQL: "mysql+pymysql://user:password@host:port/dbname"
|
|||
|
|
- PostgreSQL: "postgresql://user:password@host:port/dbname"
|
|||
|
|
"""
|
|||
|
|
self.database_url = database_url
|
|||
|
|
self.engine = None
|
|||
|
|
self.Session = None
|
|||
|
|
self._lock=threading.RLock()
|
|||
|
|
|
|||
|
|
def initialize(self):
|
|||
|
|
"""初始化数据库"""
|
|||
|
|
self.engine = create_engine(
|
|||
|
|
self.database_url,
|
|||
|
|
echo=False, # 设置为 True 查看 SQL 语句
|
|||
|
|
pool_pre_ping=True # 测试连接有效性
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
# 创建所有表
|
|||
|
|
Base.metadata.create_all(self.engine)
|
|||
|
|
|
|||
|
|
# 创建会话工厂
|
|||
|
|
self.Session = sessionmaker(bind=self.engine)
|
|||
|
|
|
|||
|
|
print(f"✓ 数据库已初始化: {self.database_url}")
|
|||
|
|
|
|||
|
|
def get_session(self):
|
|||
|
|
"""获取数据库会话"""
|
|||
|
|
if self.Session is None:
|
|||
|
|
raise RuntimeError("数据库尚未初始化,请先调用 initialize()")
|
|||
|
|
return self.Session()
|
|||
|
|
|
|||
|
|
def close(self):
|
|||
|
|
"""关闭数据库连接"""
|
|||
|
|
if self.engine:
|
|||
|
|
self.engine.dispose()
|
|||
|
|
print("✓ 数据库连接已关闭")
|
|||
|
|
|
|||
|
|
|
|||
|
|
# 全局数据库管理器实例
|
|||
|
|
_db_manager:Optional[DatabaseManager] = None
|
|||
|
|
|
|||
|
|
def get_db_manager() -> DatabaseManager:
|
|||
|
|
"""
|
|||
|
|
获取或创建全局数据库管理器实例
|
|||
|
|
|
|||
|
|
Returns:
|
|||
|
|
数据库管理器实例
|
|||
|
|
"""
|
|||
|
|
global _db_manager
|
|||
|
|
with db_lock:
|
|||
|
|
if _db_manager is None:
|
|||
|
|
_db_manager = DatabaseManager()
|
|||
|
|
return _db_manager
|
|||
|
|
|
|||
|
|
|
|||
|
|
def reset_db_manager() -> None:
|
|||
|
|
"""重置全局数据库管理器实例(用于测试)"""
|
|||
|
|
global _db_manager
|
|||
|
|
_db_manager = None
|
|||
|
|
|
|||
|
|
|
|||
|
|
|