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(
102 &self,
103 order_id: &str,
104 message: &str,
105 ) -> Result<BpiResponse<serde_json::Value>, BpiError> {
106 let csrf = self.csrf()?;
107
108 let body = [
109 ("order_id", order_id),
110 ("message", message),
111 ("csrf", &csrf),
112 ];
113
114 self.post("https://api.bilibili.com/x/ugcpay/trade/elec/message")
115 .form(&body)
116 .send_bpi("发送充电留言")
117 .await
118 }
119
120 pub async fn electric_remark_list(
136 &self,
137 pn: Option<u64>,
138 ps: Option<u64>,
139 begin: Option<NaiveDate>,
140 end: Option<NaiveDate>,
141 ) -> Result<BpiResponse<ElecRemarkList>, BpiError> {
142 let mut req = self.get("https://member.bilibili.com/x/web/elec/remark/list");
143
144 if let Some(page) = pn {
145 req = req.query(&[("pn", page)]);
146 }
147 if let Some(size) = ps {
148 req = req.query(&[("ps", size)]);
149 }
150 if let Some(begin_date) = begin {
151 req = req.query(&[("begin", begin_date.format("%Y-%m-%d").to_string())]);
152 }
153 if let Some(end_date) = end {
154 req = req.query(&[("end", end_date.format("%Y-%m-%d").to_string())]);
155 }
156
157 req.send_bpi("查询收到的充电留言").await
158 }
159
160 pub async fn electric_remark_detail(
173 &self,
174 id: u64,
175 ) -> Result<BpiResponse<ElecRemarkDetail>, BpiError> {
176 self.get("https://member.bilibili.com/x/web/elec/remark/detail")
177 .query(&[("id", id)])
178 .send_bpi("查询充电留言详情")
179 .await
180 }
181
182 pub async fn electric_remark_reply(
196 &self,
197 id: u64,
198 msg: &str,
199 ) -> Result<BpiResponse<u64>, BpiError> {
200 let csrf = self.csrf()?;
201
202 let body = [
203 ("id", id.to_string()),
204 ("msg", msg.to_string()),
205 ("csrf", csrf.to_string()),
206 ];
207
208 self.post("https://member.bilibili.com/x/web/elec/remark/reply")
209 .form(&body)
210 .send_bpi("回复充电留言")
211 .await
212 }
213}
214
215#[cfg(test)]
216mod tests {
217 use super::*;
218 use tracing::info;
219
220 #[tokio::test]
221 async fn test_send_elec_message() {
223 let bpi = BpiClient::new();
224 let resp = bpi.electric_message_send("ORDER_ID_HERE", "测试留言").await;
226 info!("响应: {:?}", resp);
227 assert!(resp.is_ok());
228 }
229
230 #[tokio::test]
231 async fn test_get_elec_remark_list() {
232 let bpi = BpiClient::new();
233 let resp = bpi
234 .electric_remark_list(Some(1), Some(10), None, None)
235 .await;
236 info!("响应: {:?}", resp);
237 assert!(resp.is_ok());
238
239 if let Ok(response) = resp {
240 let data = response.data.unwrap();
241 info!("留言总记录数: {}", data.pager.total);
242 info!("当前页留言记录数: {}", data.list.len());
243 }
244 }
245
246 #[tokio::test]
247 async fn test_get_elec_remark_detail() {
248 let bpi = BpiClient::new();
249 let resp = bpi.electric_remark_detail(6507563).await;
251 info!("响应: {:?}", resp);
252 assert!(resp.is_ok());
253 }
254
255 #[tokio::test]
256 async fn test_reply_elec_remark() {
257 let bpi = BpiClient::new();
258 let resp = bpi.electric_remark_reply(6507563, "测试回复").await;
260 info!("响应: {:?}", resp);
261 assert!(resp.is_ok());
262 }
263}