Skip to content

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

Open
trustedinster wants to merge 7 commits into
SECTL:masterfrom
trustedinster:fix/issue-232-list-search-filter
Open

feat: 添加名单表格搜索筛选功能#240
trustedinster wants to merge 7 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()
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: A race condition during initialization can cause an AttributeError if refresh_data is signaled before create_search_bar completes, as _apply_search_filter accesses an uninitialized attribute.
Severity: MEDIUM

Suggested Fix

Add a guard at the beginning of the _apply_search_filter method to ensure the search_line_edit attribute exists before attempting to access it, for example: if not hasattr(self, "search_line_edit"): return.

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/list_management/roll_call_table.py#L111-L116

Potential issue: A race condition can occur during component initialization. Several
setup methods, including `create_search_bar`, are scheduled to run deferred using
`QTimer.singleShot`. However, the `refresh_signal` is connected before these methods
execute. If this signal is emitted before the event loop processes the deferred calls,
`refresh_data` is invoked. Its `finally` block calls `_apply_search_filter`, which
attempts to access `self.search_line_edit`. Because `create_search_bar` has not yet run,
this attribute does not exist, resulting in an `AttributeError`.

Also affects:

  • app/view/settings/list_management/lottery_table.py:117~122

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

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.

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

2 participants