From 03a9948c9f34f6e13110c36467424a3f2bf6b181 Mon Sep 17 00:00:00 2001 From: lrs2187 Date: Sun, 1 Feb 2026 15:56:08 +0800 Subject: [PATCH 1/5] =?UTF-8?q?chore:=20=E6=9B=BF=E6=8D=A2=20sr4ci.interfa?= =?UTF-8?q?ce.dll=20=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/dlls/SecRandom4Ci.Interface.dll | Bin 12288 -> 14336 bytes data/dlls/SecRandom4Ci.Interface.pdb | Bin 21240 -> 23784 bytes 2 files changed, 0 insertions(+), 0 deletions(-) diff --git a/data/dlls/SecRandom4Ci.Interface.dll b/data/dlls/SecRandom4Ci.Interface.dll index 48e8faf904ad3295e4b59148da33117002a8fb3c..95bd427f9eff9973d3d3508df7905a2c37bc7bd4 100644 GIT binary patch delta 6133 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 delta 4520 zcmb7HeQ*@z8Gqh)KW_JuOD^9)5OVpvd>CTTL<9?&Foq1+MgF;@Ni6Him?#=%8 z{XO6B^X|U8msporxnpbLUC!_W>QeUAkziM}uf zB3Y>kqEv7biltseS9!}-S+KPXq5_;z?|xOOD!fCgOjUdDs=}$YO%UT)gj176zkzAX z3?k(ntf}`}w5hgw%k=hmMOKZXtzt^lrHIybPa_H@g2>gCGf7jJ)=yHDVsqv zPSP}{cTduErazgaVWxvV%?u_om>-^0XL=tR_4){TCFVRmL0-E#M;YFuW}_2K>oN~X#>2h((^)j4-Rjk)N zyc*}6j_aN}7{sLTZY*FhCgtSCBtcPf;jT|_@fXecK3YmKx*{rRk(wTdWgnwJ&Nb0=!W%O9e1tn=KJnp zwChUjI7Q2DpfU6d8v_+JEo)wg>q+o+UPh?$3OqNmKjNt++_MA+nvc`Lxd|t#ArvUP zBb&~?@X@fb}%B5{|7DdlDIKf`=+TgO+ zBf+}BZu*%_sgXFBV=Z#x2tm`8#IQgrh}Q7A7qpfuBVig>9K~1Z!+jpRnH%x&MSNU3Rpj&Za3z=Il}*VIl=S z+ZV@b+O*oIA@?&CpmjbgbhQr9vpy>hhO|R3`>Zyo@Nfr;xtJ}^LOVmd6!uxGodb4L zl1XVn+UDyxeUNtgY@dpUv5B4V>9F&eN}>0C_L8G@3RRXQQ*ioJy4+`+K9x55jMImx z&u5%IM8Egh7iyYLqj8_5=$T;or4o}%i&Hw?l%!693h8uO>9cCAU^?yd*~_RqOi%l4 z4C65U%V*7QiN^O)S+dZjZaG*}lF95dspA6HC2TY0(mN`iNxeQTr&B76cKB=`RqJee z%xBM2y-x0{AK=xY=wswkbpAMGv1F(De`5T9ID8$NXO%oG%-N+Qw!#M&-*8ibLF@rX z>@Zy>I7hHSuvzdr!R3M-z#QrXD!Kh z({lAHEs^okNy#VJo|9U(Tt$6uo?1maoQUdF<7PRqNzGDgM7~Dk>t(!N#+zikNyhi6 zoxv8>hiKT^Q7HERZKB>L>YXy)DdWRpvYbkBWR$?2n24F|nTz z`GnY?68lp!jWc3%Mr@Sg9w^0&VyHN`%TT;FuHsd36*np(MiDV8QfyNsHsxYdE;bEf z(;zm@B5xLXo5;i(*g|gQ6Ib@raC1s!{sDm=MW? zNR*ZtXr4iV9;Hu>h)5zLX^?S)jN9~Yk-k^3PjjaSW&F5|M=*|WR}&&4gVQL39U_7Y zAW1bFWZWj$D>x`PBKQk)l%|-<;{I*GdOt&{c!BY&$--8JPg#7P%*VU8)NKUT1+N9J zu&)Cq<)fv}Hx=o68Pv6kO~=K#)xFt!cG`fqC;uv|UHwpXdhg{InRlzdE6<)@eA(S9 z6MHXz>%zl766y(Gc1}VB2mTzUl%ZRuKd-!bGg^iY&v?ohx~DKp4Lx1-f#JPS_KG(a zeFFakK0mPk-c@NuO^3{?6OS*My2#sFeh7bz=U3ccSZwEHCWe)hyo9u!7J#5%Wft>w zSYUC9K;T@|?onjP_gEM3nCPF9ws6&q1#qtHg7 z7@Ao%s)o$!n^bMrn+K1Ry0(QU7suIp4Nm;!ICt=O4*s~x>+fyo-i~_PXBCD|yf^mc zuAI&#PknLv#9OyrI_|wZtE<`Dnf5Q_bIo(rQ09^wRpFjJl82KuzGkDIy?H diff --git a/data/dlls/SecRandom4Ci.Interface.pdb b/data/dlls/SecRandom4Ci.Interface.pdb index d74340c5bbc2d9010c5b65f7fab843f36083b32b..36841eaf638b1c51d425842668f85420dbea0acd 100644 GIT binary patch delta 6482 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 delta 4166 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 F{|{RQsyP4v From 11a550e98d35a7ee7b5a56947bc2bc0814577710 Mon Sep 17 00:00:00 2001 From: lrs2187 Date: Mon, 2 Feb 2026 22:43:06 +0800 Subject: [PATCH 2/5] =?UTF-8?q?fix:=20pre-commit=20=E5=9C=A8=20vendors=20?= =?UTF-8?q?=E5=87=BA=E9=94=99=E8=AF=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- data/dlls/dotnet.runtimeconfig.json | 2 +- vendors/pythonnet-stub-generator/LICENCE.md | 2 +- vendors/pythonnet-stub-generator/csharp/.gitignore | 2 +- .../csharp/PythonNetStubGenerator.sln.DotSettings | 2 +- .../csharp/PythonNetStubGenerator/ClassScope.cs | 2 +- .../csharp/PythonNetStubGenerator/MethodComparer.cs | 4 ++-- .../csharp/PythonNetStubGenerator/PythonStubTask.cs | 2 +- .../PythonNetStubGenerator/StringBuilderExtensions.cs | 6 +++--- .../csharp/PythonNetStubGenerator/StubBuilder.cs | 4 ++-- .../csharp/PythonNetStubGenerator/StubWriter.cs | 4 ++-- .../csharp/PythonNetStubGenerator/SymbolScope.cs | 4 ++-- .../csharp/PythonNetStubTool/Program.cs | 2 +- 12 files changed, 18 insertions(+), 18 deletions(-) diff --git a/data/dlls/dotnet.runtimeconfig.json b/data/dlls/dotnet.runtimeconfig.json index 77961a6f..dce8e146 100644 --- a/data/dlls/dotnet.runtimeconfig.json +++ b/data/dlls/dotnet.runtimeconfig.json @@ -19,4 +19,4 @@ "CSWINRT_USE_WINDOWS_UI_XAML_PROJECTIONS": false } } -} \ No newline at end of file +} diff --git a/vendors/pythonnet-stub-generator/LICENCE.md b/vendors/pythonnet-stub-generator/LICENCE.md index cc83c82d..96d355a7 100644 --- a/vendors/pythonnet-stub-generator/LICENCE.md +++ b/vendors/pythonnet-stub-generator/LICENCE.md @@ -19,4 +19,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/vendors/pythonnet-stub-generator/csharp/.gitignore b/vendors/pythonnet-stub-generator/csharp/.gitignore index 06262728..a437a653 100644 --- a/vendors/pythonnet-stub-generator/csharp/.gitignore +++ b/vendors/pythonnet-stub-generator/csharp/.gitignore @@ -34,4 +34,4 @@ msbuild.err msbuild.wrn # Visual Studio 2015 -.vs/ \ No newline at end of file +.vs/ diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings index 0e3eaee1..a6107553 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator.sln.DotSettings @@ -1,4 +1,4 @@  True True - True \ No newline at end of file + True diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs index d2a7517c..22629be5 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/ClassScope.cs @@ -54,4 +54,4 @@ public static IEnumerable AccessibleGenerics } } -} \ No newline at end of file +} diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs index 01d69f43..9e478d51 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/MethodComparer.cs @@ -16,7 +16,7 @@ public int Compare(MethodInfo a, MethodInfo b) var aName = a.NonGenericName(); var bName = b.NonGenericName(); - + var nameCompare = string.Compare(aName, bName, StringComparison.InvariantCulture); if (nameCompare != 0) return nameCompare; @@ -84,4 +84,4 @@ float GetDepth(Type t, bool addGenerics) return string.Compare(aParamString, bParamString, StringComparison.Ordinal); } } -} \ No newline at end of file +} diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs index a3460e00..b696db7d 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/PythonStubTask.cs @@ -38,4 +38,4 @@ public override bool Execute() } } -} \ No newline at end of file +} diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs index 4cf52c8c..80ad8d0e 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StringBuilderExtensions.cs @@ -4,7 +4,7 @@ namespace PythonNetStubGenerator { - + public static class StringBuilderExtensions { public static StringBuilder Indent(this StringBuilder sb) @@ -22,5 +22,5 @@ public class IndentScope: IDisposable public IndentScope() => IndentLevel++; public void Dispose() => IndentLevel--; } - -} \ No newline at end of file + +} diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs index b126e49c..ff40ca73 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubBuilder.cs @@ -9,7 +9,7 @@ namespace PythonNetStubGenerator public static class StubBuilder { private static HashSet SearchPaths { get; } = new HashSet(); - + public static DirectoryInfo BuildAssemblyStubs(DirectoryInfo destPath, FileInfo[] targetAssemblyPaths, DirectoryInfo[] searchPaths = null) { // prepare resolver @@ -21,7 +21,7 @@ public static DirectoryInfo BuildAssemblyStubs(DirectoryInfo destPath, FileInfo[ { var assemblyToStub = Assembly.LoadFrom(targetAssemblyPath.FullName); SearchPaths.Add(targetAssemblyPath.Directory); - + if (searchPaths != null) foreach (var path in SearchPaths) SearchPaths.Add(path); diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs index c6471e98..5832cf79 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/StubWriter.cs @@ -728,7 +728,7 @@ private static bool IsGenericMethodCallable(MethodInfo method) // be used more than once in Method signatures. In CLR, this is not the case, since the // Type of a single parameter can sometimes be used to infer the generic parameter of the method, // which can point to a different implementation/specialization. - // For now, I will assume that Python.NET uses some runtime information in the object reference to + // For now, I will assume that Python.NET uses some runtime information in the object reference to // dispatch the correct method. And we can use the type bound to type the method parameter. // Todo: I've skipped this complication. For now we'll force the user to pass in the generic parameters @@ -898,7 +898,7 @@ private static void WriteEnum(StringBuilder sb, Type stubType) var underlyingType = stubType.GetEnumUnderlyingType().ToPythonType(); sb.Indent().AppendLine($"class {stubType.Name}(typing.SupportsInt):"); using var _ = new IndentScope(); - + sb.Indent().AppendLine("@typing.overload"); sb.Indent().AppendLine($"def __init__(self, value : {underlyingType}) -> None: ..."); sb.Indent().AppendLine("@typing.overload"); diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs index 3325b993..412e4462 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubGenerator/SymbolScope.cs @@ -22,7 +22,7 @@ public void Dispose() Scopes.Remove(this); } - public bool HasConflict(string cleanName, string typeNamespace) => + public bool HasConflict(string cleanName, string typeNamespace) => typeNamespace != Namespace && ReservedSymbols.Contains(cleanName); } -} \ No newline at end of file +} diff --git a/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs b/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs index e4aa889d..98133748 100644 --- a/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs +++ b/vendors/pythonnet-stub-generator/csharp/PythonNetStubTool/Program.cs @@ -34,7 +34,7 @@ static int Main( infos.Add(assemblyPath); } - + Console.WriteLine($"building stubs..."); try From 54a621f359b81f1f0fa7df5628dba0a99c746662 Mon Sep 17 00:00:00 2001 From: lrs2187 Date: Mon, 2 Feb 2026 22:59:28 +0800 Subject: [PATCH 3/5] =?UTF-8?q?feat(IPC):=20=E4=BC=98=E5=8C=96=20C#=20IPC?= =?UTF-8?q?=20=E9=80=9A=E7=9F=A5=E4=BB=A5=E6=94=AF=E6=8C=81=E4=BC=A0?= =?UTF-8?q?=E9=80=92=E6=9B=B4=E5=A4=9A=E6=95=B0=E6=8D=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- CHANGELOG/v2.3.0-beta.2/CHANGELOG.md | 1 + app/common/IPC_URL/csharp_ipc_handler.py | 108 ++++++++++++++-- app/common/lottery/lottery_manager.py | 118 ++++++++++++++++- .../notification/notification_service.py | 119 +++++++++++++++--- app/common/roll_call/roll_call_manager.py | 9 ++ app/common/roll_call/roll_call_utils.py | 109 ++++++++++++++++ app/view/guide/pages.py | 14 ++- app/view/main/quick_draw_animation.py | 16 ++- 8 files changed, 455 insertions(+), 39 deletions(-) diff --git a/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md b/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md index ce8d0084..405be9e7 100644 --- a/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md +++ b/CHANGELOG/v2.3.0-beta.2/CHANGELOG.md @@ -15,6 +15,7 @@ v2.3 - Shiroko (砂狼白子) beta 2 - 优化 **浮窗**,切换同步收纳显示 - 优化 **计时器**,倒计时页面居中显示,秒表居中与所有时钟字距优化 - 优化 **更新安装**,管理员静默安装并退出 +- 优化 **ClassIsland 联动**,现在可以传递更多信息 ## 🐛 修复问题 diff --git a/app/common/IPC_URL/csharp_ipc_handler.py b/app/common/IPC_URL/csharp_ipc_handler.py index 7bd9260a..734f1efd 100644 --- a/app/common/IPC_URL/csharp_ipc_handler.py +++ b/app/common/IPC_URL/csharp_ipc_handler.py @@ -1,13 +1,23 @@ import sys import asyncio import threading -from typing import Optional +from typing import Optional, Any, TypedDict from loguru import logger from app.tools.path_utils import get_data_path CSHARP_AVAILABLE = False + +class SelectedStudentNotificationInfo(TypedDict): + student_id: int + student_name: str + display_text: str + exists: bool + group_name: str + lottery_name: str + + if sys.platform == "win32": try: sys.path.append(str(get_data_path("dlls"))) @@ -31,7 +41,12 @@ GeneratedIpcFactory, ) from SecRandom4Ci.Interface.Enums import ResultType - from SecRandom4Ci.Interface.Models import CallResult, NotificationData, Student + from SecRandom4Ci.Interface.Models import ( + CallResult, + Student, + NotificationData, + NotificationItem, + ) from SecRandom4Ci.Interface.Services import ISecRandomService CSHARP_AVAILABLE = True @@ -117,7 +132,7 @@ def stop_ipc_client(self): def send_notification( self, class_name, - selected_students, + selected_students: list[SelectedStudentNotificationInfo], draw_count=1, settings=None, settings_group=None, @@ -130,6 +145,69 @@ def send_notification( if not self.is_connected: return False + def _safe_int(value: Any) -> int: + try: + if value is None: + return 0 + return int(value) + except Exception: + return 0 + + def _coerce_student(value: Any) -> SelectedStudentNotificationInfo | None: + if isinstance(value, dict): + student_id = _safe_int(value.get("student_id", value.get("id", 0))) + student_name = str( + value.get("student_name", value.get("name", "")) or "" + ) + display_text = str( + value.get( + "display_text", value.get("display", value.get("text", "")) + ) + or student_name + ) + exists = bool(value.get("exists", value.get("exist", True))) + group_name = str( + value.get("group_name", value.get("group", "")) or "" + ) + lottery_name = str( + value.get( + "lottery_name", + value.get( + "lottery", + value.get("prize_name", value.get("prize", "")), + ), + ) + or "" + ) + return { + "student_id": student_id, + "student_name": student_name, + "display_text": display_text, + "exists": exists, + "group_name": group_name, + "lottery_name": lottery_name, + } + + if isinstance(value, (list, tuple)) and len(value) >= 3: + student_name = str(value[1] or "") + return { + "student_id": _safe_int(value[0]), + "student_name": student_name, + "display_text": student_name, + "exists": bool(value[2]), + "group_name": "", + "lottery_name": "", + } + + return None + + coerced_students: list[SelectedStudentNotificationInfo] = [] + for student in selected_students or []: + item = _coerce_student(student) + if item is None: + continue + coerced_students.append(item) + if settings: display_duration = settings.get("notification_display_duration", 5) else: @@ -156,11 +234,11 @@ def send_notification( result.ClassName = class_name result.DrawCount = draw_count result.DisplayDuration = display_duration - for student in selected_students: + for student in coerced_students: cs_student = Student() - cs_student.StudentId = student[0] - cs_student.StudentName = student[1] - cs_student.Exists = student[2] + cs_student.StudentId = student["student_id"] + cs_student.StudentName = student["display_text"] + cs_student.Exists = student["exists"] result.SelectedStudents.Add(cs_student) randomService.NotifyResult(result) @@ -193,12 +271,16 @@ def send_notification( data.ClassName = class_name data.DrawCount = draw_count data.DisplayDuration = display_duration - for student in selected_students: - cs_student = Student() - cs_student.StudentId = student[0] - cs_student.StudentName = student[1] - cs_student.Exists = student[2] - data.Items.Add(cs_student) + for student in coerced_students: + item = NotificationItem() + item.StudentId = student["student_id"] + item.StudentName = student["student_name"] + item.Exists = student["exists"] + item.HasGroup = bool(student["group_name"]) + item.GroupName = student["group_name"] + item.IsLottery = bool(student["lottery_name"]) + item.LotteryName = student["lottery_name"] + data.Items.Add(item) randomService.ShowNotification(data) return True diff --git a/app/common/lottery/lottery_manager.py b/app/common/lottery/lottery_manager.py index 5c37005d..96b44046 100644 --- a/app/common/lottery/lottery_manager.py +++ b/app/common/lottery/lottery_manager.py @@ -376,7 +376,16 @@ def get_random_items(self, count): selected_prizes = [system_random.choice(self.prizes) for _ in range(count)] if not self.enable_student_assignment or not self.current_class_name: - return selected_prizes + prizes_with_meta = [] + for prize in selected_prizes: + prize_copy = dict(prize) + prize_name = prize_copy.get("name", "") + prize_copy["ipc_lottery_name"] = str(prize_name or "") + prize_copy["ipc_group_name"] = "" + prize_copy["ipc_student_name"] = "" + prize_copy["ipc_display_text"] = str(prize_name or "") + prizes_with_meta.append(prize_copy) + return prizes_with_meta candidates = RollCallUtils._get_filtered_candidates( self.current_class_name, @@ -400,6 +409,7 @@ def get_random_items(self, count): for prize in selected_prizes: prize_copy = dict(prize) prize_name = prize_copy.get("name", "") + prize_copy["ipc_lottery_name"] = str(prize_name or "") group_name = "" student_name = "" @@ -422,10 +432,13 @@ def get_random_items(self, count): else: student_name = system_random.choice(candidates).get("name", "") + prize_copy["ipc_group_name"] = str(group_name or "") + prize_copy["ipc_student_name"] = str(student_name or "") if group_name or student_name: prize_copy["name"] = self._format_prize_student_text( prize_name, group_name, student_name, show_random ) + prize_copy["ipc_display_text"] = str(prize_copy.get("name", "") or "") prizes_with_students.append(prize_copy) @@ -502,6 +515,7 @@ def draw_final_items(self, count): except Exception: show_random = 0 + include_group = show_random in (0, 1, 2, 5, 6, 7, 8, 9) from app.common.data.list import get_group_members for idx, prize in enumerate(selected_prizes_dict): @@ -522,6 +536,9 @@ def draw_final_items(self, count): ) display_name = prize_name + ipc_group_name = "" + ipc_student_name = "" + ipc_display_text = str(prize_name or "") if student_tuple and len(student_tuple) >= 2 and student_tuple[1]: group_name = "" student_name = "" @@ -545,18 +562,29 @@ def draw_final_items(self, count): else: student_name = str(student_tuple[1]) + ipc_group_name = str(group_name or "") + ipc_student_name = str(student_name or "") display_name = self._format_prize_student_text( prize_name, group_name, student_name, show_random ) + ipc_display_text = str(display_name or "") selected_prizes_with_students.append((prize_id, display_name, prize_exist)) prize_copy = dict(prize) + prize_copy["ipc_lottery_name"] = str(prize_name or "") + prize_copy["ipc_group_name"] = ipc_group_name if include_group else "" + prize_copy["ipc_student_name"] = ipc_student_name + prize_copy["ipc_display_text"] = ipc_display_text if isinstance(student_dict, dict): prize_copy["student"] = student_dict prize_copy["student_id"] = student_dict.get("id", "") prize_copy["student_name"] = student_dict.get("name", "") prize_copy["student_exist"] = student_dict.get("exist", True) + if include_group and not prize_copy["ipc_group_name"]: + prize_copy["ipc_group_name"] = str( + student_dict.get("group", "") or "" + ) updated_prizes_dict.append(prize_copy) result["selected_prizes"] = selected_prizes_with_students @@ -937,11 +965,65 @@ def stop_animation(widget): settings = widget.manager.get_notification_settings(refresh=True) if settings is not None: + settings_for_notify = ( + dict(settings) if isinstance(settings, dict) else settings + ) + show_random = readme_settings_async("lottery_settings", "show_random") + try: + show_random = int(show_random or 0) + except Exception: + show_random = 0 + include_group = show_random in (0, 1, 2, 5, 6, 7, 8, 9) + ipc_selected_students = [] + for prize in widget.final_selected_students_dict or []: + if not isinstance(prize, dict): + continue + student = prize.get("student") + if not isinstance(student, dict): + student = None + try: + student_id = int(prize.get("student_id", 0) or 0) + except Exception: + student_id = 0 + if not student_id and student is not None: + try: + student_id = int(student.get("id", 0) or 0) + except Exception: + student_id = 0 + student_name = str( + prize.get("ipc_student_name", "") + or prize.get("student_name", "") + or "" + ) + display_text = str( + prize.get("ipc_display_text", "") or prize.get("name", "") or "" + ) + group_name = str(prize.get("ipc_group_name", "") or "") + if not include_group: + group_name = "" + lottery_name = str( + prize.get("ipc_lottery_name", "") or prize.get("name", "") or "" + ) + exists = bool(prize.get("student_exist", prize.get("exist", True))) + ipc_selected_students.append( + { + "student_id": student_id, + "student_name": student_name, + "display_text": display_text, + "exists": exists, + "group_name": group_name, + "lottery_name": lottery_name, + } + ) + + if ipc_selected_students and isinstance(settings_for_notify, dict): + settings_for_notify["ipc_selected_students"] = ipc_selected_students + ResultDisplayUtils.show_notification_if_enabled( widget.final_pool_name, widget.final_selected_students, actual_draw_count, - settings, + settings_for_notify, settings_group="lottery_notification_settings", ) @@ -991,6 +1073,24 @@ def draw_random(widget): display_count = min(display_count, remaining_count) prizes = widget.manager.get_random_items(display_count) + ipc_selected_students = [] + for p in prizes or []: + if not isinstance(p, dict): + continue + ipc_selected_students.append( + { + "student_id": 0, + "student_name": str(p.get("ipc_student_name", "") or ""), + "display_text": str( + p.get("ipc_display_text", p.get("name", "")) or "" + ), + "exists": bool(p.get("exist", True)), + "group_name": str(p.get("ipc_group_name", "") or ""), + "lottery_name": str( + p.get("ipc_lottery_name", p.get("name", "")) or "" + ), + } + ) selected_prizes = [(p["id"], p["name"], p.get("exist", True)) for p in prizes] display_result_animated( @@ -998,6 +1098,7 @@ def draw_random(widget): selected_prizes, widget.manager.current_pool_name, draw_count=display_count, + ipc_selected_students=ipc_selected_students, ) @@ -1034,7 +1135,9 @@ def display_result(widget, selected_students, pool_name, draw_count=None): ResultDisplayUtils.display_results_in_grid(widget.result_grid, student_labels) -def display_result_animated(widget, selected_students, pool_name, draw_count=None): +def display_result_animated( + widget, selected_students, pool_name, draw_count=None, ipc_selected_students=None +): render_settings = widget.manager.get_render_settings(refresh=False) if draw_count is None: draw_count = widget.current_count @@ -1069,11 +1172,18 @@ def display_result_animated(widget, selected_students, pool_name, draw_count=Non settings = widget.manager.get_notification_settings(refresh=False) if settings is not None: + settings_for_notify = dict(settings) if isinstance(settings, dict) else settings + if ( + ipc_selected_students + and isinstance(settings_for_notify, dict) + and isinstance(ipc_selected_students, list) + ): + settings_for_notify["ipc_selected_students"] = ipc_selected_students ResultDisplayUtils.show_notification_if_enabled( pool_name, selected_students, draw_count, - settings, + settings_for_notify, settings_group="lottery_notification_settings", is_animating=True, ) diff --git a/app/common/notification/notification_service.py b/app/common/notification/notification_service.py index 9ac29a51..44210a32 100644 --- a/app/common/notification/notification_service.py +++ b/app/common/notification/notification_service.py @@ -962,15 +962,17 @@ def send_to_classisland( """ try: + import re def _normalize_text(value): text = str(value or "") text = text.replace("\r\n", "\n").replace("\r", "\n") + text = text.strip() if "\n" in text: - text = " - ".join( - [part.strip() for part in text.split("\n") if part.strip()] - ) - return text + text = text.replace("\n", " - ") + text = re.sub(r"\s*-\s*", " - ", text) + text = re.sub(r"\s{2,}", " ", text) + return text.strip() show_random = 0 if settings: @@ -979,6 +981,10 @@ def _normalize_text(value): except Exception: show_random = 0 + ipc_students = None + if isinstance(settings, dict): + ipc_students = settings.get("ipc_selected_students") + group_mode = False for item in selected_students or []: if ( @@ -989,30 +995,85 @@ def _normalize_text(value): group_mode = True break - if group_mode: - from app.common.data.list import get_group_members - + if isinstance(ipc_students, list) and ipc_students: + selected_students_for_ipc = [] + for item in ipc_students: + if not isinstance(item, dict): + continue + try: + student_id = int(item.get("student_id", 0) or 0) + except Exception: + student_id = 0 + student_name = _normalize_text(item.get("student_name", "")) + display_text = ( + _normalize_text(item.get("display_text", "")) or student_name + ) + group_name_raw = _normalize_text(item.get("group_name", "")) + lottery_name = _normalize_text(item.get("lottery_name", "")) + is_lottery = bool( + settings_group and "lottery" in str(settings_group) + ) or bool(lottery_name) + group_name = group_name_raw if (group_mode or is_lottery) else "" + if group_mode and (not is_lottery) and show_random == 0: + group_name = "" + selected_students_for_ipc.append( + { + "student_id": student_id, + "student_name": student_name, + "display_text": display_text, + "exists": bool(item.get("exists", True)), + "group_name": group_name, + "lottery_name": lottery_name, + } + ) + elif group_mode: selected_students_for_ipc = [] for item in selected_students or []: if not isinstance(item, (list, tuple)) or len(item) < 3: continue - group_name = _normalize_text(item[1]) + group_display_text = _normalize_text(item[1]) exist = bool(item[2]) - if show_random in (1, 2): - group_members = get_group_members(class_name, group_name) - if group_members: - selected_member = system_random.choice(group_members) - selected_name = _normalize_text( - (selected_member or {}).get("name", "") - ) - if selected_name: - group_name = f"{group_name} - {selected_name}" + group_name = "" + student_name = group_display_text + if show_random > 0 and " - " in group_display_text: + parts = group_display_text.split(" - ", 1) + if len(parts) == 2 and parts[0].strip() and parts[1].strip(): + group_name = parts[0].strip() + student_name = parts[1].strip() selected_students_for_ipc.append( - (0, _normalize_text(group_name), exist) + { + "student_id": 0, + "student_name": student_name, + "display_text": group_display_text, + "exists": exist, + "group_name": group_name, + "lottery_name": "", + } ) else: + student_group_by_id = {} + student_group_by_name = {} + try: + from app.common.data.list import get_student_list + + for student in get_student_list(class_name) or []: + if not isinstance(student, dict): + continue + sid = student.get("id", 0) + sname = str(student.get("name", "") or "") + sgroup = str(student.get("group", "") or "") + try: + student_group_by_id[int(sid or 0)] = sgroup + except Exception: + pass + if sname: + student_group_by_name[sname] = sgroup + except Exception: + student_group_by_id = {} + student_group_by_name = {} + selected_students_for_ipc = [] for item in selected_students or []: if not isinstance(item, (list, tuple)) or len(item) < 3: @@ -1020,8 +1081,28 @@ def _normalize_text(value): student_id = item[0] if student_id is None: student_id = 0 + normalized_name = _normalize_text(item[1]) + exist = bool(item[2]) + + try: + sid = int(student_id or 0) + except Exception: + sid = 0 + group_name = student_group_by_id.get(sid, "") or "" + if not group_name and normalized_name: + group_name = ( + student_group_by_name.get(normalized_name, "") or "" + ) + selected_students_for_ipc.append( - (student_id, _normalize_text(item[1]), bool(item[2])) + { + "student_id": int(student_id or 0), + "student_name": normalized_name, + "display_text": normalized_name, + "exists": exist, + "group_name": "", + "lottery_name": "", + } ) cs_ipc = CSharpIPCHandler.instance() diff --git a/app/common/roll_call/roll_call_manager.py b/app/common/roll_call/roll_call_manager.py index 3693da00..e3734e25 100644 --- a/app/common/roll_call/roll_call_manager.py +++ b/app/common/roll_call/roll_call_manager.py @@ -577,6 +577,7 @@ def stop_animation(widget): result.get("class_name") or widget.manager.current_class_name ) widget.final_selected_students_dict = result.get("selected_students_dict") or [] + widget.final_ipc_selected_students = result.get("ipc_selected_students") or [] widget.final_group_filter = ( result.get("group_filter") or widget.range_combobox.currentText() ) @@ -616,6 +617,9 @@ def stop_animation(widget): selected_students=widget.final_selected_students, draw_count=actual_draw_count, settings_group="roll_call_notification_settings", + ipc_selected_students=getattr( + widget, "final_ipc_selected_students", None + ), ) play_voice_result(widget) @@ -717,6 +721,11 @@ def display_result_animated(widget, selected_students, class_name, draw_count=No if draw_count is None: draw_count = widget.current_count + if group_index == 1: + selected_students = RollCallUtils.render_group_display_students( + class_name, selected_students, display_dict.get("show_random", 0) + ) + student_labels = ResultDisplayUtils.create_student_label( class_name=class_name, selected_students=selected_students, diff --git a/app/common/roll_call/roll_call_utils.py b/app/common/roll_call/roll_call_utils.py index 38f2312f..c01a6860 100644 --- a/app/common/roll_call/roll_call_utils.py +++ b/app/common/roll_call/roll_call_utils.py @@ -291,10 +291,17 @@ def draw_random_students( selected_groups = RollCallUtils.draw_random_groups( students_dict_list, current_count, draw_type ) + show_random = readme_settings_async("roll_call_settings", "show_random") + selected_groups, ipc_selected_students = ( + RollCallUtils.render_group_display_students_and_ipc( + class_name, selected_groups, show_random + ) + ) return { "selected_students": selected_groups, "class_name": class_name, "selected_students_dict": [], + "ipc_selected_students": ipc_selected_students, "group_filter": group_filter, "gender_filter": gender_filter, } @@ -405,6 +412,101 @@ def draw_random_groups(students_dict_list, current_count, draw_type): return selected_groups + @staticmethod + def render_group_display_students(class_name, selected_students, show_random): + rendered, _ = RollCallUtils.render_group_display_students_and_ipc( + class_name, selected_students, show_random + ) + return rendered + + @staticmethod + def render_group_display_students_and_ipc( + class_name, selected_students, show_random + ): + try: + show_random = int(show_random or 0) + except Exception: + show_random = 0 + + try: + from app.common.data.list import get_group_members + except Exception: + get_group_members = None + + rendered = [] + ipc_selected_students = [] + for item in selected_students or []: + if not isinstance(item, (list, tuple)) or len(item) < 3: + continue + + student_id = item[0] + name = str(item[1] or "") + exist = bool(item[2]) + + if student_id is not None: + rendered.append((student_id, name, exist)) + ipc_selected_students.append( + { + "student_id": int(student_id or 0), + "student_name": name, + "display_text": name, + "exists": exist, + "group_name": "", + "lottery_name": "", + } + ) + continue + + group_name = name + selected_name = "" + if ( + show_random > 0 + and get_group_members is not None + and class_name + and group_name + ): + try: + group_members = get_group_members(class_name, group_name) or [] + except Exception: + group_members = [] + + if group_members: + try: + selected_member = system_random.choice(group_members) + except Exception: + selected_member = None + selected_name = str( + (selected_member or {}).get("name", "") or "" + ).strip() + if selected_name: + display_text = f"{group_name} - {selected_name}" + rendered.append((None, display_text, exist)) + ipc_selected_students.append( + { + "student_id": 0, + "student_name": selected_name, + "display_text": display_text, + "exists": exist, + "group_name": group_name, + "lottery_name": "", + } + ) + continue + + rendered.append((None, group_name, exist)) + ipc_selected_students.append( + { + "student_id": 0, + "student_name": group_name, + "display_text": group_name, + "exists": exist, + "group_name": group_name if show_random > 0 else "", + "lottery_name": "", + } + ) + + return rendered, ipc_selected_students + @staticmethod def prepare_notification_settings(): """ @@ -736,6 +838,7 @@ def show_notification_if_enabled( draw_count, settings_group="roll_call_notification_settings", display_settings=None, + ipc_selected_students=None, is_animating=False, ): """ @@ -759,6 +862,12 @@ def show_notification_if_enabled( settings = RollCallUtils.prepare_notification_settings_by_group( settings_group, display_settings ) + if ( + ipc_selected_students + and isinstance(ipc_selected_students, list) + and isinstance(settings, dict) + ): + settings["ipc_selected_students"] = ipc_selected_students ResultDisplayUtils.show_notification_if_enabled( class_name, selected_students, diff --git a/app/view/guide/pages.py b/app/view/guide/pages.py index 5e2862b2..c5db1be0 100644 --- a/app/view/guide/pages.py +++ b/app/view/guide/pages.py @@ -1066,7 +1066,19 @@ def _test_classisland(self): try: handler = CSharpIPCHandler.instance() if handler.is_connected: - handler.send_notification("SecRandom Test", [(0, "Test Student", True)]) + handler.send_notification( + "SecRandom Test", + [ + { + "student_id": 0, + "student_name": "Test Student", + "display_text": "Test Student", + "exists": True, + "group_name": "", + "lottery_name": "", + } + ], + ) self.statusLabel.setText( get_any_position_value_async("guide", "test_page", "success") ) diff --git a/app/view/main/quick_draw_animation.py b/app/view/main/quick_draw_animation.py index 2f52ac04..e9531479 100644 --- a/app/view/main/quick_draw_animation.py +++ b/app/view/main/quick_draw_animation.py @@ -39,6 +39,7 @@ def __init__(self, roll_call_widget): self.final_selected_students = None self.final_class_name = None self.final_selected_students_dict = None + self.final_ipc_selected_students = None self.final_group_filter = None self.final_gender_filter = None @@ -127,6 +128,7 @@ def _set_final_result(self, result): self.final_selected_students = result["selected_students"] self.final_class_name = result["class_name"] self.final_selected_students_dict = result["selected_students_dict"] + self.final_ipc_selected_students = result.get("ipc_selected_students") self.final_group_filter = result["group_filter"] self.final_gender_filter = result["gender_filter"] @@ -136,6 +138,9 @@ def _sync_final_result_to_widget(self): self.roll_call_widget.final_selected_students_dict = ( self.final_selected_students_dict ) + self.roll_call_widget.final_ipc_selected_students = ( + self.final_ipc_selected_students + ) self.roll_call_widget.final_group_filter = self.final_group_filter self.roll_call_widget.final_gender_filter = self.final_gender_filter @@ -281,6 +286,7 @@ def stop_animation(self): draw_count=draw_count, settings_group="quick_draw_notification_settings", display_settings=self.quick_draw_settings, + ipc_selected_students=self.final_ipc_selected_students, is_animating=False, ) @@ -412,7 +418,9 @@ def display_final_result(self, quick_draw_settings): class_name=self.final_class_name, selected_students=self.final_selected_students, draw_count=draw_count, - group_index=0, + group_index=getattr( + self.roll_call_widget.range_combobox, "currentIndex", lambda: 0 + )(), settings_group="quick_draw_settings", display_settings=quick_draw_settings, ) @@ -437,6 +445,7 @@ def display_final_result(self, quick_draw_settings): draw_count=draw_count, settings_group="quick_draw_notification_settings", display_settings=quick_draw_settings, + ipc_selected_students=self.final_ipc_selected_students, ) except Exception as e: @@ -478,6 +487,7 @@ def _update_floating_notification(self): draw_count=draw_count, settings_group="quick_draw_notification_settings", display_settings=self.quick_draw_settings, + ipc_selected_students=self.final_ipc_selected_students, is_animating=True, ) @@ -504,7 +514,9 @@ def display_result_animated( display_format=display_settings["display_format"], display_style=0, show_student_image=display_settings["student_image"], - group_index=0, + group_index=getattr( + self.roll_call_widget.range_combobox, "currentIndex", lambda: 0 + )(), show_random=display_settings["show_random"], settings_group="quick_draw_settings", ) From dfa4e34efcd7bdc774070eb330d645ab807fe64b Mon Sep 17 00:00:00 2001 From: lrs2187 Date: Mon, 2 Feb 2026 23:20:15 +0800 Subject: [PATCH 4/5] =?UTF-8?q?fix:=20=E8=A7=A3=E5=86=B3=E6=8E=89=E9=83=A8?= =?UTF-8?q?=E5=88=86=20codefactor=20=E7=9A=84=E9=97=AE=E9=A2=98=E5=92=8C?= =?UTF-8?q?=20seer=20=E6=8F=90=E7=9A=84=E6=97=A0=E6=95=88=20bug?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/common/IPC_URL/csharp_ipc_handler.py | 113 +++++++++--------- .../notification/notification_service.py | 10 -- 2 files changed, 56 insertions(+), 67 deletions(-) diff --git a/app/common/IPC_URL/csharp_ipc_handler.py b/app/common/IPC_URL/csharp_ipc_handler.py index 734f1efd..6a4aced3 100644 --- a/app/common/IPC_URL/csharp_ipc_handler.py +++ b/app/common/IPC_URL/csharp_ipc_handler.py @@ -145,65 +145,9 @@ def send_notification( if not self.is_connected: return False - def _safe_int(value: Any) -> int: - try: - if value is None: - return 0 - return int(value) - except Exception: - return 0 - - def _coerce_student(value: Any) -> SelectedStudentNotificationInfo | None: - if isinstance(value, dict): - student_id = _safe_int(value.get("student_id", value.get("id", 0))) - student_name = str( - value.get("student_name", value.get("name", "")) or "" - ) - display_text = str( - value.get( - "display_text", value.get("display", value.get("text", "")) - ) - or student_name - ) - exists = bool(value.get("exists", value.get("exist", True))) - group_name = str( - value.get("group_name", value.get("group", "")) or "" - ) - lottery_name = str( - value.get( - "lottery_name", - value.get( - "lottery", - value.get("prize_name", value.get("prize", "")), - ), - ) - or "" - ) - return { - "student_id": student_id, - "student_name": student_name, - "display_text": display_text, - "exists": exists, - "group_name": group_name, - "lottery_name": lottery_name, - } - - if isinstance(value, (list, tuple)) and len(value) >= 3: - student_name = str(value[1] or "") - return { - "student_id": _safe_int(value[0]), - "student_name": student_name, - "display_text": student_name, - "exists": bool(value[2]), - "group_name": "", - "lottery_name": "", - } - - return None - coerced_students: list[SelectedStudentNotificationInfo] = [] for student in selected_students or []: - item = _coerce_student(student) + item = self._coerce_student(student) if item is None: continue coerced_students.append(item) @@ -534,6 +478,61 @@ def check_plugin_alive(self) -> bool: return randomService.IsAlive() == "Yes" except Exception: return False + + @staticmethod + def _safe_int(value: Any) -> int: + try: + if value is None: + return 0 + return int(value) + except Exception: + return 0 + + def _coerce_student(self, value: Any) -> SelectedStudentNotificationInfo | None: + if isinstance(value, dict): + student_id = self._safe_int(value.get("student_id", value.get("id", 0))) + student_name = str( + value.get("student_name", value.get("name", "")) or "" + ) + display_text = str( + value.get( + "display_text", value.get("display", value.get("text", "")) + ) + or student_name + ) + exists = bool(value.get("exists", value.get("exist", True))) + group_name = str(value.get("group_name", value.get("group", "")) or "") + lottery_name = str( + value.get( + "lottery_name", + value.get( + "lottery", + value.get("prize_name", value.get("prize", "")), + ), + ) + or "" + ) + return { + "student_id": student_id, + "student_name": student_name, + "display_text": display_text, + "exists": exists, + "group_name": group_name, + "lottery_name": lottery_name, + } + + if isinstance(value, (list, tuple)) and len(value) >= 3: + student_name = str(value[1] or "") + return { + "student_id": self._safe_int(value[0]), + "student_name": student_name, + "display_text": student_name, + "exists": bool(value[2]), + "group_name": "", + "lottery_name": "", + } + + return None else: class CSharpIPCHandler: diff --git a/app/common/notification/notification_service.py b/app/common/notification/notification_service.py index 44210a32..2710be6d 100644 --- a/app/common/notification/notification_service.py +++ b/app/common/notification/notification_service.py @@ -1084,16 +1084,6 @@ def _normalize_text(value): normalized_name = _normalize_text(item[1]) exist = bool(item[2]) - try: - sid = int(student_id or 0) - except Exception: - sid = 0 - group_name = student_group_by_id.get(sid, "") or "" - if not group_name and normalized_name: - group_name = ( - student_group_by_name.get(normalized_name, "") or "" - ) - selected_students_for_ipc.append( { "student_id": int(student_id or 0), From aea084c72aac73cb2f833c5d6d240ae3211ec45e Mon Sep 17 00:00:00 2001 From: lrs2187 Date: Mon, 2 Feb 2026 23:22:39 +0800 Subject: [PATCH 5/5] =?UTF-8?q?fix:=20=E7=A7=BB=E9=99=A4=E5=A4=9A=E4=BD=99?= =?UTF-8?q?=E7=9A=84=E4=BB=A3=E7=A0=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../notification/notification_service.py | 21 ------------------- 1 file changed, 21 deletions(-) diff --git a/app/common/notification/notification_service.py b/app/common/notification/notification_service.py index 2710be6d..045cd8ca 100644 --- a/app/common/notification/notification_service.py +++ b/app/common/notification/notification_service.py @@ -1053,27 +1053,6 @@ def _normalize_text(value): } ) else: - student_group_by_id = {} - student_group_by_name = {} - try: - from app.common.data.list import get_student_list - - for student in get_student_list(class_name) or []: - if not isinstance(student, dict): - continue - sid = student.get("id", 0) - sname = str(student.get("name", "") or "") - sgroup = str(student.get("group", "") or "") - try: - student_group_by_id[int(sid or 0)] = sgroup - except Exception: - pass - if sname: - student_group_by_name[sname] = sgroup - except Exception: - student_group_by_id = {} - student_group_by_name = {} - selected_students_for_ipc = [] for item in selected_students or []: if not isinstance(item, (list, tuple)) or len(item) < 3: