1use chrono::NaiveDate;
2use serde::{ Deserialize, Serialize };
3
4use crate::{ BilibiliRequest, BpiClient, BpiError, BpiResponse };
5
6#[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#[derive(Debug, Clone, Deserialize, Serialize)]
16pub struct ElecRemarkPager {
17 pub current: u64,
19 pub size: u64,
21 pub total: u64,
23}
24
25#[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 pub state: u8,
36 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 pub ctime: u64,
46 pub reply_time: u64,
47}
48
49#[derive(Debug, Clone, Deserialize, Serialize)]
51pub struct ElecRemarkList {
52 pub list: Vec<ElecRemarkRecord>,
53 pub pager: ElecRemarkPager,
54}
55
56#[derive(Debug, Clone, Deserialize, Serialize)]
58pub struct ElecRemarkDetail {
59 pub aid: u64,
60 pub bvid: String,
61 pub id: u64,
62 pub mid: u64,
64 pub reply_mid: u64,
66 pub elec_num: u64,
67 pub state: u8,
69 pub msg: String,
71 pub aname: String,
72 pub uname: String,
74 pub avator: String,
76 pub reply_name: String,
78 pub reply_avator: String,
80 pub reply_msg: String,
82 pub ctime: u64,
84 pub reply_time: u64,
86}
87
88impl BpiClient {
89 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 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 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 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 async fn test_send_elec_message() {
224 let bpi = BpiClient::new();
225 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 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 let resp = bpi.electric_remark_reply(6507563, "测试回复").await;
259 info!("响应: {:?}", resp);
260 assert!(resp.is_ok());
261 }
262}