Skip to main content

tdm_server_rust/entity/
manga.rs

1//! 漫画相关实体 (Manga Entities)
2//!
3//! 定义漫画管理的全部数据结构:
4//! - 漫画核心实体: [`Mangatb`] (数据库行), [`Manga`] (内部 POJO), [`MangaResponse`] (API 响应)
5//! - VO/DTO: [`MangaCardVo`], [`MangaSimpleVo`], [`MangaDetailVo`]
6//! - 特典: [`MangaBenefitDto`], [`VolumeVo`], [`StoreBenefitVo`], [`MangaBenefitItemVo`]
7//! - 术语表: [`GlossaryVo`], [`GlossaryRequest`]
8//! - 收藏: [`MangaCollect`], [`CollectedMembersVo`]
9//! - 常驻/下载请求: [`AddStationRequest`], [`EpisodeDownloadRequest`]
10
11use chrono::{DateTime, Utc};
12use serde::{Deserialize, Serialize};
13
14/// 漫画实体 (Manga Table Row)
15///
16/// 映射 `t_manga` 表,用于数据库 CRUD 操作。
17/// 对应 Java `Mangatb` 类,常用于 `PendingMangaTask` 等场景。
18#[derive(Debug, Clone, Serialize, Deserialize, Default)]
19#[serde(rename_all = "camelCase")]
20pub struct Mangatb {
21    /// 漫画 ID
22    pub id: Option<i32>,
23    /// 译名
24    pub manga_tran_name: Option<String>,
25    /// 原名
26    pub manga_ori_name: Option<String>,
27    /// 封面
28    pub image: Option<String>,
29    /// 分类
30    pub category: Option<i32>,
31    /// 状态
32    pub manga_status: Option<i32>,
33    /// 开坑时间
34    pub setup_time: Option<DateTime<Utc>>,
35    /// 更新时间
36    pub update_time: Option<DateTime<Utc>>,
37    /// 原著链接
38    pub link: Option<String>,
39    /// 简介
40    pub introduction: Option<String>,
41}
42
43/// 漫画卡片视图 (Manga Card View Object)
44///
45/// 用于列表、收藏、常驻卡片等场景的统一展示格式。
46/// 包含漫画基本信息 + 各岗位的最新接稿/交稿时间。
47///
48/// 同时作为 [`MangaListVo`] 的类型别名使用。
49#[derive(Debug, Clone, Serialize, Deserialize, Default)]
50#[serde(rename_all = "camelCase")]
51pub struct MangaCardVo {
52    /// 漫画 ID
53    pub id: i32,
54    /// 译名
55    pub manga_tran_name: Option<String>,
56    /// 原名
57    pub manga_ori_name: Option<String>,
58    /// 封面路径
59    pub image: Option<String>,
60    /// 分类
61    pub category: Option<i16>,
62    /// 状态
63    pub manga_status: Option<i16>,
64    /// 更新时间
65    pub update_time: Option<DateTime<Utc>>,
66    /// 原作作者名
67    #[serde(skip_serializing_if = "Option::is_none")]
68    pub author_name: Option<String>,
69    /// 作画作者名
70    #[serde(skip_serializing_if = "Option::is_none")]
71    pub author_name2: Option<String>,
72    /// 作画作者 ID
73    #[serde(skip_serializing_if = "Option::is_none")]
74    pub author_id2: Option<i32>,
75    /// 杂志名
76    #[serde(skip_serializing_if = "Option::is_none")]
77    pub magazine_name: Option<String>,
78    /// 翻译接稿时间
79    #[serde(skip_serializing_if = "Option::is_none")]
80    pub translator_setup_time: Option<DateTime<Utc>>,
81    /// 翻译交稿时间
82    #[serde(skip_serializing_if = "Option::is_none")]
83    pub translator_update_time: Option<DateTime<Utc>>,
84    /// 校对接稿时间
85    #[serde(skip_serializing_if = "Option::is_none")]
86    pub proofreader_setup_time: Option<DateTime<Utc>>,
87    /// 校对交稿时间
88    #[serde(skip_serializing_if = "Option::is_none")]
89    pub proofreader_update_time: Option<DateTime<Utc>>,
90    /// 嵌字接稿时间
91    #[serde(skip_serializing_if = "Option::is_none")]
92    pub letterer_setup_time: Option<DateTime<Utc>>,
93    /// 嵌字交稿时间
94    #[serde(skip_serializing_if = "Option::is_none")]
95    pub letterer_update_time: Option<DateTime<Utc>>,
96    /// 审稿接稿时间
97    #[serde(skip_serializing_if = "Option::is_none")]
98    pub reviewer_setup_time: Option<DateTime<Utc>>,
99    /// 审稿交稿时间
100    #[serde(skip_serializing_if = "Option::is_none")]
101    pub reviewer_update_time: Option<DateTime<Utc>>,
102    /// 时轴接稿时间
103    #[serde(skip_serializing_if = "Option::is_none")]
104    pub timer_setup_time: Option<DateTime<Utc>>,
105    /// 时轴交稿时间
106    #[serde(skip_serializing_if = "Option::is_none")]
107    pub timer_update_time: Option<DateTime<Utc>>,
108}
109
110/// 漫画列表 VO
111pub type MangaListVo = MangaCardVo;
112
113/// 漫画简 VO
114#[derive(Debug, Clone, Serialize, Deserialize, Default)]
115#[serde(rename_all = "camelCase")]
116pub struct MangaSimpleVo {
117    /// 漫画 ID
118    pub id: i32,
119    /// 译名
120    #[serde(skip_serializing_if = "Option::is_none")]
121    pub manga_tran_name: Option<String>,
122    /// 原名
123    #[serde(skip_serializing_if = "Option::is_none")]
124    pub manga_ori_name: Option<String>,
125}
126
127/// 漫画详情 VO
128#[derive(Debug, Clone, Serialize, Deserialize, Default)]
129#[serde(rename_all = "camelCase")]
130pub struct MangaDetailVo {
131    /// 漫画 ID
132    pub id: i32,
133    /// 译名
134    pub manga_tran_name: Option<String>,
135    /// 原名
136    pub manga_ori_name: Option<String>,
137    /// 封面路径
138    pub image: Option<String>,
139    /// 分类
140    pub category: Option<i16>,
141    /// 状态
142    pub manga_status: Option<i16>,
143    /// 开坑时间
144    pub setup_time: Option<DateTime<Utc>>,
145    /// 更新时间
146    pub update_time: Option<DateTime<Utc>>,
147    /// 原著链接
148    pub link: Option<String>,
149    /// 简介
150    pub introduction: Option<String>,
151    /// 原作作者名
152    pub author_name: Option<String>,
153    /// 原作作者 ID
154    pub author_id: Option<i32>,
155    /// 作画作者名
156    pub author_name2: Option<String>,
157    /// 作画作者 ID
158    pub author_id2: Option<i32>,
159    /// 杂志名
160    pub magazine_name: Option<String>,
161    /// 杂志 ID
162    pub magazine_id: Option<i32>,
163}
164
165/// 漫画 POJO(对齐 Java Manga,用于常驻漫画等 API 响应)
166#[derive(Debug, Clone, Serialize, Deserialize, Default)]
167#[serde(rename_all = "camelCase")]
168pub struct MangaResponse {
169    /// 漫画 ID
170    pub id: Option<i32>,
171    /// 译名
172    pub manga_tran_name: Option<String>,
173    /// 原名
174    pub manga_ori_name: Option<String>,
175    /// 封面
176    pub image: Option<String>,
177    /// 分类
178    pub category: Option<i16>,
179    /// 状态
180    pub manga_status: Option<i16>,
181    /// 开坑时间
182    pub setup_time: Option<DateTime<Utc>>,
183    /// 更新时间
184    pub update_time: Option<DateTime<Utc>>,
185    /// 原著链接
186    pub link: Option<String>,
187    /// 简介
188    pub introduction: Option<String>,
189    /// 原作作者名
190    pub author_name: Option<String>,
191    /// 原作作者 ID
192    pub author_id: Option<i32>,
193    /// 作画作者名
194    pub author_name2: Option<String>,
195    /// 作画作者 ID
196    pub author_id2: Option<i32>,
197    /// 杂志名
198    pub magazine_name: Option<String>,
199    /// 杂志 ID
200    pub magazine_id: Option<i32>,
201    /// 翻译接稿时间
202    pub translator_setup_time: Option<DateTime<Utc>>,
203    /// 翻译交稿时间
204    pub translator_update_time: Option<DateTime<Utc>>,
205    /// 校对接稿时间
206    pub proofreader_setup_time: Option<DateTime<Utc>>,
207    /// 校对交稿时间
208    pub proofreader_update_time: Option<DateTime<Utc>>,
209    /// 嵌字接稿时间
210    pub letterer_setup_time: Option<DateTime<Utc>>,
211    /// 嵌字交稿时间
212    pub letterer_update_time: Option<DateTime<Utc>>,
213    /// 审稿接稿时间
214    pub reviewer_setup_time: Option<DateTime<Utc>>,
215    /// 审稿交稿时间
216    pub reviewer_update_time: Option<DateTime<Utc>>,
217}
218
219/// 漫画 POJO(内部仓储用,字段较少)
220#[derive(Debug, Clone, Serialize, Deserialize, Default)]
221#[serde(rename_all = "camelCase")]
222pub struct Manga {
223    /// 漫画 ID
224    #[serde(rename = "Id")]
225    pub id: Option<i32>,
226    /// 译名
227    pub manga_tran_name: Option<String>,
228    /// 原名
229    pub manga_ori_name: Option<String>,
230    /// 分类
231    pub category: Option<i16>,
232    /// 状态
233    pub manga_status: Option<i16>,
234    /// 封面
235    pub img_url: Option<String>,
236    /// 原著链接
237    pub link: Option<String>,
238    /// 简介
239    pub introduction: Option<String>,
240    /// 更新时间
241    pub update_time: Option<DateTime<Utc>>,
242}
243
244/// 漫画收藏
245#[derive(Debug, Clone, Serialize, Deserialize)]
246#[serde(rename_all = "camelCase")]
247pub struct MangaCollect {
248    /// ID
249    pub id: Option<i32>,
250    /// 漫画 ID
251    pub manga_id: i32,
252    /// 组员 ID
253    pub member_id: i32,
254}
255
256/// 收藏组员 VO
257#[derive(Debug, Clone, Serialize, Deserialize, Default)]
258#[serde(rename_all = "camelCase")]
259pub struct CollectedMembersVo {
260    /// 组员 ID
261    pub id: i32,
262    /// 用户名
263    pub username: Option<String>,
264    /// 职阶
265    pub intern: i16,
266    /// 岗位列表
267    pub posts: Vec<crate::entity::member::Post>,
268    /// 常驻计数
269    pub station_count: Option<i32>,
270    /// 注册时间
271    pub registration_time: Option<DateTime<Utc>>,
272    /// 最近交稿时间
273    pub last_submit_time: Option<DateTime<Utc>>,
274}
275
276/// 术语表视图 (Glossary View Object)
277///
278/// 对应漫画汉化组术语翻译对照表,包含原文、翻译、示意截图等信息。
279/// 字段 `r#type` 区分术语类型(人名/地名/专有名词等)。
280#[derive(Debug, Clone, Serialize, Deserialize, Default)]
281#[serde(rename_all = "camelCase")]
282pub struct GlossaryVo {
283    /// ID
284    pub id: i32,
285    /// 原文
286    pub title: Option<String>,
287    /// 翻译/说明
288    pub content: Option<String>,
289    /// 示意截图路径
290    pub image: Option<String>,
291    /// 类型
292    pub r#type: Option<i16>,
293    /// 漫画 ID
294    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
295    pub manga_id: Option<i16>,
296    /// 首次出现话数
297    pub first: Option<String>,
298    /// 更新时间
299    pub update_time: Option<DateTime<Utc>>,
300    /// 更新者 ID
301    pub update_by: Option<i32>,
302    /// 更新者用户名
303    pub update_member_name: Option<String>,
304}
305
306/// 术语表请求
307#[derive(Debug, Clone, Deserialize, Default)]
308#[serde(rename_all = "camelCase")]
309pub struct GlossaryRequest {
310    /// ID
311    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
312    pub id: Option<i32>,
313    /// 原文
314    pub title: Option<String>,
315    /// 翻译/说明
316    pub content: Option<String>,
317    /// 示意截图路径
318    pub image: Option<String>,
319    /// 类型
320    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
321    pub r#type: Option<i16>,
322    /// 漫画 ID
323    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
324    pub manga_id: Option<i16>,
325    /// 首次出现话数
326    pub first: Option<String>,
327    /// 更新时间
328    pub update_time: Option<DateTime<Utc>>,
329    /// 更新者 ID
330    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
331    pub update_by: Option<i32>,
332    /// 更新者用户名
333    pub update_member_name: Option<String>,
334}
335
336/// 漫画更新请求(对齐 Java MangaUpdateRequest)
337#[derive(Debug, Clone, Deserialize, Default)]
338#[serde(rename_all = "camelCase")]
339pub struct MangaUpdateRequest {
340    /// 漫画 ID
341    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
342    pub id: Option<i32>,
343    /// 译名
344    pub manga_tran_name: Option<String>,
345    /// 原名
346    pub manga_ori_name: Option<String>,
347    /// 分类
348    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
349    pub category: Option<i16>,
350    /// 状态
351    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
352    pub manga_status: Option<i16>,
353    /// 原著链接
354    pub link: Option<String>,
355    /// 简介
356    pub introduction: Option<String>,
357    /// 原作作者 ID
358    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
359    pub author_id: Option<i32>,
360    /// 原作作者名
361    pub author_name: Option<String>,
362    /// 作画作者名
363    pub author_name2: Option<String>,
364    /// 作画作者 ID
365    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
366    pub author_id2: Option<i32>,
367    /// 杂志名
368    pub magazine_name: Option<String>,
369    /// 杂志 ID
370    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
371    pub magazine_id: Option<i32>,
372    /// 封面
373    pub image: Option<String>,
374}
375
376/// 添加常驻请求(对齐 Java AddStationRequest)
377#[derive(Debug, Clone, Deserialize, Default)]
378#[serde(rename_all = "camelCase")]
379pub struct AddStationRequest {
380    /// 漫画 ID
381    pub manga_id: i32,
382    /// 组员 ID
383    pub member_id: i32,
384    /// 岗位
385    pub post: i32,
386    /// 是否填充单话
387    pub fill_episodes: Option<bool>,
388}
389
390/// 话数下载请求(对齐 Java EpisodeDownloadRequest)
391#[derive(Debug, Clone, Deserialize, Default)]
392#[serde(rename_all = "camelCase")]
393pub struct EpisodeDownloadRequest {
394    /// 话数 ID
395    pub id: i32,
396    /// 漫画 ID
397    pub manga_id: i32,
398    /// 组员 ID
399    pub member_id: i32,
400    /// 岗位名
401    pub my_name: String,
402}
403
404/// 漫画话数 RSS
405#[derive(Debug, Clone, Serialize, Deserialize)]
406#[serde(rename_all = "camelCase")]
407pub struct MangaEpisodeRss {
408    /// 话数 ID
409    #[serde(rename = "Id")]
410    pub id: i32,
411    /// 漫画 ID
412    pub manga_id: i32,
413}
414
415/// 特典 DTO (Manga Benefit Data Transfer Object)
416///
417/// 用于创建/更新漫画卷特典信息。
418/// - `r#type`: 1=封面, 2=特典, 3=官方图片
419/// - `img_url`: 图片在 OSS 上的相对路径
420///
421/// 对应 Java `MangaBenefitDTO`。
422#[derive(Debug, Clone, Deserialize, Default)]
423#[serde(rename_all = "camelCase")]
424pub struct MangaBenefitDto {
425    /// 主键
426    pub id: Option<i32>,
427    /// 漫画 ID
428    pub manga_id: i32,
429    /// 卷号
430    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i32_loose")]
431    pub volume_number: Option<i32>,
432    /// 卷标题
433    pub volume_title: Option<String>,
434    /// 店铺名称
435    pub store_name: Option<String>,
436    /// 特典名称
437    pub benefit_name: Option<String>,
438    /// 特典标签
439    pub benefit_tag: Option<String>,
440    /// 图片路径
441    pub img_url: Option<String>,
442    /// 类型 1 封面 2 特典 3 官方
443    #[serde(default, deserialize_with = "crate::utils::query_deserialize::de_opt_i16_loose")]
444    pub r#type: Option<i16>,
445    /// 发布时间
446    pub publish_time: Option<chrono::DateTime<chrono::Utc>>,
447}
448
449/// 卷 VO(对齐 Java VolumeVO)
450#[derive(Debug, Clone, Serialize, Deserialize)]
451#[serde(rename_all = "camelCase")]
452pub struct VolumeVo {
453    /// 卷 ID(首条记录 id)
454    pub id: i32,
455    /// 卷号
456    pub volume_number: i32,
457    /// 卷标题
458    pub volume_title: Option<String>,
459    /// 发布时间
460    pub publish_time: Option<chrono::DateTime<chrono::Utc>>,
461    /// 封面 URL
462    pub cover_url: Option<String>,
463    /// 店铺特典列表
464    pub benefits: Vec<StoreBenefitVo>,
465}
466
467/// 店铺特典 VO(对齐 Java StoreBenefitVO)
468#[derive(Debug, Clone, Serialize, Deserialize)]
469#[serde(rename_all = "camelCase")]
470pub struct StoreBenefitVo {
471    /// 店铺名
472    pub store_name: Option<String>,
473    /// 特典项列表
474    pub items: Vec<MangaBenefitItemVo>,
475}
476
477/// 特典项 VO(对齐 Java BenefitItemVO)
478#[derive(Debug, Clone, Serialize, Deserialize)]
479#[serde(rename_all = "camelCase")]
480pub struct MangaBenefitItemVo {
481    /// ID
482    pub id: i32,
483    /// 特典名称
484    pub benefit_name: Option<String>,
485    /// 特典标签
486    pub benefit_tag: Option<String>,
487    /// 缩略图
488    pub thumbnail_url: Option<String>,
489    /// 图片 URL
490    pub image_url: Option<String>,
491}