Skip to content

Commit 253cb78

Browse files
committed
优化&新增&修复
- 优化 **抽取临时记录**,区分点名/抽奖文件名 - 优化 **课前重置**,仅清除抽取临时记录 - 优化 **闪抽设置**,移除清除记录项 - 优化 **点名/抽奖点名逻辑**,页面逻辑迁移管理器 - 优化 **抽取记录清理**,按模块读取清理设置 - 新增 **离线用户ID**,关于页展示并用于错误上报 - 新增 **结果显示样式**,支持卡片显示 - 新增 **头像显示布局**,头像位置可自由调整(上/下/左/右) - 修复 **抽取记录读取**,兼容旧格式 - 修复 **通知浮窗显示**,首帧尺寸与上下间距异常
1 parent 8666322 commit 253cb78

23 files changed

Lines changed: 2715 additions & 2069 deletions

CHANGELOG/v2.2.6/CHANGELOG.md

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,25 @@ v2.3 - Shirako (砂狼白子) beta 1
33

44
## 🚀 主要更新
55

6-
-
6+
- 新增 **离线用户ID**,关于页展示并用于错误上报
7+
- 新增 **结果显示样式**,支持卡片显示
8+
- 新增 **头像显示布局**,头像位置可自由调整(上/下/左/右)
79

810
## 💡 功能优化
911

1012
- 优化 **备份管理**,恢复备份的对话框文本改为对应内容
1113
- 优化 **结果显示布局**,使用流式布局显示
14+
- 优化 **抽取临时记录**,区分点名/抽奖文件名
15+
- 优化 **课前重置**,仅清除抽取临时记录
16+
- 优化 **闪抽设置**,移除清除记录项
17+
- 优化 **点名/抽奖点名逻辑**,页面逻辑迁移管理器
18+
- 优化 **抽取记录清理**,按模块读取清理设置
1219

1320
## 🐛 修复问题
1421

1522
- 修复 **版本号更新脚本**,修复 DEV_VERSION 被误更新的问题
23+
- 修复 **抽取记录读取**,兼容旧格式
24+
- 修复 **通知浮窗显示**,首帧尺寸与上下间距异常
1625

1726
## 🔧 其它变更
1827

app/Language/modules/extraction_settings.py

Lines changed: 50 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@
6565
"description": "设置点名结果显示格式",
6666
"combo_items": ["学号+姓名", "姓名", "学号"],
6767
},
68+
"display_style": {
69+
"name": "结果显示样式",
70+
"description": "设置点名结果显示样式",
71+
"combo_items": ["默认样式", "卡片样式"],
72+
},
6873
"show_random": {
6974
"name": "显示随机组员格式",
7075
"description": "设置随机组员显示格式",
@@ -106,6 +111,11 @@
106111
"description": "设置是否显示学生图片",
107112
"switchbutton_name": {"enable": "", "disable": ""},
108113
},
114+
"student_image_position": {
115+
"name": "头像位置",
116+
"description": "设置学生头像在结果中的位置",
117+
"combo_items": ["左部", "顶部", "右部", "底部"],
118+
},
109119
"open_student_image_folder": {
110120
"name": "学生图片文件夹",
111121
"description": "管理学生图片文件,图片文件名需与学生姓名一致",
@@ -183,6 +193,11 @@
183193
"description": "Set the results display format",
184194
"combo_items": {"0": "Student ID + Name", "1": "Name", "2": "Student ID"},
185195
},
196+
"display_style": {
197+
"name": "Result display style",
198+
"description": "Set the pick result display style",
199+
"combo_items": {"0": "Default", "1": "Card"},
200+
},
186201
"show_random": {
187202
"name": "Format of showing random group member",
188203
"description": "Set random group member display format",
@@ -231,6 +246,11 @@
231246
"name": "Show student images",
232247
"description": "Set whether to show student images",
233248
},
249+
"student_image_position": {
250+
"name": "Image position",
251+
"description": "Set the position of student images in results",
252+
"combo_items": {"0": "Left", "1": "Top", "2": "Right", "3": "Bottom"},
253+
},
234254
"open_student_image_folder": {
235255
"name": "Student image folder",
236256
"description": "Manage student image files. Picture file names must match student name",
@@ -269,12 +289,6 @@
269289
"description": "设置闪抽抽取模式",
270290
"combo_items": ["重复抽取", "不重复抽取", "半重复抽取"],
271291
},
272-
"clear_record": {
273-
"name": "清除抽取记录方式",
274-
"description": "设置清除闪抽抽取记录方式",
275-
"combo_items": ["重启后清除", "直到全部抽取完"],
276-
"combo_items_other": ["重启后清除", "直到全部抽取完", "无需清除"],
277-
},
278292
"half_repeat": {
279293
"name": "半重复抽取次数",
280294
"description": "设置每人被抽中多少次后清除抽取记录",
@@ -340,6 +354,11 @@
340354
"description": "设置是否显示学生图片",
341355
"switchbutton_name": {"enable": "", "disable": ""},
342356
},
357+
"student_image_position": {
358+
"name": "头像位置",
359+
"description": "设置学生头像在结果中的位置",
360+
"combo_items": ["左侧", "顶部", "右侧", "底部"],
361+
},
343362
"open_student_image_folder": {
344363
"name": "学生图片文件夹",
345364
"description": "管理学生图片文件,图片文件名需与学生姓名一致",
@@ -380,16 +399,6 @@
380399
"2": "Semi-repeatedly pick",
381400
},
382401
},
383-
"clear_record": {
384-
"name": "Clear history method",
385-
"description": "Set the method to clear Quick Pick records",
386-
"combo_items": {"0": "Clear on restart", "1": "Until all have been picked"},
387-
"combo_items_other": {
388-
"0": "Clear on restart",
389-
"1": "Until all have been picked",
390-
"2": "Do not clear",
391-
},
392-
},
393402
"half_repeat": {
394403
"name": "Semi-repeated pick count",
395404
"description": "Set the maximum picked times of each person to clean history",
@@ -461,6 +470,11 @@
461470
"name": "Show student images",
462471
"description": "Set whether to show student images",
463472
},
473+
"student_image_position": {
474+
"name": "Image position",
475+
"description": "Set the position of student images in results",
476+
"combo_items": {"0": "Left", "1": "Top", "2": "Right", "3": "Bottom"},
477+
},
464478
"open_student_image_folder": {
465479
"name": "Student image folder",
466480
"description": "Manage student image files. Picture file names must match student name",
@@ -536,6 +550,11 @@
536550
"description": "设置抽奖结果显示格式",
537551
"combo_items": ["序号+名称", "名称", "序号"],
538552
},
553+
"display_style": {
554+
"name": "结果显示样式",
555+
"description": "设置抽奖结果显示样式",
556+
"combo_items": ["默认样式", "卡片样式"],
557+
},
539558
"show_random": {
540559
"name": "显示随机学生格式",
541560
"description": "设置显示随机学生抽取结果格式",
@@ -585,6 +604,11 @@
585604
"description": "设置是否显示奖品图片",
586605
"switchbutton_name": {"enable": "", "disable": ""},
587606
},
607+
"lottery_image_position": {
608+
"name": "图片位置",
609+
"description": "设置奖品图片在结果中的位置",
610+
"combo_items": ["左侧", "顶部", "右侧", "底部"],
611+
},
588612
"open_lottery_image_folder": {
589613
"name": "奖品图片文件夹",
590614
"description": "管理奖品图片文件,图片文件名需与奖品名称一致",
@@ -662,6 +686,11 @@
662686
"description": "Set the lottery results display format",
663687
"combo_items": {"0": "Serial + Name", "1": "Name", "2": "Serial"},
664688
},
689+
"display_style": {
690+
"name": "Result display style",
691+
"description": "Set the lottery result display style",
692+
"combo_items": {"0": "Default", "1": "Card"},
693+
},
665694
"show_random": {
666695
"name": "Random student display format",
667696
"description": "Set random student display format in lottery results",
@@ -724,6 +753,11 @@
724753
"name": "Show prize images",
725754
"description": "Set whether to show prize images",
726755
},
756+
"lottery_image_position": {
757+
"name": "Image position",
758+
"description": "Set the position of prize images in results",
759+
"combo_items": {"0": "Left", "1": "Top", "2": "Right", "3": "Bottom"},
760+
},
727761
"open_lottery_image_folder": {
728762
"name": "Prize image folder",
729763
"description": "Manage s\nprize image files. Picture file names must match prize names",

app/Language/modules/more_settings.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"website": {"name": "SecRandom 官网", "description": "访问SecRandom软件官网"},
8383
"copyright": {"name": "版权", "description": "SecRandom遵循GPL-3.0协议"},
8484
"version": {"name": "版本", "description": "显示当前软件版本号"},
85+
"user_id": {"name": "用户ID", "description": "用于错误追踪的离线唯一标识"},
8586
},
8687
"EN_US": {
8788
"title": {"name": "About", "description": "APP about page"},
@@ -118,6 +119,10 @@
118119
},
119120
"copyright": {"name": "Copyright", "description": "SecRandom follows GPL-3.0"},
120121
"version": {"name": "Version", "description": "Show current version"},
122+
"user_id": {
123+
"name": "User ID",
124+
"description": "Offline unique identifier for error tracking",
125+
},
121126
},
122127
}
123128

app/common/display/result_display.py

Lines changed: 92 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@
66
import weakref
77
from loguru import logger
88

9-
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMenu
9+
from PySide6.QtWidgets import QWidget, QHBoxLayout, QVBoxLayout, QMenu, QSizePolicy
1010
from PySide6.QtGui import QMouseEvent
1111
from PySide6.QtCore import Qt, QPoint, QTimer, QEvent
12-
from qfluentwidgets import BodyLabel, AvatarWidget, qconfig
12+
from qfluentwidgets import BodyLabel, AvatarWidget, ElevatedCardWidget, qconfig
1313

1414
from app.tools.variable import (
1515
STUDENT_ID_FORMAT,
@@ -294,7 +294,7 @@ def _format_student_text(
294294

295295
@staticmethod
296296
def _create_student_label_with_avatar(
297-
image_path, name, font_size, draw_count, text
297+
image_path, name, font_size, draw_count, text, image_position=0
298298
):
299299
"""
300300
创建带头像的学生标签
@@ -313,21 +313,35 @@ def _create_student_label_with_avatar(
313313
container = QWidget()
314314
container.setAttribute(Qt.WA_DeleteOnClose) # 自动清理
315315

316-
# 创建水平布局
317-
h_layout = QHBoxLayout(container)
318-
h_layout.setSpacing(AVATAR_LABEL_SPACING)
319-
h_layout.setContentsMargins(0, 0, 0, 0)
316+
try:
317+
image_position = int(image_position)
318+
except Exception:
319+
image_position = 0
320+
321+
use_vertical_layout = image_position in (1, 3)
322+
layout = (
323+
QVBoxLayout(container) if use_vertical_layout else QHBoxLayout(container)
324+
)
325+
layout.setSpacing(AVATAR_LABEL_SPACING)
326+
layout.setContentsMargins(0, 0, 0, 0)
320327

321-
# 创建头像
322328
avatar = ResultDisplayUtils._create_avatar_widget(image_path, name, font_size)
323-
avatar.setRadius(font_size * 2 if draw_count == 1 else font_size // 2)
329+
avatar.setRadius(font_size * 2 if draw_count == 1 else int(font_size * 1.5))
324330

325-
# 创建文本标签
326331
text_label = BodyLabel(text)
327332

328-
# 添加到布局
329-
h_layout.addWidget(avatar)
330-
h_layout.addWidget(text_label)
333+
if image_position == 3:
334+
layout.addWidget(text_label, 0, Qt.AlignmentFlag.AlignHCenter)
335+
layout.addWidget(avatar, 0, Qt.AlignmentFlag.AlignHCenter)
336+
elif image_position == 2:
337+
layout.addWidget(text_label, 0, Qt.AlignmentFlag.AlignVCenter)
338+
layout.addWidget(avatar, 0, Qt.AlignmentFlag.AlignVCenter)
339+
elif image_position == 1:
340+
layout.addWidget(avatar, 0, Qt.AlignmentFlag.AlignHCenter)
341+
layout.addWidget(text_label, 0, Qt.AlignmentFlag.AlignHCenter)
342+
else:
343+
layout.addWidget(avatar, 0, Qt.AlignmentFlag.AlignVCenter)
344+
layout.addWidget(text_label, 0, Qt.AlignmentFlag.AlignVCenter)
331345

332346
# 内存优化:跟踪创建的widget以便清理
333347
ResultDisplayUtils._weak_widget_refs.add(container)
@@ -385,22 +399,21 @@ def _apply_label_style(
385399
if custom_font and use_global_font == 1:
386400
style_sheet = f"font-family: '{custom_font}'; {style_sheet}"
387401

388-
if (
389-
isinstance(label, QWidget)
390-
and hasattr(label, "layout")
391-
and label.layout() is not None
392-
):
393-
layout = label.layout()
394-
if layout:
402+
def apply_to_widget(widget):
403+
if isinstance(widget, BodyLabel):
404+
widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
405+
widget.setStyleSheet(style_sheet)
406+
return
407+
if isinstance(widget, QWidget) and widget.layout() is not None:
408+
layout = widget.layout()
395409
for i in range(layout.count()):
396410
item = layout.itemAt(i)
397-
widget = item.widget()
398-
if isinstance(widget, BodyLabel):
399-
widget.setAlignment(Qt.AlignmentFlag.AlignCenter)
400-
widget.setStyleSheet(style_sheet)
401-
else:
402-
label.setAlignment(Qt.AlignmentFlag.AlignCenter)
403-
label.setStyleSheet(style_sheet)
411+
child = item.widget()
412+
if child is not None:
413+
apply_to_widget(child)
414+
415+
if isinstance(label, QWidget):
416+
apply_to_widget(label)
404417

405418
@staticmethod
406419
def _find_student_image(image_dir, image_name):
@@ -419,7 +432,9 @@ def create_student_label(
419432
font_size=50,
420433
animation_color=0,
421434
display_format=0,
435+
display_style=None,
422436
show_student_image=False,
437+
image_position=None,
423438
group_index=0,
424439
show_random=0,
425440
settings_group="roll_call_settings",
@@ -456,6 +471,29 @@ def create_student_label(
456471
image_dir = (
457472
"prize_images" if settings_group == "lottery_settings" else "student_images"
458473
)
474+
if display_style is None:
475+
try:
476+
display_style = readme_settings_async(settings_group, "display_style")
477+
except Exception:
478+
display_style = 0
479+
480+
image_position_key = (
481+
"lottery_image_position"
482+
if settings_group == "lottery_settings"
483+
else "student_image_position"
484+
)
485+
if image_position is None:
486+
try:
487+
image_position = readme_settings_async(
488+
settings_group, image_position_key
489+
)
490+
except Exception:
491+
image_position = 0
492+
493+
try:
494+
image_position = int(image_position)
495+
except Exception:
496+
image_position = 0
459497

460498
for i, (num, selected, exist) in enumerate(selected_students):
461499
current_image_path = None
@@ -490,7 +528,6 @@ def create_student_label(
490528
is_group_mode=(group_index == 1),
491529
show_random=show_random,
492530
)
493-
494531
# 使用支持触屏的容器包装所有内容,确保整个区域都能响应触屏操作
495532
touch_container = TouchResultWidget()
496533
touch_container.setAttribute(Qt.WA_DeleteOnClose) # 自动清理
@@ -504,16 +541,42 @@ def create_student_label(
504541
# 在小组模式下,只在没有成员显示时才显示头像
505542
if show_student_image:
506543
label = ResultDisplayUtils._create_student_label_with_avatar(
507-
current_image_path, name, font_size, draw_count, text
544+
current_image_path,
545+
name,
546+
font_size,
547+
draw_count,
548+
text,
549+
image_position,
508550
)
509551
else:
510552
label = BodyLabel(text)
511553
label.setAttribute(Qt.WA_DeleteOnClose) # 自动清理
512554

555+
card_widget = None
556+
if display_style == 1:
557+
card_widget = ElevatedCardWidget()
558+
card_widget.setAttribute(Qt.WA_DeleteOnClose)
559+
card_layout = QVBoxLayout(card_widget)
560+
card_layout.setContentsMargins(12, 12, 12, 12)
561+
card_layout.setSpacing(4)
562+
card_layout.addWidget(label, 0, Qt.AlignmentFlag.AlignCenter)
563+
label = card_widget
564+
513565
ResultDisplayUtils._apply_label_style(
514566
label, font_size, animation_color, settings_group, custom_font_family
515567
)
516568

569+
if card_widget is not None:
570+
card_widget.setSizePolicy(
571+
QSizePolicy.Policy.MinimumExpanding,
572+
QSizePolicy.Policy.MinimumExpanding,
573+
)
574+
layout = card_widget.layout()
575+
if layout is not None:
576+
layout.setSizeConstraint(QVBoxLayout.SizeConstraint.SetMinimumSize)
577+
layout.activate()
578+
card_widget.setMinimumSize(layout.sizeHint())
579+
517580
# 将标签添加到触屏容器中
518581
inner_layout.addWidget(label)
519582
student_labels[i] = touch_container

0 commit comments

Comments
 (0)