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