Files
udmin/backend/src/routes/schedule_jobs.rs
ayou 8c06849254 feat(调度任务): 实现调度任务管理功能
新增调度任务模块,支持任务的增删改查、启停及手动执行
- 后端添加 schedule_job 模型、服务、路由及调度器工具类
- 前端新增调度任务管理页面
- 修改 flow 相关接口将 id 类型从 String 改为 i64
- 添加 tokio-cron-scheduler 依赖实现定时任务调度
- 初始化时加载已启用任务并注册到调度器
2025-09-24 00:21:30 +08:00

76 lines
4.0 KiB
Rust

use axum::{Router, routing::{get, post, put}, extract::{State, Path, Query}, Json};
use crate::{db::Db, error::AppError, response::ApiResponse, services::{schedule_job_service, flow_service}, models::schedule_job};
use crate::middlewares::jwt::AuthUser;
use sea_orm::{EntityTrait};
pub fn router() -> Router<Db> {
Router::new()
.route("/schedule_jobs", get(list).post(create))
.route("/schedule_jobs/{id}", put(update).delete(remove))
// 新增:独立启停端点
.route("/schedule_jobs/{id}/enable", post(enable))
.route("/schedule_jobs/{id}/disable", post(disable))
// 新增:手动执行端点
.route("/schedule_jobs/{id}/execute", post(execute))
}
async fn list(State(db): State<Db>, Query(p): Query<schedule_job_service::ListParams>) -> Result<Json<ApiResponse<schedule_job_service::PageResp<schedule_job_service::ScheduleJobDoc>>>, AppError> {
let res = schedule_job_service::list(&db, p).await?;
Ok(Json(ApiResponse::ok(res)))
}
#[derive(serde::Deserialize)]
struct CreateReq { name: String, cron_expr: String, enabled: bool, flow_code: String }
async fn create(State(db): State<Db>, _user: AuthUser, Json(req): Json<CreateReq>) -> Result<Json<ApiResponse<schedule_job_service::ScheduleJobDoc>>, AppError> {
let res = schedule_job_service::create(&db, schedule_job_service::CreateReq { name: req.name, cron_expr: req.cron_expr, enabled: req.enabled, flow_code: req.flow_code }).await?;
Ok(Json(ApiResponse::ok(res)))
}
#[derive(serde::Deserialize)]
struct UpdateReq { name: Option<String>, cron_expr: Option<String>, enabled: Option<bool>, flow_code: Option<String> }
async fn update(State(db): State<Db>, _user: AuthUser, Path(id): Path<String>, Json(req): Json<UpdateReq>) -> Result<Json<ApiResponse<schedule_job_service::ScheduleJobDoc>>, AppError> {
let res = schedule_job_service::update(&db, &id, schedule_job_service::UpdateReq { name: req.name, cron_expr: req.cron_expr, enabled: req.enabled, flow_code: req.flow_code }).await?;
Ok(Json(ApiResponse::ok(res)))
}
async fn remove(State(db): State<Db>, _user: AuthUser, Path(id): Path<String>) -> Result<Json<ApiResponse<serde_json::Value>>, AppError> {
schedule_job_service::remove(&db, &id).await?;
Ok(Json(ApiResponse::ok(serde_json::json!({}))))
}
// 新增:启用指定任务(不需要请求体)
async fn enable(State(db): State<Db>, _user: AuthUser, Path(id): Path<String>) -> Result<Json<ApiResponse<schedule_job_service::ScheduleJobDoc>>, AppError> {
let res = schedule_job_service::update(&db, &id, schedule_job_service::UpdateReq { name: None, cron_expr: None, enabled: Some(true), flow_code: None }).await?;
Ok(Json(ApiResponse::ok(res)))
}
// 新增:禁用指定任务(不需要请求体)
async fn disable(State(db): State<Db>, _user: AuthUser, Path(id): Path<String>) -> Result<Json<ApiResponse<schedule_job_service::ScheduleJobDoc>>, AppError> {
let res = schedule_job_service::update(&db, &id, schedule_job_service::UpdateReq { name: None, cron_expr: None, enabled: Some(false), flow_code: None }).await?;
Ok(Json(ApiResponse::ok(res)))
}
// 新增:手动执行指定任务
async fn execute(State(db): State<Db>, user: AuthUser, Path(id): Path<String>) -> Result<Json<ApiResponse<serde_json::Value>>, AppError> {
// 1) 获取任务信息
let job = schedule_job::Entity::find_by_id(id.to_string())
.one(&db)
.await?
.ok_or(AppError::NotFound)?;
// 2) 通过 flow_code 获取流程
let flow_doc = flow_service::get_by_code(&db, &job.flow_code).await
.map_err(flow_service::ae)?;
// 3) 执行流程(使用空输入,操作者为当前用户)
let result = flow_service::run(
&db,
flow_doc.id,
flow_service::RunReq { input: serde_json::json!({}) },
Some((user.uid, user.username)),
).await.map_err(flow_service::ae)?;
Ok(Json(ApiResponse::ok(serde_json::to_value(result).map_err(|e| AppError::BadRequest(e.to_string()))?)))
}