Skip to content

Commit 08eeb6e

Browse files
committed
重构代码并添加积分查看功能
- 添加 scraper 依赖用于 HTML 解析和引用消息处理 - 在聊天室命令中新增 :p 命令,支持查看当前用户积分 - 提取 format_quote_message 函数到独立 quote 模块,使用 scraper 库重写,支持嵌套引用和 HTML 结构解析 - 在 UserApi 中添加 get_points 方法获取用户积分信息 - 在 UserService 中添加 get_point 方法封装积分查询逻辑 - 更新聊天室帮助文本和命令补全列表,包含新功能说明 此变更优化了代码结构,增强了引用消息的显示效果,并新增了用户积分查询功能,提升了聊天室客户端的用户体验。
1 parent dc40590 commit 08eeb6e

7 files changed

Lines changed: 226 additions & 115 deletions

File tree

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ serde_repr = "0.1.12"
6060
serde_path_to_error = "0.1.17"
6161
lru = "0.12"
6262
once_cell = "1.21.3"
63+
scraper = "0.25.0"
6364

6465
[package.metadata.docs.rs]
6566
all-features = true

client/src/commands/handlers/chatroom.rs

Lines changed: 41 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ impl Command for ChatroomCommand {
8585
:rp - 红包
8686
:bl - 消息屏蔽/过滤
8787
:rw - 查看自动猜拳分布
88+
:p - 查看积分
8889
"#
8990
}
9091
}
@@ -158,6 +159,10 @@ impl ChatroomCommand {
158159
name: ":rw",
159160
desc: "查看自动猜拳分布",
160161
},
162+
CommandItem {
163+
name: ":p",
164+
desc: "查看积分",
165+
},
161166
]);
162167

163168
let prompt = format!("{}", "聊天室> ".green().bold());
@@ -261,6 +266,24 @@ impl ChatroomCommand {
261266
self.show_current_topic().await;
262267
}
263268
}
269+
cmd if cmd.starts_with(":p") => {
270+
let username = self.context.auth.get_user_name().await?;
271+
let result = self.context.client.user.get_point(&username).await;
272+
if result.success {
273+
if let Some(points) = result.data {
274+
println!(
275+
"{} 的积分: {}",
276+
username.green(),
277+
points.to_string().yellow()
278+
);
279+
} else {
280+
println!("{}", "数据为空".red());
281+
}
282+
} else {
283+
let error_msg = result.message.unwrap_or_else(|| "未知错误".to_string());
284+
println!("{}: {}", "获取积分失败".red(), error_msg);
285+
}
286+
}
264287
cmd if cmd.starts_with(":bg") => {
265288
let parts: Vec<&str> = cmd.split_whitespace().collect();
266289
if parts.len() >= 2 {
@@ -507,23 +530,23 @@ impl ChatroomCommand {
507530
weather.format_colored_weather()
508531
);
509532
} else {
510-
let content = msg.md_text();
511-
if is_quote_message(content) {
512-
let formatted_content = format_quote_message(content);
533+
let content = msg;
534+
if is_quote_message(content.md_text()) {
535+
let formatted_content = format_quote_message(&content.content);
513536
println!(
514537
"\r{} {} {}: {}",
515-
msg.time.blue(),
516-
msg.all_name().green(),
517-
format!("[{}]", msg.oid).bright_black(),
538+
content.time.blue(),
539+
content.all_name().green(),
540+
format!("[{}]", content.oid.clone()).bright_black(),
518541
filter_tail_content(&formatted_content)
519542
);
520543
} else {
521-
let filtered_content = filter_tail_content(content);
544+
let filtered_content = filter_tail_content(content.md_text());
522545
println!(
523546
"\r{} {} {}: {}",
524-
msg.time.blue(),
525-
msg.all_name().green(),
526-
format!("[{}]", msg.oid).bright_black(),
547+
content.time.blue(),
548+
content.all_name().green(),
549+
format!("[{}]", content.oid).bright_black(),
527550
strip_html_tags_chatroom(&filtered_content)
528551
);
529552
}
@@ -576,9 +599,9 @@ impl ChatroomCommand {
576599

577600
if is_sender || is_receiver {
578601
let result = client.redpacket.open(&status.oid).await;
579-
if result.success {
580-
if let Some(info) = result.data {
581-
if let Some(gesture) = info.info.gesture {
602+
if result.success
603+
&& let Some(info) = result.data
604+
&& let Some(gesture) = info.info.gesture {
582605
if is_receiver {
583606
// 我抢到了红包
584607
if let Some(who) = info.who.iter().find(|w| w.user_name == status.who_got) {
@@ -631,14 +654,12 @@ impl ChatroomCommand {
631654
Self::rps_result(display_gesture, who.money, is_sender);
632655
}
633656
}
634-
}
635-
}
636657
} else {
637658
// 旁观者
638659
let result = client.redpacket.open(&status.oid).await;
639-
if result.success {
640-
if let Some(info) = result.data {
641-
if let Some(gesture) = info.info.gesture {
660+
if result.success
661+
&& let Some(info) = result.data
662+
&& let Some(gesture) = info.info.gesture {
642663
// 记录发送者出拳
643664
record_opponent_gesture_only(
644665
&status.who_give,
@@ -654,8 +675,6 @@ impl ChatroomCommand {
654675
);
655676
}
656677
}
657-
}
658-
}
659678
}
660679
}
661680
}
@@ -710,8 +729,8 @@ impl ChatroomCommand {
710729
let result = self.context.client.chatroom.get_history(page).await;
711730

712731
if result.success {
713-
if let Some(response) = result.data {
714-
if let Some(messages) = response.data {
732+
if let Some(response) = result.data
733+
&& let Some(messages) = response.data {
715734
for msg in messages.iter().rev() {
716735
if msg.is_redpacket() {
717736
let redpacket = msg.redpacket().unwrap();
@@ -754,7 +773,6 @@ impl ChatroomCommand {
754773
}
755774
}
756775
}
757-
}
758776
} else {
759777
println!(
760778
"{}: {}",

client/src/utils/auth.rs

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -23,11 +23,10 @@ impl AuthService {
2323
let expire = Duration::from_secs(300); // 5分钟
2424

2525
// 检查缓存是否可用
26-
if let Some((info, ts)) = &*cache {
27-
if now.duration_since(*ts) < expire {
26+
if let Some((info, ts)) = &*cache
27+
&& now.duration_since(*ts) < expire {
2828
return Ok(info.clone());
2929
}
30-
}
3130

3231
// 缓存无效,重新获取
3332
let result = self.client.user.get_info().await;
@@ -104,12 +103,11 @@ impl AuthService {
104103
.await;
105104

106105
if response.success {
107-
if let Some(token) = self.client.get_token().await {
108-
if std::fs::write("token.txt", &token).is_err() {
106+
if let Some(token) = self.client.get_token().await
107+
&& std::fs::write("token.txt", &token).is_err() {
109108
// 保存失败不影响登录成功
110109
eprintln!("警告: 无法保存token到文件");
111110
}
112-
}
113111
Ok(())
114112
} else {
115113
Err(anyhow::anyhow!(
@@ -124,7 +122,7 @@ impl AuthService {
124122
Ok(result.success)
125123
}
126124

127-
/// 获取username
125+
// 获取username
128126
pub async fn get_user_name(&self) -> Result<String> {
129127
self.get_user_info_cached().await.map(|info| info.user_name)
130128
}

client/src/utils/mod.rs

Lines changed: 2 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
pub mod auth;
22
pub mod gesture;
33
pub mod script;
4+
pub mod quote;
45

56
pub use auth::AuthService;
67

@@ -26,89 +27,8 @@ pub fn is_quote_message(content: &str) -> bool {
2627
content.contains("##### 引用") || content.lines().any(|line| line.trim().starts_with('>'))
2728
}
2829

29-
// 格式化引用消息
3030
pub fn format_quote_message(content: &str) -> String {
31-
let mut result = String::new();
32-
let mut quotes = Vec::new();
33-
34-
// 按 "##### 引用" 分割消息
35-
let parts: Vec<&str> = content.split("##### 引用").collect();
36-
37-
// 第一部分是主要内容
38-
if let Some(main_part) = parts.first() {
39-
let main_content = main_part.trim();
40-
if !main_content.is_empty() {
41-
result.push_str(main_content);
42-
}
43-
}
44-
45-
// 处理每个引用部分
46-
for (index, part) in parts.iter().skip(1).enumerate() {
47-
// 提取用户名 (@用户名)
48-
if let Some(at_pos) = part.find('@') {
49-
let after_at = &part[at_pos..];
50-
let username = if let Some(space_pos) = after_at.find(' ') {
51-
&after_at[..space_pos]
52-
} else if let Some(bracket_pos) = after_at.find('[') {
53-
&after_at[..bracket_pos]
54-
} else {
55-
after_at.split_whitespace().next().unwrap_or("")
56-
};
57-
58-
// 查找引用内容 (> 开头的行)
59-
let lines: Vec<&str> = part.lines().collect();
60-
let mut quote_content = Vec::new();
61-
let mut max_level = 0;
62-
63-
for line in lines {
64-
let trimmed = line.trim();
65-
if trimmed.starts_with('>') {
66-
let level = trimmed.chars().take_while(|&c| c == '>').count();
67-
max_level = max_level.max(level);
68-
let collected: String = trimmed.chars().skip(level).collect();
69-
let content_part = collected.trim().to_string();
70-
if !content_part.is_empty() {
71-
quote_content.push(content_part);
72-
}
73-
}
74-
}
75-
76-
if !quote_content.is_empty() {
77-
let indent = " ".repeat(index + 1);
78-
quotes.push(format!(
79-
"{}└─引用 {}: {}",
80-
indent,
81-
username.green().bold(),
82-
quote_content.join(" ")
83-
));
84-
} else {
85-
// 如果没有找到 > 内容,尝试提取链接后的文本
86-
if let Some(link_end) = part.find(')') {
87-
let after_link = &part[link_end + 1..];
88-
let remaining_text = after_link.trim();
89-
if !remaining_text.is_empty() {
90-
let indent = " ".repeat(index + 1);
91-
quotes.push(format!(
92-
"{}└─引用 {}: {}",
93-
indent,
94-
username.green().bold(),
95-
remaining_text
96-
));
97-
}
98-
}
99-
}
100-
}
101-
}
102-
103-
// 组合结果
104-
if !quotes.is_empty() {
105-
if !result.is_empty() {
106-
result.push('\n');
107-
}
108-
result.push_str(&quotes.join("\n"));
109-
}
110-
111-
result
31+
quote::format_quote_message(content)
11232
}
11333

11434
pub fn filter_tail_content(content: &str) -> String {

0 commit comments

Comments
 (0)