Skip to main content

bpi_rs/electric/
charge_msg.rs

1use chrono::NaiveDate;
2use serde::{ Deserialize, Serialize };
3
4use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5
6/// 发送充电留言的请求体
7#[derive(Debug, Clone, Serialize)]
8pub struct SendElecMessageBody<'a> {
9    pub order_id: &'a str,
10    pub message: &'a str,
11    pub csrf: &'a str,
12}
13
14/// 充电留言列表分页信息
15#[derive(Debug, Clone, Deserialize, Serialize)]
16pub struct ElecRemarkPager {
17    /// 当前页数
18    pub current: u64,
19    /// 当前分页大小
20    pub size: u64,
21    /// 记录总数
22    pub total: u64,
23}
24
25/// 充电留言列表中的单条留言
26#[derive(Debug, Clone, Deserialize, Serialize)]
27pub struct ElecRemarkRecord {
28    pub aid: u64,
29    pub bvid: String,
30    pub id: u64,
31    pub mid: u64,
32    pub reply_mid: u64,
33    pub elec_num: u64,
34    /// UP是否已经回复这条留言 0: 未回复 1: 已回复
35    pub state: u8,
36    /// 留言信息
37    pub msg: String,
38    pub aname: String,
39    pub uname: String,
40    pub avator: String,
41    pub reply_name: String,
42    pub reply_avator: String,
43    pub reply_msg: String,
44    /// 留言时间毫秒级时间戳
45    pub ctime: u64,
46    pub reply_time: u64,
47}
48
49/// 充电留言列表数据
50#[derive(Debug, Clone, Deserialize, Serialize)]
51pub struct ElecRemarkList {
52    pub list: Vec<ElecRemarkRecord>,
53    pub pager: ElecRemarkPager,
54}
55
56/// 充电留言详情数据
57#[derive(Debug, Clone, Deserialize, Serialize)]
58pub struct ElecRemarkDetail {
59    pub aid: u64,
60    pub bvid: String,
61    pub id: u64,
62    /// 留言者mid(充电用户)
63    pub mid: u64,
64    /// UP主mid
65    pub reply_mid: u64,
66    pub elec_num: u64,
67    /// UP是否已经回复这条留言 0: 未回复 1: 已回复
68    pub state: u8,
69    /// 留言内容
70    pub msg: String,
71    pub aname: String,
72    /// 留言者用户名
73    pub uname: String,
74    /// 留言者头像
75    pub avator: String,
76    /// UP主用户名
77    pub reply_name: String,
78    /// UP主头像
79    pub reply_avator: String,
80    /// 回复内容
81    pub reply_msg: String,
82    /// 留言时间毫秒级时间戳
83    pub ctime: u64,
84    /// 回复时间毫秒级时间戳
85    pub reply_time: u64,
86}
87
88impl BpiClient {
89    /// 发送充电留言
90    ///
91    /// 注意: 此接口需要登录态 (Cookie: SESSDATA)
92    ///
93    /// # 文档
94    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/electric)
95    ///
96    /// # 参数
97    ///
98    /// | 名称 | 类型 | 说明 |
99    /// | ---- | ---- | ---- |
100    /// | `order_id` | &str | 留言 token |
101    /// | `message` | &str | 留言内容 |
102    pub async fn electric_message_send(
103        &self,
104        order_id: &str,
105        message: &str
106    ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
107        let csrf = self.csrf()?;
108
109        let body = [
110            ("order_id", order_id),
111            ("message", message),
112            ("csrf", &csrf),
113        ];
114
115        self
116            .post("https://api.bilibili.com/x/ugcpay/trade/elec/message")
117            .form(&body)
118            .send_bpi("发送充电留言").await
119    }
120
121    /// 查询我收到的充电留言
122    ///
123    /// 注意: 此接口需要登录态 (Cookie: SESSDATA)
124    ///
125    /// # 文档
126    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/electric)
127    ///
128    /// # 参数
129    ///
130    /// | 名称 | 类型 | 说明 |
131    /// | ---- | ---- | ---- |
132    /// | `pn` | `Option<u64>` | 页数,默认 1 |
133    /// | `ps` | `Option<u64>` | 分页大小,默认 10,范围 `[1,12]` |
134    /// | `begin` | `Option<NaiveDate>` | 开始日期 YYYY-MM-DD |
135    /// | `end` | `Option<NaiveDate>` | 结束日期 YYYY-MM-DD |
136    pub async fn electric_remark_list(
137        &self,
138        pn: Option<u64>,
139        ps: Option<u64>,
140        begin: Option<NaiveDate>,
141        end: Option<NaiveDate>
142    ) -> Result<BpiResponse<ElecRemarkList>, BpiError> {
143        let mut req = self.get("https://member.bilibili.com/x/web/elec/remark/list");
144
145        if let Some(page) = pn {
146            req = req.query(&[("pn", page)]);
147        }
148        if let Some(size) = ps {
149            req = req.query(&[("ps", size)]);
150        }
151        if let Some(begin_date) = begin {
152            req = req.query(&[("begin", begin_date.format("%Y-%m-%d").to_string())]);
153        }
154        if let Some(end_date) = end {
155            req = req.query(&[("end", end_date.format("%Y-%m-%d").to_string())]);
156        }
157
158        req.send_bpi("查询收到的充电留言").await
159    }
160
161    /// 查询充电留言详情
162    ///
163    /// 注意: 此接口需要登录态 (Cookie: SESSDATA)
164    ///
165    /// # 文档
166    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/electric)
167    ///
168    /// # 参数
169    ///
170    /// | 名称 | 类型 | 说明 |
171    /// | ---- | ---- | ---- |
172    /// | `id` | u64 | 留言 id |
173    pub async fn electric_remark_detail(
174        &self,
175        id: u64
176    ) -> Result<BpiResponse<ElecRemarkDetail>, BpiError> {
177        self
178            .get("https://member.bilibili.com/x/web/elec/remark/detail")
179            .query(&[("id", id)])
180            .send_bpi("查询充电留言详情").await
181    }
182
183    /// 回复充电留言
184    ///
185    /// 注意: 此接口需要登录态 (Cookie: SESSDATA)
186    ///
187    /// # 文档
188    /// [查看API文档](https://github.com/SocialSisterYi/bilibili-API-collect/tree/master/docs/electric)
189    ///
190    /// # 参数
191    ///
192    /// | 名称 | 类型 | 说明 |
193    /// | ---- | ---- | ---- |
194    /// | `id` | u64 | 留言 id |
195    /// | `msg` | &str | 回复内容 |
196    pub async fn electric_remark_reply(
197        &self,
198        id: u64,
199        msg: &str
200    ) -> Result<BpiResponse<u64>, BpiError> {
201        let csrf = self.csrf()?;
202
203        let body = [
204            ("id", id.to_string()),
205            ("msg", msg.to_string()),
206            ("csrf", csrf.to_string()),
207        ];
208
209        self
210            .post("https://member.bilibili.com/x/web/elec/remark/reply")
211            .form(&body)
212            .send_bpi("回复充电留言").await
213    }
214}
215
216#[cfg(test)]
217mod tests {
218    use super::*;
219    use tracing::info;
220
221    #[tokio::test]
222    /// 未测试
223    async fn test_send_elec_message() {
224        let bpi = BpiClient::new();
225        // 替换为有效的 order_id 和留言
226        let resp = bpi.electric_message_send("ORDER_ID_HERE", "测试留言").await;
227        info!("响应: {:?}", resp);
228        assert!(resp.is_ok());
229    }
230
231    #[tokio::test]
232    async fn test_get_elec_remark_list() {
233        let bpi = BpiClient::new();
234        let resp = bpi.electric_remark_list(Some(1), Some(10), None, None).await;
235        info!("响应: {:?}", resp);
236        assert!(resp.is_ok());
237
238        if let Ok(response) = resp {
239            let data = response.data.unwrap();
240            info!("留言总记录数: {}", data.pager.total);
241            info!("当前页留言记录数: {}", data.list.len());
242        }
243    }
244
245    #[tokio::test]
246    async fn test_get_elec_remark_detail() {
247        let bpi = BpiClient::new();
248        // 替换为有效的留言id
249        let resp = bpi.electric_remark_detail(6507563).await;
250        info!("响应: {:?}", resp);
251        assert!(resp.is_ok());
252    }
253
254    #[tokio::test]
255    async fn test_reply_elec_remark() {
256        let bpi = BpiClient::new();
257        // 替换为有效的留言id和回复内容
258        let resp = bpi.electric_remark_reply(6507563, "测试回复").await;
259        info!("响应: {:?}", resp);
260        assert!(resp.is_ok());
261    }
262}