Skip to content

feat: 添加名单表格搜索筛选功能#240

Merged
Hongbro886 merged 11 commits into
SECTL:masterfrom
trustedinster:fix/issue-232-list-search-filter
May 23, 2026
Merged

feat: 添加名单表格搜索筛选功能#240
Hongbro886 merged 11 commits into
SECTL:masterfrom
trustedinster:fix/issue-232-list-search-filter

Conversation

@trustedinster
Copy link
Copy Markdown
Contributor

概述

实现 #232 请求的功能:在查看名单时添加搜索/筛选功能。

变更内容

新增功能

  • 点名表格搜索栏:在点名表格卡片中添加搜索栏,支持按学号、姓名、性别、小组、标签进行关键词筛选
  • 抽奖表格搜索栏:在抽奖表格卡片中添加搜索栏,支持按序号、奖品、权重、标签、数量进行关键词筛选

技术实现

  • 使用 SearchLineEdit 组件(qfluentwidgets),与项目现有搜索组件风格一致
  • 搜索输入带 300ms 防抖处理,避免频繁刷新
  • 搜索匹配所有列的文本内容(不区分大小写)
  • 清空搜索框自动恢复显示所有行
  • 数据刷新后自动重新应用搜索过滤
  • 使用 ic_fluent_search_20_filled 图标,与 Fluent Design 风格一致

国际化

  • 添加中文、英文、日文三语翻译
  • 搜索栏标题和占位符文本均支持多语言

修改文件

  • app/view/settings/list_management/roll_call_table.py — 点名表格添加搜索功能
  • app/view/settings/list_management/lottery_table.py — 抽奖表格添加搜索功能
  • app/Language/modules/list_management.py — 添加搜索相关翻译

截图

搜索栏位于班级/奖池选择器下方、表格上方,输入关键词即可实时筛选。

Closes #232

在点名表格和抽奖表格中添加搜索栏,支持按关键词实时筛选表格行。

- 点名表格:支持按学号、姓名、性别、小组、标签筛选
- 抽奖表格:支持按序号、奖品、权重、标签、数量筛选
- 使用 SearchLineEdit 组件,带防抖处理(300ms)
- 添加中/英/日三语国际化翻译
- 刷新数据后自动重新应用搜索过滤

Closes SECTL#232
在点名历史记录和抽奖历史记录表格中添加导出按钮,
支持将当前表格数据导出为 xlsx、csv、txt 格式。

- 点名历史记录:支持导出全部记录、按时间查看、个人统计三种模式的数据
- 抽奖历史记录:支持导出全部记录、按时间查看、奖品统计三种模式的数据
- 导出内容与用户当前看到的表格一致(包括筛选和排序状态)
- 添加中/英/日三语国际化翻译
- 添加 QFileDialog 翻译配置

Closes SECTL#232
Comment on lines +1191 to +1197
export_type = (
"excel"
if "Excel 文件 (*.xlsx)" in selected_filter
else "csv"
if "CSV 文件 (*.csv)" in selected_filter
else "txt"
)

This comment was marked as outdated.

Comment on lines +1026 to +1032
export_type = (
"excel"
if "Excel 文件 (*.xlsx)" in selected_filter
else "csv"
if "CSV 文件 (*.csv)" in selected_filter
else "txt"
)

This comment was marked as outdated.

trustedinster and others added 2 commits May 16, 2026 09:22
修复非中文语言环境下导出格式判断失败的问题。
将 'Excel 文件 (*.xlsx)' 改为 '.xlsx' 匹配,
确保所有语言下都能正确识别导出格式。
Signed-off-by: Hongbro886 <hongbroyier@gmail.com>
Comment on lines +1117 to +1124
content=get_any_position_value_async(
"notification",
"lottery",
"export",
"content",
"error",
"name",
).format(message=str(e)),

This comment was marked as outdated.

- 为 notification 模块补充缺失的 JA_JP 翻译
- 为 get_any_position_value_async 返回值添加空值保护,
  防止翻译缺失时 .format() 调用 None 导致 AttributeError
- 修复导出仅导出已加载行而非全部数据的问题(Critical)
  导出前检查是否所有数据已加载,未加载时强制加载全部数据
- 修复预期导出错误使用 logger.exception 导致误报 Sentry 的问题
  改用 logger.error() 符合项目 Sentry 日志策略
- 修复默认文件名硬编码中文字符串的问题
  添加 export_default_filename i18n 键,支持三语
- 修复 TXT 导出硬编码中文表头匹配的问题
  改用列索引识别名称列,不再依赖表头文本
- 抽取共享导出工具 export_utils.py 消除代码重复
- 添加 get_path() 和 mkdir() 路径保护,与项目既有模式一致
Comment on lines +111 to +116
def _apply_search_filter(self):
"""根据搜索关键词过滤表格行"""
if not hasattr(self, "table") or self.table is None:
return

keyword = self.search_line_edit.text().strip().lower()

This comment was marked as outdated.

Comment on lines +1163 to +1167
def export_history_data(self):
if not self.current_class_name:
return

if self.current_row < self.total_rows:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bug: Exporting large history datasets results in incomplete files because the data loading logic is capped at ~630 rows when the UI is not rendered.
Severity: HIGH

Suggested Fix

Modify the data loading logic in _ensure_scrollable_rows to not depend on the scrollbar's visibility when force_load_all is true. Instead, it should loop until all expected rows (self.total_rows) are loaded.

Prompt for AI Agent
Review the code at the location below. A potential bug has been identified by an AI
agent. Verify if this is a real issue. If it is, propose a fix; if not, explain why it's
not valid.

Location: app/view/settings/history/roll_call_history_table.py#L1163-L1167

Potential issue: When exporting a history table with more than approximately 630 rows,
the resulting file is incomplete. The `export_history_data` function triggers a data
load that relies on a loop in `_ensure_scrollable_rows`. This loop's condition depends
on the scrollbar's visibility (`max_value == 0`) and is limited to 20 attempts. When
exporting, the widget may not be rendered, so the scrollbar never appears, and the loop
loads a maximum of 20 batches (600 rows). Data beyond this limit is never loaded into
the table, causing it to be exported as empty rows.

Also affects:

  • app/view/settings/history/lottery_history_table.py:997~1001

@Hongbro886
Copy link
Copy Markdown
Contributor

@trustedinster 从UI层的导出会有各种奇怪的问题,比如未渲染的数据(ReviewBot所提出的),建议直接从json数据源进行导出,最好用流式写入预防内存泄漏,这个数据量有时可能比较大还是得注意一下

并跑一下uv run pre-commit run --all-files 检查并规范代码格式

- 重构 export_utils.py:直接从 JSON 数据源导出历史数据,
  不再依赖 UI 表格渲染,解决大数据集导出截断问题
- 使用流式写入(CSV/TXT 逐行写入,Excel 分块写入)预防内存泄漏
- 修复 roll_call_table/lottery_table 搜索栏初始化竞态条件:
  _apply_search_filter 添加 search_line_edit 存在性检查
- 补充 notification 模块缺失的 JA_JP 翻译
- 为 get_any_position_value_async 返回值添加空值保护
if name_col_idx is not None:
for row in rows:
if name_col_idx < len(row):
f.write(f"{row[name_col_idx]}\n")
f.write("\n")
else:
for row in rows:
f.write("\t".join(str(v) for v in row) + "\n")
Comment on lines +378 to +382
title=get_any_position_value_async(
"notification", i18n_domain, "export", "title", "success", "name"
),
content=(
get_any_position_value_async(

This comment was marked as outdated.

- export_utils.py 中 title 字段的 get_any_position_value_async
  返回值添加 or '' 保护,与 content 字段保持一致
Comment on lines +1001 to +1004
current_item_name = ""
if self.current_mode >= 2:
if hasattr(self, "mode_comboBox"):
current_item_name = self.mode_comboBox.currentText()

This comment was marked as outdated.

- on_pool_changed 中重新获取奖品名称列表并更新 mode_comboBox
- on_class_changed 中重新获取学生名称列表并更新 mode_comboBox
- 使用 blockSignals 防止更新时触发 refresh_data
- 为 notification title 添加空值保护
get_any_position_value_async(
"qfiledialog", i18n_domain, "export_history", "caption", "name"
),
f"{current_name}_{get_content_name_async(f'{i18n_domain}_history_table', 'export_default_filename')}-SecRandom",

This comment was marked as outdated.

@Hongbro886
Copy link
Copy Markdown
Contributor

Hongbro886 commented May 23, 2026

@trustedinster 感谢你对本项目做出的贡献,我还看到了一些问题
1.我已经提到过了的使用流式写入
2.规范代码格式

@Hongbro886
Copy link
Copy Markdown
Contributor

我认为这个PR已经可以合并,如果你愿意修复这个问题可以再提PR

@Hongbro886 Hongbro886 merged commit d896280 into SECTL:master May 23, 2026
5 of 7 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

优化查看名单时的筛选按钮

3 participants