tdm_server_rust/web/
task_tracking_controller.rs1use crate::utils::query_deserialize::{
7 de_opt_csv_i32, de_opt_csv_intern, de_opt_csv_string, de_opt_datetime, de_opt_string, de_page,
8 de_page_size,
9};
10use crate::{
11 app::AppState,
12 common::{
13 page_bean::PageBean,
14 result::{json_bytes_response, ResultBody},
15 },
16 entity::episode::{PendingMangaTask, WorkflowEpisodeItem},
17 error::ApiResult,
18 repository::workflow_filter::WorkflowEpisodeQuery,
19 service::task_tracking_service::TaskTrackingService,
20};
21use axum::{
22 extract::{Query, State},
23 response::Response,
24 routing::get,
25 Router,
26};
27use serde::Deserialize;
28
29#[derive(Debug, Deserialize)]
31#[serde(rename_all = "camelCase")]
32pub struct WorkflowEpisodesQuery {
33 pub status: String,
35 pub aspect: String,
37 pub steps: String,
39 #[serde(default, deserialize_with = "de_opt_string")]
41 pub manga_tran_name: Option<String>,
42 #[serde(default, deserialize_with = "de_opt_csv_i32")]
44 pub manga_ids: Option<Vec<i32>>,
45 #[serde(default, deserialize_with = "de_opt_csv_i32")]
47 pub member_ids: Option<Vec<i32>>,
48 #[serde(default, deserialize_with = "de_opt_csv_intern")]
50 pub intern_ids: Option<Vec<Option<i32>>>,
51 #[serde(default, deserialize_with = "de_opt_datetime")]
53 pub previous_update_time_after: Option<chrono::DateTime<chrono::Utc>>,
54 #[serde(default, deserialize_with = "de_opt_csv_string")]
56 pub step_filter: Option<Vec<String>>,
57 #[serde(default, deserialize_with = "de_page")]
59 pub page: i32,
60 #[serde(default, deserialize_with = "de_page_size")]
62 pub page_size: i32,
63 #[serde(default, deserialize_with = "de_opt_string")]
65 pub sort_prop: Option<String>,
66 #[serde(default, deserialize_with = "de_opt_string")]
68 pub sort_order: Option<String>,
69}
70
71#[derive(Debug, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct PendingMangaQuery {
75 #[serde(default, deserialize_with = "de_page")]
77 pub page: i32,
78 #[serde(default, deserialize_with = "de_page_size")]
80 pub page_size: i32,
81 #[serde(default, deserialize_with = "de_opt_string")]
83 pub manga_tran_name: Option<String>,
84}
85
86pub fn routes() -> Router<AppState> {
88 Router::new()
89 .route("/memberTaskCounts", get(get_member_task_counts))
90 .route("/episodeTasks", get(get_episode_tasks))
91 .route("/pendingMangaTasks", get(get_pending_manga_tasks))
92 .route("/workflowEpisodes", get(get_workflow_episodes))
93}
94
95#[tracing::instrument(skip_all, level = "info")]
97pub async fn get_member_task_counts(State(state): State<AppState>) -> ApiResult<Response> {
98 let json = TaskTrackingService::get_member_task_counts_json(&state).await?;
99 Ok(json_bytes_response(json))
100}
101
102#[tracing::instrument(skip_all, level = "info")]
104pub async fn get_episode_tasks(State(state): State<AppState>) -> ApiResult<Response> {
105 let json = TaskTrackingService::get_episode_tasks_json(&state).await?;
106 Ok(json_bytes_response(json))
107}
108
109#[tracing::instrument(skip_all, level = "info")]
111pub async fn get_pending_manga_tasks(
112 State(state): State<AppState>,
113 Query(q): Query<PendingMangaQuery>,
114) -> ApiResult<ResultBody<PageBean<PendingMangaTask>>> {
115 let data = TaskTrackingService::get_pending_manga_tasks(
116 &state,
117 q.page,
118 q.page_size,
119 q.manga_tran_name,
120 )
121 .await?;
122 Ok(ResultBody::success_data(data))
123}
124
125#[tracing::instrument(skip_all, level = "info")]
127pub async fn get_workflow_episodes(
128 State(state): State<AppState>,
129 Query(q): Query<WorkflowEpisodesQuery>,
130) -> ApiResult<ResultBody<PageBean<WorkflowEpisodeItem>>> {
131 let steps: Vec<String> = q
132 .steps
133 .split(',')
134 .map(|s| s.trim().to_string())
135 .filter(|s| !s.is_empty())
136 .collect();
137 let query = WorkflowEpisodeQuery {
138 status: q.status,
139 aspect: q.aspect,
140 steps,
141 manga_tran_name: q.manga_tran_name,
142 manga_ids: q.manga_ids,
143 member_ids: q.member_ids,
144 intern_ids: q.intern_ids,
145 previous_update_time_after: q.previous_update_time_after,
146 step_filter: q.step_filter,
147 page: q.page,
148 page_size: q.page_size,
149 sort_prop: q.sort_prop,
150 sort_order: q.sort_order,
151 };
152 let data = TaskTrackingService::get_workflow_episodes(&state, query).await?;
153 Ok(ResultBody::success_data(data))
154}