feat: 实现定时任务系统
All checks were successful
continuous-integration/drone/push Build is passing

- 新增 platform_scheduled_tasks, platform_task_logs, platform_script_vars, platform_secrets 数据库表
- 实现 ScriptSDK 提供 AI/通知/DB/HTTP/变量存储/参数获取等功能
- 实现安全的脚本执行器,支持沙箱环境和禁止危险操作
- 实现 APScheduler 调度服务,支持简单时间点和 CRON 表达式
- 新增定时任务 API 路由,包含 CRUD、执行、日志、密钥管理
- 新增定时任务前端页面,支持脚本编辑、测试运行、日志查看
This commit is contained in:
2026-01-28 16:38:19 +08:00
parent 7806072b17
commit 104487f082
19 changed files with 1870 additions and 5406 deletions

View File

@@ -23,18 +23,6 @@ class ToolItem(BaseModel):
path: str
class ConfigSchemaItem(BaseModel):
"""配置项定义"""
key: str # 配置键
label: str # 显示标签
type: str # text | radio | select | switch
options: Optional[List[str]] = None # radio/select 的选项值
option_labels: Optional[dict] = None # 选项显示名称 {"value": "显示名"}
default: Optional[str] = None # 默认值
placeholder: Optional[str] = None # 输入提示text类型
required: bool = False # 是否必填
class AppCreate(BaseModel):
"""创建应用"""
app_code: str
@@ -42,7 +30,6 @@ class AppCreate(BaseModel):
base_url: Optional[str] = None
description: Optional[str] = None
tools: Optional[List[ToolItem]] = None
config_schema: Optional[List[ConfigSchemaItem]] = None
require_jssdk: bool = False
@@ -52,7 +39,6 @@ class AppUpdate(BaseModel):
base_url: Optional[str] = None
description: Optional[str] = None
tools: Optional[List[ToolItem]] = None
config_schema: Optional[List[ConfigSchemaItem]] = None
require_jssdk: Optional[bool] = None
status: Optional[int] = None
@@ -133,7 +119,6 @@ async def create_app(
base_url=data.base_url,
description=data.description,
tools=json.dumps([t.model_dump() for t in data.tools], ensure_ascii=False) if data.tools else None,
config_schema=json.dumps([c.model_dump() for c in data.config_schema], ensure_ascii=False) if data.config_schema else None,
require_jssdk=1 if data.require_jssdk else 0,
status=1
)
@@ -165,13 +150,6 @@ async def update_app(
else:
update_data['tools'] = None
# 处理 config_schema JSON
if 'config_schema' in update_data:
if update_data['config_schema']:
update_data['config_schema'] = json.dumps([c.model_dump() if hasattr(c, 'model_dump') else c for c in update_data['config_schema']], ensure_ascii=False)
else:
update_data['config_schema'] = None
# 处理 require_jssdk
if 'require_jssdk' in update_data:
update_data['require_jssdk'] = 1 if update_data['require_jssdk'] else 0
@@ -281,21 +259,6 @@ async def get_app_tools(
return tools
@router.get("/{app_code}/config-schema")
async def get_app_config_schema(
app_code: str,
user: User = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""获取应用的配置项定义(用于租户订阅时渲染表单)"""
app = db.query(App).filter(App.app_code == app_code).first()
if not app:
raise HTTPException(status_code=404, detail="应用不存在")
config_schema = json.loads(app.config_schema) if app.config_schema else []
return config_schema
def format_app(app: App) -> dict:
"""格式化应用数据"""
return {
@@ -305,7 +268,6 @@ def format_app(app: App) -> dict:
"base_url": app.base_url,
"description": app.description,
"tools": json.loads(app.tools) if app.tools else [],
"config_schema": json.loads(app.config_schema) if app.config_schema else [],
"require_jssdk": bool(app.require_jssdk),
"status": app.status,
"created_at": app.created_at,