Releases: WRD1145/ClassShout
Release list
v1.14.0
新功能
-
账号分三级:教师 / 班主任 / 管理员:管理员在控制台的「班级授权」里勾上「设为该班的班主任」,这一个动作同时把账号角色升为班主任(少一步就少一种"勾了却什么也管不了"的困惑)。班主任能管自己被授予班主任的那几间班 —— 给别的老师授权、收回(只能收回普通任课老师,班主任的任免仍只在管理员手里)、上传那个班统一使用的名单;管不到别人的班,也管不到账号本身。一个班可以有好几位班主任。 · bd56469 · 无
-
名单按班隔离:一位老师教三个班,三个班的名单是三分不同的数据 —— 给二班导入的名单不会再被当成三班的用。服务器上按「账号 + 班级」各存一份,网页呼叫时用的也是那个班自己那份。 · bd56469 · 无
-
班主任可以给一个班上传"全班统一使用"的名单,并设为强制:不强制时它只是一份默认名单(任课老师没传自己的就用它);设为强制之后,这个班的任课老师连上传入口都没有,服务器也会拒绝他的上传,同时把服务器那份取回本机覆盖掉他原来那份 —— 一个班到底按哪份名单叫人,只有一个答案。他原来那份不会被删掉,取消强制之后立刻回来。 · bd56469 · 无
-
局域网与远程班级合并成一份「可发送班级」:教师端登录之后会带着自己的账号 Id 问一次服务器,拿回绑定的班级 + 在线状态 + 我在这个班的角色 + 这个班该用哪份名单,与局域网里发现到的那间合成同一张表(同一间教室两条路都通时只留一项,走局域网那条)。文字与语音两页勾了几间就发给几间**(语音会同时说给每一间);呼叫与随机叫人只让选一个班** —— 姓名、小组、抽到的人都来自某一份名单,同时叫几个班抽到的人只有一个是"对的那个班"的。 · bd56469 · 无
-
网页控制台的班主任视图:老师视图里多出一块「我的班级」,只列出自己当班主任的那几间班:在线状态、已授权哪些老师、有没有统一名单、是否强制;可以在那里给班授权 / 收回老师、上传班级统一名单并开关"强制"。控制台的用户表也多了「角色」一列(可切换),授权列表里带班主任徽标。 · bd56469 · 无
Bug 修复
- 网页呼叫:没同步过名单时,提示又变回"一个学生都没选"了:改成按班隔离时,校验顺序被排成"班级 → 学生 → 模板","服务器上还没有你的名单,先去 App 同步"这句只剩预览分支里还有 —— 而没同步过名单时页面上本来就列不出学生,老师会去一个空列表里找学生,永远学不到该先同步。现在这句重新排在"没选学生"之前。 · bd56469 · 无
- 被强制的班里,网页呼叫拿不到学生:
GET /api/teacher/roster原先只回调用者自己那份记录,于是班主任设了强制之后,任课老师在网页上看到的是"名单是空的"。现在来源是班主任那份时,回的就是班主任那份(与逐班挑选学生时用的是同一份)。 · bd56469 · 无
说明
- 教室端不受影响(版本号跟着走,行为无变化);这一版要升的是教师端(Windows 压缩包 / Android APK)与服务器。
- 服务器新增一个状态文件
relay-classroom-rosters.json(班主任上传的班级统一名单 + 强制开关)。升级时要在 systemd 单元里补一行Environment=CLASSSHOUT_CLASSROOM_ROSTER_STATE=/opt/classshout/relay-classroom-rosters.json,否则它会落在app/里(与本项目"程序与数据分开"的约定不符)。旧的状态文件格式完全兼容,无需迁移。 - 文档站新增账号与权限一页,并更新了名单、呼叫、中继与配置文件几页(中英双语)。
- 回归:局域网端到端 337 项、中继端到端 191 项(其中本次新增 58 项覆盖角色、跨班越权、名单隔离与强制名单),全部通过;渲染预览 50 张 PNG 校验通过;网页前端自检 48 个动作全部接线。
v1.13.0
新功能
-
名单可以直接导入表格文件(.xlsx / .xlsm / .xls),CSV / TXT 照旧:名单页上的「从文件导入」,手机上打开系统文件选择器。老师手里的名单九成是表格,而"先另存为 CSV"那一步恰恰最容易出错 —— 另存时选错编码、或者 Excel 把学号前面的 0 吃掉;直接读表格就没有这一步。表格只读第一个工作表,并把工作表名当作名单名(工作表叫「三年二班」时,导入后名单就叫「三年二班」)。数字单元格里的学号会写成整数,不会变成
20250101.0。 · 6cc1d77 · 无 -
名单新增第五列「性别」:
姓名,学号,简写,小组,性别,仍然只有姓名必填。男/女/男生/女生/M/F/1/0都认,认不出来的留空(不瞎猜)。与 CSV、表格、网页那三条入口共用同一套解析规则,不会同一个文件两个结果;名单页的每一行也会把学号/简写/小组/性别摊平显示出来,少填一列一眼就能看见。 · 6cc1d77 · 无 -
呼叫页新增「随机叫人」组件:模板里加上它,页面就从"手动勾学生"换成"按范围抽签" —— 小组、性别、人数(默认 1,最多 10)、冷却(默认 40 分钟,可选 20/40/60/90)。抽中的几位拼成一句("请 张三、李四 来回答这个问题"),而不是一人发一条。 · 6cc1d77 · 无
-
隐形的「时间因子」让刚叫过的人先缓一缓:每人一个 0.00~1.00 的因子,导入时一律 0.00;权重 =
1 − 因子(最低留 5% 的边,刚叫过的人也不是完全没机会);抽中一次重置到 0.95~1.00,之后随时间线性衰减回 0,衰减窗口就是上面那个"冷却"。它不是靠定时器一直改,而是存"因子值 + 写入时刻"、用一个减法推出来,所以应用关掉、电脑休眠、甚至系统时间被改过都不会失准。界面上不显示 —— 它对老师没有意义,显示出来只会让人以为哪里坏了。 · 6cc1d77 · 无
说明
- 教室端、服务器、ClassIsland 插件都不受影响:这一版改的是教师端的名单与呼叫页,加上中继服务器网页版呼叫列表多显示一列性别。
- 建议升级:教师端(Windows 压缩包 / Android APK)与服务器(网页版那一列)。
- 模块(
ClassShout.Design)与文档站同步更新:guide/roster、guide/call、reference/config-files(中英双语)。 - 回归:局域网端到端 331 项、中继端到端 134 项,全部通过;渲染预览 48 张 PNG 校验通过。
v1.12.2
v1.12.1
Bug 修复
- 安卓教师端一打开就闪退(
FATAL EXCEPTION,空引用):呼叫页的学生行StudentPickRow在构造时,把"这一条要不要勾上"(_isSelected = isSelected && IsSelectable)写在了Display赋值之前,而IsSelectable看的就是Display。只在"上次勾过学生"时才会炸 —— 勾选记录存在本机,LoadStudents会把它们带上,于是&&不再短路,读到一个还没赋值的Display;第一次用的人因为没有勾选记录、短路掉了,侥幸不崩。这解释了为什么它只在"用过一次呼叫"的设备上现形。现在把赋值顺序摆正,并加了两条断言(上次勾过的那位要构造得出来;该样式下没内容的条目不可选,哪怕请求里勾着)。 ·b51adfc· 无
说明
- 只有 APK 需要升:教室端 / 教师端桌面端 / 服务器都不受这条影响(桌面端同样有这个顺序问题,只是要"本机记着勾选"才会触发,一并修了,建议顺手升)。
- 受影响版本:1.12.0 及之前带呼叫页的所有版本。
v1.12.0
新功能
- 网页版也能「呼叫」:老师登录服务器账号后,浏览器里多了一块呼叫区 —— 选模板、勾学生、先「预览会喊什么」,再发出去。它和 App 的规则是同一条,因为两边用的是同一段拼装代码(组件顺序、空格、按小组归并、来源里的科目全都一致),不是照着重写一遍。前提是名单在服务器上,所以教师端「名单」页多了一个「同步名单到服务器(网页呼叫用)」按钮。 ·
299b856· 无 - 网页喊话也能指定展示参数:展示方式(窗口/弹窗)、文字大小、停留时间,加上朗读与打断两个开关,取值与 App 的文字页完全一致;不选就是按教室端默认。 ·
299b856· 无 - 日志详细程度可选:Trace / Debug / Info(默认)/ Warning / Error,两端的运行日志卡片上直接有下拉框,改完立刻生效并落盘;低于档位的日志既不显示也不落盘,档位认不出来退回 Info。服务器那份日志用环境变量
CLASSSHOUT_LOG_LEVEL调同一套档位。 ·7fb252e· 无
Bug 修复
- 同一台机器上开教室端与教师端,自动发现失效 / 搜得到连不上:连接地址改为一律取回包的来源地址(按定义就是从教师端能走通的地址),不再直接用教室端自报的 Host —— 装了 WSL / Docker / VPN 的机器上,教室端挑出来的那个地址常常是虚拟网卡或 169.254 的自动地址,别的设备根本连不上,表现就是"搜得到、连不上"。 ·
0c7863a· 无 - 广播探测不发给本机地址:教室端与教师端跑在同一台机器上时,广播可能被 VPN / WSL 那种"默认路由"吞掉。现在探测也会直接发给本机各地址与
127.0.0.1,两端同机就一定发现得了。 ·0c7863a· 无 - 教室端自报的地址可能是连不上的那个:本机地址改成打分制(有默认网关 + 物理网卡加分,虚拟网卡名与 169.254、172.16–31 减分),界面上与广播包里报出的地址更可能是别人真能连上的。 ·
0c7863a· 无 - 教师端「文字」页没有发送按钮:
Text.SendCommand从来没绑到界面上,文字喊话只能绕道呼叫页或语音页。补上按钮,并在按钮下面写清"为什么现在发不出去"(没连教室 / 还没写内容 / 上一条还在发)。 ·7fb252e· 无 - 查到新版本后「下载新版」点不动:属性变了但没人通知命令重新问一次
CanExecute,按钮就一直是灰的。补上通知。 ·7fb252e· 无 - 教室端「只看 ClassIsland 提醒」时,预览仍然弹 ClassShout 弹窗:那条规则在两个地方各写了一遍。现在只有一份(
ShoutNotificationChannels),收到喊话与点预览都问它;ClassIsland 通道下预览改投一条给 ClassIsland。 ·7fb252e· 无 - 教师端各种横幅关不掉也不会消失:顶部错误提示、录音错误、「地址已保存」这类一次性提示、服务器地址与分享链接的错误 —— 现在都有右边的叉,并会自己收起(错误 15 秒、一次性提示 10 秒)。 ·
3a96771· 无 - 「这条发给谁」只有一间教室时整块不显示:那一块现在有一间就显示,并写清是"经服务器"还是"局域网直连"。 ·
82f8dbd· 无
说明
- 服务器新增一个状态文件
relay-rosters.json(老师同步上来的名单与呼叫模板,含学生姓名与学号)。部署时请把CLASSSHOUT_ROSTER_STATE指到app/之外,否则升级覆盖app/时会把它一起冲掉。 - 网页版只读名单:编辑仍然只在 App 里,网页是"用"而不是"管"。
升级提示:这一版两端都要升(网页呼叫与来源里的科目、展示参数都依赖两端一致),
服务器也建议一起升(新增了名单与呼叫两个接口)。
压缩包解压覆盖app/即可,状态文件在上一级,不会被覆盖。
ClassIsland 联动插件另有更新:1.0.3.0(目标框架改为与宿主一致的net8.0-windows,
装进 ClassIsland 2.1.0.1 才加载得起来),在另一个仓库发布。
v1.11.2
Bug 修复
- 服务器的日志文件里其实没有事件:落盘的过滤器按「类别名是不是以
ClassShout开头」来分「是不是自己的日志」,而服务器自己的主日志用的类别叫Relay—— 于是登录、班级授权、喊话、定时发送这些 Information 全被挡在文件之外,logs/里只剩下启动那几行(外加那条 Warning 级的控制台横幅)。恰恰是排障要看的那几类记录一条都没有,而文件建得出来、启动又有内容,所以只看"日志建好了没"根本发现不了。判据改成「只把框架类别(Microsoft.*、System.*,含每条长轮询请求)压到 Warning,其余照收」。 ·723a140· 无
说明
- 这一版只动了服务器的落盘日志,喊话协议与两端行为都没变,可以单独升。
- 回归里补了一段「服务端文件日志」断言(9 条):日志确实落在
CLASSSHOUT_LOG_DIR指的目录、按天命名、启动与运行事件都在文件里、没有口令明文、超过 7 天的被清掉而保留期内的不动。其中 3 条在把判据改回旧写法时会失败 —— 也就是说这个 bug 以后不会再悄悄溜过去。
升级提示:教室端与教师端不必升。部署了服务器的建议升这一版,
否则logs/classshout-YYYY-MM-DD.log里翻不到"谁在哪节课喊了什么"。
解压覆盖app/即可(状态文件在上一级,不会被覆盖),
确认单元里有CLASSSHOUT_LOG_DIR=/opt/classshout/logs。
v1.11.1
Bug 修复
- 日志文件里会写下明文口令:把日志落到软件目录下之后(1.11.0)才发现,有两处日志本身带着凭据 —— 服务器首次启动的横幅里有「口令:xxx」(管理员口令),教室端注册成功后界面上显示「口令:xxx —— 请抄给老师」。界面显示口令是设计如此,但落到磁盘是另一回事:日志会被打包发给别人看排障、会被备份拷走、会随压缩包传播。现在写文件前统一把「口令/密钥/Secret/Token/API Key + 冒号 + 值」抹成「(已隐去)」,不带值的消息(如「管理员口令已更新。」)照旧保留 —— 否则日志没法读。 ·
pending· 无 - 日志文件的权限没收紧:Linux 上按默认 umask 建出来是 0644,同机其他账号能读。现在日志目录是 0700、日志文件是 0600(Windows 上用户目录本来就只有本人可读)。 ·
pending· 无
说明
- 服务器的日志现在同时写进软件目录下的
logs/(原先只有 stdout,由 systemd 收进
journald —— 那套东西对"翻昨天的日志"并不友好)。刻意只收有用的那些:
我们自己代码(ClassShout.*)的 Information 及以上照收,
别的类别(Microsoft.*,含每条长轮询请求)只收 Warning 及以上,
否则一晚上就能把磁盘写满。
升级提示:两端的喊话协议没有变化,可以单独升。
服务器(如果部署了)建议升这一版:它把日志写进logs/,并保证那里不出现口令。
解压覆盖app/即可,并确认单元里有CLASSSHOUT_LOG_DIR=/opt/classshout/logs。
v1.11.0
新功能
- 日志挪到软件目录下:运行日志现在写在软件自己那个目录的
logs\里(不再是%LOCALAPPDATA%)—— "日志在哪"与"软件在哪"是同一件事,找日志的人多半正站在那台机器前面。装在只读位置时逐级退:CLASSSHOUT_LOG_DIR→ 程序目录logs\→ 用户数据目录logs\,退到哪一级会显示在设置页的「关于」里。 ·pending· 无 - 压缩包里的布局收拾干净:顶层只留一个启动脚本、一份说明、
logs\和app\,257 个程序文件全部待在app\里 —— 打开文件夹一眼就知道该双击哪个。Linux 版对应run.sh(它会把CLASSSHOUT_LOG_DIR指到同级logs/)。 ·pending· 无
说明
- 为什么 DLL 不能单独再分一个文件夹:.NET 的运行时宿主文件(
hostpolicy.dll/
hostfxr.dll/coreclr.dll/System.Private.CoreLib.dll…)必须与 exe 同级,
而它们占了文件数的一大半。试过把其余程序集挪进lib\并改写deps.json的路径,
应用直接崩在hostpolicy.dll not found(自检脚本实测)。
所以能收拾的是界面:程序本体进app\,顶层保持干净。 - 启动脚本会闪一下黑窗口,那是
cmd本身,不是程序。
升级提示:这一版改的是目录布局与日志位置,与喊话协议无关。
升级仍然是"解压覆盖同一个目录"。日志从这一版起写在软件目录下,
旧版留在%LOCALAPPDATA%\ClassShout\logs\里的那几天可以删掉。
服务器(如果部署了)解压时加--strip-components=1到/opt/classshout,
并在 systemd 单元里把ExecStart指向app/ClassShout.RelayServer、
加上CLASSSHOUT_LOG_DIR=/opt/classshout/logs。
v1.10.1
Bug 修复
- 「跟随系统代理」实际上没有走代理:.NET 的
HttpClient.DefaultProxy在装了代理的机器上未必走代理 —— 只要存在任何一个代理环境变量,它就选那个"只看环境变量"的实现,而那个实现按 URL 的 scheme 取变量:https 请求只看HTTPS_PROXY。代理软件常常只设了HTTP_PROXY,于是 https 请求一个都不走代理;Windows 的"系统代理"设置(注册表里那份)它同样不读。表现就是"浏览器能开 GitHub、ClassShout 连不上",而且没有任何提示。现在「跟随系统」会直接读 Windows 的系统代理设置(ProxyEnable/ProxyServer/ProxyOverride),按可靠程度依次退到环境变量、再退到 .NET 自带解析;界面上显示实际解析出来的地址,是"系统代理 → http://127.0.0.1:7890"还是"系统没有配置代理(直连)"一眼可见。 ·pending· 无 - 自定义代理地址写错时会当成合法地址用:填了中文或别的乱码时,程序会一本正经地拿它当代理,然后所有请求都失败在一个没人看得懂的地方。现在会说"地址看不懂"。 ·
pending· 无
升级提示:只有客户端(教室端 / 教师端)受影响,喊话协议没有任何变化。
如果你之前"检查更新"连不上 GitHub 而浏览器能开,这一版就是修那个的:
升上去之后打开「版本与更新」,看代理那一行写的是不是"系统代理 → …"。
如果它写"系统没有配置代理",而你确实开着代理,就把代理改成「自己填代理地址」
并填上http://127.0.0.1:7890(端口按你的代理软件来)。
v1.10.0
新功能
- 一键检测所有镜像源(并发):更新卡片里把镜像源做成一份列表,点「一键检测全部」会同时测每一条,列出通不通、耗时、查到的最新版本,并自动切到最快的那条。原先是单线程一条条测 —— 六条源里只要有一条不通,用户就要干等它超时。 ·
ad056bd· 无 - 可以加多个镜像源:内置 6 条(直连 GitHub、Gitee 码云 li-hansen136/ClassShout、ghproxy.net、gh-proxy.com、ghfast.top、kkgithub),自己也能加(名字 / GitHub 还是 Gitee / API 地址 / 仓库 / 下载模板)。自定义的能删,内置的删不掉 —— 它们是"一条都不剩"时的兜底。每条镜像有自己的仓库与接口地址,因为码云那份不在同一个仓库名下。 ·
ad056bd· 无 - 代理可显式设置:跟随系统 / 不使用 / 自己填地址,并且界面下方显示实际解析出来的代理(「系统代理 → http://127.0.0.1:7890」或「系统没有配置代理(直连)」)。 ·
ad056bd· 无 - 运行日志落盘,按天分文件、保留 7 天:两端界面上的日志一关就没,而排障最常见的问法是"昨天下午那节课怎么没声音"。现在每条同时写进
logs/classshout-YYYY-MM-DD.log,启动时清理 7 天前的。 ·ad056bd· 无
Bug 修复
- 检查更新没走系统代理:代理软件只设了环境变量、或进程从桌面启动没继承到时,.NET 默认那套读不到代理,表现就是"浏览器能开 GitHub、ClassShout 连不上",而且没有任何提示。现在代理是显式的、能看见、能填;直连失败时那句错误里也会提醒"可以设个代理"。 ·
ad056bd· 无
回退
- 不再打成单文件:单文件每次启动都要把 Skia 这类原生库解压到临时目录,首次启动明显变慢、体积还更大。现在每个应用一个目录,发布资产改成压缩包(
ClassShout.Classroom-win-x64.zip、ClassShout.Teacher-win-x64.zip、ClassShout.RelayServer-win-x64.zip、ClassShout.RelayServer-linux-x64.tar.gz、ClassShout.Classroom-linux-x64.tar.gz)。压缩包里套一层以应用命名的目录,解压出来是一整个目录而不是十几个 dll 散在"下载"文件夹里。 ·ad056bd· 无
升级提示:附件形式变了,升级方式也跟着变 —— 不再是"替换一个 exe",而是
"把压缩包解压覆盖同一个目录"。配置与日志都在用户目录里(Windows 是
%LOCALAPPDATA%\ClassShout\),从来不在程序旁边,所以升级不影响教室名、UUID、
口令与账号。教室端与教师端没有协议变化,可以单独升。
服务器(如果部署了)请换用ClassShout.RelayServer-linux-x64.tar.gz,
解压后保留relay-*.json、relay-schedule-audio/与logs/。