fbc_starter/
base.rs

1use crate::constants::*;
2use crate::utils::{deserialize_option_u32_from_str_or_num, deserialize_u32_from_str_or_num};
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Serialize, Deserialize)]
6pub struct R<T> {
7    pub success: bool,
8    pub code: i32,
9    pub msg: Option<String>,
10    pub data: Option<T>,
11    #[serde(skip)]
12    pub def_exec: bool,
13    pub path: String,
14    pub version: String,
15    pub base_version: String,
16    pub timestamp: i64,
17}
18
19impl<T> R<T> {
20    pub fn new(code: i32, msg: Option<String>, data: Option<T>) -> Self {
21        Self {
22            success: code == SUCCESS_CODE,
23            code,
24            msg,
25            data,
26            def_exec: false,
27            path: String::new(),
28            version: String::new(),
29            base_version: String::new(),
30            timestamp: chrono::Local::now().timestamp_millis(),
31        }
32    }
33
34    pub fn ok() -> Self {
35        Self::new(SUCCESS_CODE, Some(SUCCESS_MESSAGE.into()), None)
36    }
37
38    pub fn ok_with_data(data: T) -> Self {
39        Self::new(SUCCESS_CODE, Some(SUCCESS_MESSAGE.into()), Some(data))
40    }
41
42    pub fn fail() -> Self {
43        Self::new(OPERATION_EX_CODE, None, None)
44    }
45
46    pub fn fail_with_code(code: i32, msg: String) -> Self {
47        Self::new(code, Some(msg.into()), None)
48    }
49
50    pub fn fail_with_message(msg: String) -> Self {
51        Self::new(FAIL_CODE, Some(msg.into()), None)
52    }
53}
54
55/// 游标分页基础响应
56#[derive(Debug, Clone, Serialize, Deserialize)]
57pub struct CursorPageBaseResp<T> {
58    /// 游标(下次翻页带上这参数)
59    #[serde(skip_serializing_if = "Option::is_none")]
60    pub cursor: Option<u32>,
61    /// 是否最后一页
62    pub is_last: bool,
63    /// 数据列表
64    pub list: Vec<T>,
65    /// 总数
66    pub total: i64,
67}
68
69impl<T> CursorPageBaseResp<T> {
70    /// 初始化游标分页响应
71    ///
72    /// # 参数
73    /// - `cursor_page`: 游标分页请求(用于获取 cursor 和 is_last)
74    /// - `list`: 数据列表
75    /// - `total`: 总数
76    pub fn init(cursor: Option<u32>, is_last: bool, list: Vec<T>, total: i64) -> Self {
77        Self {
78            cursor,
79            is_last,
80            list,
81            total,
82        }
83    }
84
85    /// 判断是否为空
86    pub fn is_empty(&self) -> bool {
87        self.list.is_empty()
88    }
89
90    /// 创建空的分页响应
91    pub fn empty() -> Self {
92        Self {
93            cursor: None,
94            is_last: true,
95            list: Vec::new(),
96            total: 0,
97        }
98    }
99}
100
101impl<T> Default for CursorPageBaseResp<T> {
102    fn default() -> Self {
103        Self {
104            cursor: None,
105            is_last: false,
106            list: Vec::new(),
107            total: 0,
108        }
109    }
110}
111
112/// 游标翻页基础请求
113#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct CursorPageBaseReq {
115    /// 页面大小(默认 10,最大 100)
116    #[serde(
117        default = "CursorPageBaseReq::default_page_size",
118        deserialize_with = "deserialize_u32_from_str_or_num"
119    )]
120    pub page_size: u32,
121    /// 游标(初始为 None,后续请求附带上次翻页的游标)
122    #[serde(
123        skip_serializing_if = "Option::is_none",
124        deserialize_with = "deserialize_option_u32_from_str_or_num"
125    )]
126    pub cursor: Option<u32>,
127}
128
129impl CursorPageBaseReq {
130    fn default_page_size() -> u32 {
131        10
132    }
133
134    /// 是否是第一页(cursor 为空或 None 或者 0)
135    pub fn is_first_page(&self) -> bool {
136        self.cursor
137            .as_ref()
138            .map(|s| *s == 0 || *s < self.page_size)
139            .unwrap_or(true)
140    }
141
142    /// 计算分页参数,返回 (页码, page_size)
143    ///
144    /// 对应 Java 中的 plusPage(),这里固定页码为 1,因为采用游标分页。
145    pub fn plus_page(&self) -> (u32, u32) {
146        (1, self.page_size)
147    }
148}
149
150impl Default for CursorPageBaseReq {
151    fn default() -> Self {
152        Self {
153            page_size: Self::default_page_size(),
154            cursor: None,
155        }
156    }
157}