Files
Scoreboard/docs/升级说明.md
T
AskaEth 9663d5bfb0 fix(entry): 修「团体名次 / 批次号 / 每批人数」填数字导致整页白屏(P0);版本 dev_0.5.4
## 现场现象
在「按单位手动录名次」的项目(例如篮球)的录成绩页,往底部「团体名次」输入框里填一个数字,
**整个录入页立刻变空白**,控制台 `TypeError: e.trim is not a function`(栈里是 computed 的 getter)。

## 根因(老 bug,不是联队引入)
- 模板是 `v-model="row.input"` + `type="number"`。
- **Vue 3 的 `vModelText` 对 `type="number"` 会自动做数值转换**
  (`castToNumber = number || (vnode.props && vnode.props.type === 'number')`)→ 填了数字之后值是
  `number`;只有**清空**时 `looseToNumber('')` 才留空串。当初的注释只写了后一半,漏了前一半。
- `teamRanks.ts` 的 `parseTeamRankInput(raw: string)` 里直接 `raw.trim()` → TypeError;
  而它的三个调用点(保存载荷 / 重复名次提示 / 描红)**全在渲染期的 computed 里** → 整页白屏。

证据:0.5.2(联队之前)的 `EntryPage.vue` 里就已是这套写法,`teamRanks.ts` 本轮一个字没改过。

## 修复
- `teamRanks.ts`:`parseTeamRankInput` 参数与 `TeamRankRow.input` 类型如实标注 `string | number`,
  解析前 `String(raw).trim()`;`teamRanksDirty` 归一后比较(否则 `number 3` 与 `string '3'` 会被判成
  「已修改」,保存按钮空亮着却什么都没改)。
- `EntryPage.vue`:**同类第二处** —— 「批量设置批次」的 `heatInput` / `heatSizeInput` 同样是
  `type="number"` 且下游 `.trim()`,**同样会整页白屏**,一并修掉。
- 写法与仓库既有的正确实现保持一致(`CategoriesSection.vue` / `AthletesSection.vue` 的 `toAge()`)。

## 同类隐患体检
把全仓库 **21 个 `type="number"` 的 v-model 绑定点**逐个追了下游用法(解析 / 比较 / `.trim()` / 传接口):
**真正会炸的只有上面这 3 处**,其余 18 处本来就用 `Number()` 归一,安全。

## 验证
- **先红后绿**:修复前 3 例红(`raw.trim is not a function` 原地复现:number 解析抛错、computed 调用链抛错、
  脏判断误报 `true !== false`),修复后 13/13 通过。
- 前端用例 809 → **813**,0 fail;`vue-tsc` / `pnpm build` 退出码 0。
- 全量自检两轮全绿(服务端 14 包 / Console 68 例);退出码直接读,未用管道吞。

## 版本
`dev_0.5.3` → **`dev_0.5.4`**(0.5.3 已产出并记过哈希,不重出同名包);安装器素材同步重生成
(版本号烙在位图里,实测仍只有 `brand.bmp` 的 1x/2x 两张变化)。
2026-09-14 09:57:02 +08:00

541 lines
55 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 升级说明
> **按版本倒序,最新在最上面。** 每次升级前先看「要升到的那一版」这一节,照着做完再开赛。
> 数据、配置、规则包都在用户数据目录(`%LOCALAPPDATA%\ScoreboardConsole\`),**覆盖安装不会丢**,见《部署指南》3.4 / 3.5。
> 常规升级流程(停服务 → 覆盖安装 → 启动 → 核对)见《部署指南》3.1 / 3.4。
---
## dev_0.5.4(当前版本)
### 一句话
**没有数据迁移,升级后不用重配任何东西**:修掉一个会让**成绩录入页整页白屏**的问题 —— 在「按单位手动录名次」的项目(例如篮球)底部**「团体名次」输入框里填数字**,或者在顶部工具条里填**批次号 / 每批人数**,页面会整个变成空白。**已经录好的成绩、名次、榜单数据都不受影响**,这三处只是以前一填数字就崩。
### ① 修了什么(三处输入框,同一个根因)
- **团体名次**(「按单位手工录名次」的项目,录成绩页底部那个区块):往某个单位的名次框里填数字 → **整页白屏**;
- **批次号 / 每批人数**(录成绩页顶部「批量设置批次」工具条):同样填数字 → **整页白屏**;
- 根因在浏览器与框架这一层:这几个框是**数字输入框**,填进去的值会被**自动转成数字**,而处理它的代码是按「文本」写的(对值调用文本方法)→ 当场抛错。又因为它发生在**页面渲染过程**里,所以表现不是「弹个错误」,而是**整页变空白**(这也是为什么它看起来比一般错误严重)。
- 三处都改成**先归一成文本再解析**;**填同样的内容,结果与以前预期的完全一致**(团体名次填 `3` 就是第 3 名,填 `0` 或留空仍是「清空该单位」)。
- 顺带把仓库里**其余同类输入框逐个体检了一遍**(共 21 处),确认只有上面这三处会出问题,其余的写法本来就是安全的。
### ② 升级后 5 分钟核对
1. 打开一个「按单位手工录名次」的项目(例如篮球)的录成绩页,在底部**「团体名次」**里给某个单位填一个数字:**页面应当正常显示**;名次重复或超出参赛单位数时,输入框会描红并给出提示(**只提示不拦截,仍然允许保存**);
2. 在录成绩页顶部**「批量设置批次」**里填一个数字,确认页面不白屏、按钮可点;
3. 打开一个**联队**的报名(单位编码形如 `T1+T2`),确认单位那格显示两个单位的名字与份额 —— 这是上一版(0.5.3)新增的能力;
4. 其余照旧:**不需要重新导入规则包,也不需要重配任何东西**。
---
## dev_0.5.3
### 一句话
**有一条数据迁移(`0024`),但升级后不用重配任何东西、老数据一个数字都不变**:一条报名现在可以挂**多个单位、按份额分成**——两个单位因参赛人数不足合并成一个联队参赛时,分数按份额拆给各单位(默认均分,允许出现 7.5 这种小数),奖牌**每个成员单位各记一枚整枚**。升级前就有的赛事,榜单、名次、积分、奖牌、导出件与升级前一模一样——**联队能力只有在真的把某条报名配成联队之后才会体现**。不用重新导入规则包。
### ① 数据迁移:一条(`0024`)
- **它做什么**:新建一张 `entry_team_shares` 表,记「这条报名归哪些单位、各占多少」(积分份额 + 奖牌是否记给本单位),并把**已有的每一条报名回填成「主单位独占 100%」**。`entries.team_id` 保留为**主单位**(联队时就是加号左边那个),既有的查询、唯一键、榜单、导入都还认它。
- **只加一张表 + 回填**:不改任何既有字段、不删任何数据;回填用的是「已经有份额就不动」的写法,重复执行(或迁移被重放)**不会覆盖已经配好的联队份额**。
- **怎么看它跑过**:启动一次 Console,在运行日志或 `logs\operations\` 当天文件里能看到 `已应用迁移 … name=0024_entry_team_shares.sql`。
### ② 老数据零变化(有对拍证据)
- **无联队的老数据在引擎层、接口层、导出层三层都做过签名 / 逐行对拍,差异 0 处**,签名取自**联队实现之前**的代码,实现之后必须一字不差:
- 引擎层:`server/internal/domain/legacy_forms_golden_test.go`(`TestLegacyFormsScoringUnchanged`,签名 `a2aa1c97…`);
- 接口层:`server/internal/httpapi/legacy_forms_golden_test.go`(`TestLegacyFormsAPISnapshotUnchanged`,签名 `aa6cea37…`);
- 导出层:`server/internal/export/joint_team_export_test.go` 的 `TestSingleUnitExportsHaveNoJointTeamText`(只有一条独占份额时,各份导出件一个字都不能多)。
- 所以:**升级后单位总分榜、单位奖牌榜、个人积分榜的每一个数字、每一条名次、每一枚奖牌、每一份导出件都与升级前一模一样**。本事只在真的把某条报名配成联队之后才生效。
### ③ 不用重新导入规则包
- 本版**没有改规则包格式、没有改计分口径、没有改任何计分通道配置**:随包规则包与现场那份都不用动,也不需要重算。
- (对照:dev_0.5.1 那次是建议重新导入的,本版不是。)
### ④ 新增能力:联队 + 份额分成(口径已定稿)
| 口径 | 定稿写法 |
| --- | --- |
| 份额 | **可配、默认均分**(权重都留空 = 各 50%;填 2 与 1 = 67% 与 33%) |
| 积分 | **平均拆,接受 .5**:团体第 1 名 15 分 → 两个单位各 **7.5 分**(榜单上就写 7.5) |
| 奖牌 | **每个成员单位各记一枚整枚**:联队的金牌,两个单位**各记 1 枚**(不是各 0.5 枚) |
| 显示 | 联队的名字**都写出来**:`第一分公司+第二分公司联队` |
| 导入 | 报名表的**单位编码**列写 `A+B`(加号左边那个是**主单位**;全角 `+` 与两侧空格等价) |
怎么用:
- **配联队的两个入口**:
1. **导入报名表**时把单位编码写成 `A+B`(默认均分;最多 5 个单位;`A+`、`+B`、`A++B`、`A+A` 这些写法会被**逐行拦下**并说清是第几行、错在哪,**其余行照常导入**);报名模板(分工作表 xlsx)的「单位编码」表头挂了一条**单元格批注**、该列还有**输入提示**,中英各一份,内容就是这套写法——**表头文字、列序、12 列、工作表命名一个字都没动**,老表格照常导入;
2. 导入后到**「成绩录入」页点那一行的「单位」格**,打开「**成员单位与份额**」弹窗改(加成员单位、填权重、去掉成员)。⚠️ **非均分(例如 2:1)不能在导入表里写**,只能在弹窗里改。
- **谁能改**:份额编辑与录成绩同档,**录入员及以上**;访客只读时输入框置灰并写明原因。
- **改完当场生效**:保存立即重算该小项该组别并推送大屏。
- **录入与复核页看得到**:联队的单位格显示成 `联队 第一分公司 50% 第二分公司 50%`(非均分时带 `(权重 2)`)。**普通报名(只有一个单位)的格子文案、元素一个字没动**,只是多了一个可点的入口和一行悬停提示。
- **大屏**:分项成绩表与实时赛况的「单位」列写 `第一分公司+第二分公司联队`,并**把两个单位的 logo 都放上**(单位列宽会为该行的 logo 数留位);底栏「最新完成项目」同样写联队全名;单位奖牌榜与总积分榜本来就是逐单位一行,服务端已按份额拆好(例:A、B 各 1 枚金、各 7.5 分)。
### ⑤ 导出件里现在写成什么样
| 位置 | 现在写成 |
| --- | --- |
| 分项成绩表 / 全部成绩(单页)「单位」列 | `第一分公司+第二分公司联队` |
| 同上「备注」列 | `联队分拆:第一分公司 5 分(50%)、第二分公司 5 分(50%)` |
| 报名名单「单位编码 / 单位名 / 备注」 | `T1+T2` / `第一分公司+第二分公司联队` / `联队分拆:第一分公司 50%、第二分公司 50%` |
| 单位积分明细 / 总明细「备注」列 | `联队分拆:… 各多少分(各多少 %)` |
| 个人积分总明细「来源」列 | `成绩(联队分拆:…)` |
| 单位奖牌明细「奖牌」列 | `金牌(联队 第一分公司+第二分公司,各单位各记 1 枚)` |
| 总表 / 单位奖牌明细的副标题 | 追加 `· 注:本赛事含联队,奖牌按「每个成员单位各记 1 枚」统计,各单位奖牌数之和会大于实际颁发数` |
- **按单位筛选导出**:成员单位的名单里也能看到**主单位是另一个单位的联队报名**(否则 B 导出自己的名单会发现「没派人上场」);
- 导出件的**值只在真的有联队时才变**:没有联队的赛事,导出件与升级前逐字一致。
### ⑥ 两条要主动告知的口径后果
1. **各单位的奖牌数之和会大于实际颁发的奖牌数**——因为联队的每一枚奖牌**每个成员单位各记 1 枚**。例:A、B 联队拿 1 枚金牌,奖牌榜上 A 记 1 金、B 记 1 金,而场上只颁发了 1 枚。**这是定稿口径,不是数据错了**;含联队的「总表 / 单位奖牌明细」副标题会写这句话,奖牌明细里联队那一格也写着「各单位各记 1 枚」。**拿奖牌数去和实际颁发的奖牌核对时请记住这一点。**
2. **个人积分总明细里,联队里的同一个人会出现两行**——引擎按份额给两个成员单位各留了一行流水,导出侧只在「来源」列写清这两行为什么出现(`成绩(联队分拆:…)`)。**看两行加起来才是这个人的总数**;这不是重复计分(他的总分没有被算两遍),是按份额拆开的结果。
### ⑦ 顺带:单位奖牌明细的「奖牌」列加宽并允许换行
- 导出件「单位奖牌明细」的「奖牌」列原来是**宽 8、居中**,写不下 `金牌(联队 第一分公司+第二分公司,各单位各记 1 枚)` 那句(会被右边的「运动员/队」裁掉),现在**加宽到 26 并允许换行**。
- **列里的值没变**:没有联队时这一格仍然只是「金牌」「银牌」「铜牌」三个字。
### ⑧ 升级后 5 分钟核对
1. 启动一次 Console,看运行日志 / `logs\operations\` 当天文件:应能看到 `0024` 这条迁移记录,没有别的报错;
2. 刷新管理端「积分榜」与大屏:**单位总分榜、单位奖牌榜、个人积分榜的每一个数字与升级前一致**(本版不改任何计分口径;只有你之后自己配了联队的地方才会变);
3. 打开「成绩录入」页:普通报名的**「单位」那一格与升级前长得一样**(只是鼠标移上去变成手型、有一行悬停提示,点一下会打开「成员单位与份额」弹窗,什么都不改直接关掉等于没动过);
4. 打开「基础数据 → 报名导入」,下载一份「**分工作表 · 中文表头**」,把鼠标停在表头「**单位编码**」那一格上:应弹出「单位编码怎么写」的批注(内容含 `A+B`);点中该列任一格应弹出同样的输入提示;
5. 真要用联队的:按 ④ 把那条报名配好(导入写 `A+B`,或点单位格改份额),确认榜单上两个单位**各拿到一半分、各记一枚牌**、大屏上两个单位的 logo 都在;
6. 用《上线检查清单》过一遍。
### ⑨ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 联队怎么录、份额怎么改、分成后长什么样 | 《使用手册》4.11 |
| 导入表里联队怎么写、写错了报什么错 | 《报名名单导入规范》第三节的「单位编码」、第六节 |
| 大屏与导出件上联队写成什么 | 《使用手册》17.1、8.3、11.1 |
| 迁移与份额表结构 | `server/migrations/event/0024_entry_team_shares.sql` |
---
## dev_0.5.2
### 一句话
**没有数据迁移,升级后不用重配任何东西**:报名模板新增「分工作表」两种(一个小项组别再挤在一张总表里,填表不容易串行);修好了「同一个人报多个项目被误判成号码布重复、整块拦下」;自动备份加固——备份写到一半时关程序、或备份失败,都不会在备份目录里留下半截文件。
### ① 新增:报名模板支持「一个小项组别一张工作表」
- 「基础数据 → 报名导入」的「下载模板」现在有四个按钮:**中文表头**、**英文表头**(这两种还是**一份总表** CSV,全部报名挤在一张表里,与升级前完全一样),以及新的 **分工作表 · 中文表头**、**分工作表 · 英文表头**(XLSX)。
- 后两种由系统按当前赛事**已配好的小项 × 组别**生成:**一个小项组别一张工作表**,工作表名就是「小项名称@组别名称」(例:`100 米跑@男子组 30岁以下`)。填表的人不用在一张大表里反复抄小项名与组别名,也就抄不串了;收上来直接导入,不用再拆。
- **导入时工作表名和表内的小项 / 组别列都认**:两者说的是同一个项目就照常导入;**说法不一致会把那张表整张拦下、并指出是哪一张**,不会闷头按其中一个算。
- 小项名称、组别名称里**不能再用 `@`(含全角 @)**:它是工作表名的分隔符,写进名字会让「小项@组别」拆不开。新建 / 改名时会当场拦下并说明原因;**规则包里名字带 `@` 的**这类写法仍能导出、也仍留在库里,只是**不能再导入**;库里已经存在的带 `@` 名字照旧能用,只是**不会出现在分工作表模板里**(这种名字拼不出合法的工作表名)。
- 原来那种单表 CSV 导入(中文表头 / 英文表头两套)**一个字没改**,手上已有的表格照常导入。
### ② 修复:同一个人报多个项目,不再被误判成「号码布重复」
- 以前判重只看号码布,而**证件号是选填的**:同一个人用一个号码布报两个项目,会被整块拦下、提示「号码布 XXX 在报名表内重复出现,这些行未导入」,只能人工删行再传一次。
- 现在按**证件号**来分辨:号码布相同、**证件号也相同**(能证明是同一个人)→ 放行;号码布相同、**证件号都填了且不一样**(真抢号)→ 仍然报错;**一方证件号没填** → 放行,并在导入结果里给一条提示,让人自己扫一眼确认。
- 团体报名行里的号码布也一并查重(同一条规则)。
### ③ 加固:自动备份不会再在备份目录里留下半截文件
- 半截备份(程序被强杀、磁盘写满、备份写一半时退出——**文件名看着正常、内容却不完整**)以前会被列进「系统 → 备份」的列表里,**手一抖当成正常备份去「恢复」就会出事**。
- 现在备份一律**先写临时名、写完整了才改成正式名**;关停程序时也会**等一下正在写的这一轮备份收尾**(最多 10 秒,等不到只记一条警告,不会卡住关不掉)。
- **升级后建议顺手看一眼**:打开「系统 → 备份」,如果列表里有个**明显偏小或 0 字节**的备份,那是老版本留下的半截文件。界面没有删除按钮,请到数据目录 `%LOCALAPPDATA%\ScoreboardConsole\data\backups\` 手工把它删掉。**留着也不会被自动使用**——点「恢复」时服务端会先校验这份备份能不能用,不合格会直接拒。
### ④ 升级后 5 分钟核对
1. 覆盖安装后启动 Console,看运行日志:**这一版没有数据迁移**,只应有正常的服务启动信息,没有迁移记录、也没有报错;
2. 打开「基础数据 → 报名导入」,「下载模板」处确认有四个按钮;点「分工作表 · 中文表头」下载一份 xlsx,打开应看到**多个工作表**、表名形如「小项@组别」;
3. 拿手上的一份报名表试导入一次,结果应与升级前一致(该进的进、该报的报);
4. 打开「系统 → 备份」,确认列表正常,并点一次「立即备份」;
5. 用《上线检查清单》过一遍。
---
## dev_0.5.1
### 一句话
**两条数据迁移、三处计分口径变化、安装器换新,升级后建议重新导入一次新版规则包**:迁移 `0022` 把「小项已被删除、积分流水却还挂在榜上」的历史脏数据一次性作废(**只影响分数,不影响名次与奖牌,人工调整分不受影响**);迁移 `0023` 给计分通道加一列「聚合口径」(默认「平均」,不切就与升级前一样);**单位奖牌榜改为按奖牌数独立排名,可能与积分榜顺序不同**;安装器换新——界面全面重做,并且**安装时改了三处行为**(一启动就申请管理员、自动关闭正在运行的旧版本、装到哪与「上次安装目录」的关系,见 ③)。
### ① 数据迁移:两条(0022 / 0023)
**`0022` —— 历史孤儿积分流水一次性作废**(现场可能少几分,那是升级前就该清掉的分)
- **它清理什么**:升级前删掉一个「只按单位录名次、没有报名行」的小项时,它名下**已经产生**的积分流水会留在库里、并且没有被作废——分数继续算在单位总分里,但这个小项已经不存在,此后任何一次重算都再也碰不到这些流水(只能改库才能清)。
- **只作废「成绩流水」与「破纪录加分」**:这两类流水一定挂着小项,空小项 = 小项已被删除。**人工调整分不受影响**——人工调整本来就可以不挂小项,是合法的,不会被误清。
- **影响面**:**只影响分数**。这些流水本来就没有名次、也没有奖牌,所以**名次与奖牌一件不变**;作废后这些分在**单位总分与单位积分明细里一起消失**(不会出现「榜上无分、明细有分」)。它是**作废不是删除**:流水行与作废时间都留着,并注明是升级时清理的历史数据,事后查得到。
- **怎么确认**:启动一次 Console,在运行日志或 `logs\operations\` 当天文件里能看到迁移记录(`已应用迁移 … name=0022_void_historical_orphan_ledger.sql`)。**现场确认删过「带分的小项」的机器上,相应单位的总分会少一点**——那是清掉了历史脏数据,不是这次升级算错了。
- **想核对到条**:升级前先导出一次单位积分明细存底(「积分榜」页的「导出该单位明细」或「导出总明细」),升级后再导一次对比,就能看出少了哪几条。
**`0023` —— 计分通道新增一列「聚合口径」**(只加列、不动既有数据)
- 老通道一律取默认**「平均」**(团体成绩 = 该单位成员成绩的平均值),**升级前后榜单一分不差**;想改成「总和」的,到「基础数据 → 计分通道」手工切(见《使用手册》10.4)。
### ② 三处口径变化(现场看到的数字 / 顺序可能不同)
**1)「末位归零」:末位不再丢分**
- 本版随包规则包里两个模板的「末位归零」都设成**关**:**参赛人数少于表里档位数时,最后一名按表拿分**(例:3 人参赛、模板有 6 档,第 3 名按表拿 6 分),不再被抹成 0。重新导入规则包会把库里这个开关一起写成「关」——**此前在模板页手工勾过它、或导入过把它勾上的规则包**的机器,这一步之后末位分数会变(这是定稿口径:规则里没配的名次分数就是 0 分,分只按表发)。
- 另外,**开关打开时也只抹「真正落在最末那一档」的那一条**:并列档位从更靠前的名次起步、区间跨过末位的并列组**不再被整组抹 0**,按他们并列到的名次照表拿分(7 人里三人并列第 5、前六档表 → 每人按第 5 名拿分;升级前是 0 分)。
- **名次与奖牌不受影响**:这一段改的只是「这一组拿多少分」。
**2)单位奖牌榜改为按奖牌数独立排名**
- 顺序与名次:**金牌 → 银牌 → 铜牌 → 单位编码**,**不再跟着单位总分榜**。所以「金牌多、总分低」的单位在奖牌榜上排前面、在单位总分榜上排后面——**这是口径不同,不是数据错了**(升级前奖牌榜沿用总分榜顺序,会出现「金牌多的排在后面」)。
- 三处同一个口径:管理端「积分榜 → 单位奖牌榜」、大屏的单位奖牌榜页、大屏底栏滚动的奖牌 Top3。
- 「导出奖牌明细」(`单位奖牌明细.xlsx`)逐枚列出奖牌的总表不受影响;各单位**分表的先后仍按单位总分排**(得分高的在前),与奖牌榜的顺序不同,这不是错。
**3)同分并列段的排列按规则包的排序口径**
- 总积分榜(及个人积分榜)里**总分相同**的单位那一段内,先后按规则包里的排序口径排——本赛会包的默认是 **总分 → 金 → 银 → 铜 → 单位编码**。
- 重新导入规则包会把这条口径按规则包的值写回库里(本赛会包是 **总分 → 金 → 银 → 铜 → 单位编码**):**此前导入过排序口径写法不同的规则包**的机器,这一段里单位的先后可能变化——**变的是顺序,分数与奖牌都不变**,看到顺序变了不要当成故障。
- **单位奖牌榜不受这条影响**:它固定按金 → 银 → 铜 → 单位编码(见上面第 2 条)。
### ③ 安装器换新(界面重做 + 三处安装行为变化)
- **界面全面重做**:安装程序(`Scoreboard Console-<版本>-x64.exe`)的欢迎 / 目录 / 许可 / 进度 / 完成各页与按钮换成新素材,并**支持 4K 高 DPI**(系统缩放到 200% 时界面按缩放后的尺寸排布,字与按钮不会糊成一团)。
- **① 安装程序现在一启动就申请管理员**:双击安装包会**先弹一次 UAC**(Windows 的「是否允许此应用对你的设备进行更改?」),点「是」之后整个安装过程都在提权状态下进行 —— 装到 `C:\Program Files\…`、自动放行防火墙入站 19540(规则名 `Scoreboard Console (TCP 19540)`,卸载时会自动删掉)都靠它。
- **管理员机器**:会弹这一次 UAC;装完不用再手工放行防火墙。
- **受限账户(不是管理员)的机器**:**不会弹 UAC**(弹了也没用),安装程序会**自动降级为「仅为我安装」**,装到你的用户目录(`%LOCALAPPDATA%\Programs\…`),**不装**到 Program Files,也**加不了**防火墙规则 —— 这种机器要照《部署指南》7.5 在管理员账户下手工放行一次。
- **② 安装时会自动关闭正在运行的旧版本**:升级前**不用手工退出**「赛事积分榜」——安装程序会自己找到在跑的旧版本进程并关掉(连它拉起的 `scoreboard.exe` 服务端进程一起关)。以前那个「请先关闭程序」的提示框会被新界面压在下面,看不到又挡着流程,现场很容易卡在那儿出不来。
- **③ 安装位置(装到哪个目录)**:
- 向导里**默认填这台机器上次装的那个目录**;
- 切换「为所有用户安装 / 仅为我安装」时,**目录输入框会跟着变成该模式的默认目录**(分别是 `C:\Program Files\Scoreboard_Console` 和你的用户目录);
- 但你**手工改过路径(或点过「浏览…」)之后,再切模式也不会冲掉你填的那个目录** —— 想回到模式默认目录,把路径清空重新切一次模式即可;
- 想知道这次装到哪了:右键桌面「赛事积分榜」快捷方式 →「属性」→ 看「目标」。
- **静默安装**(`安装包.exe /S`,无人值守用):**会跳过旧版本卸载器** —— 旧卸载器自己可能弹一个没人能点的提权框,跳过它才能保证无人值守下一定跑得完。静默安装也可以用 `/allusers` / `/currentuser` 指定装法;用 `/D=` 指定目录时**以 `/D=` 为准**(不取「上次安装目录」的记忆)。
- 装到哪、装什么、桌面快捷方式(「赛事积分榜」)、卸载方式、数据与配置在 `%LOCALAPPDATA%\ScoreboardConsole\`(**覆盖安装不会丢**)—— 这些与升级前一致(交互式升级仍会先跑一遍旧版本的卸载器,这也是数据不能放在安装目录里的原因,见《部署指南》3.4)。
### ④ 升级后建议:把新版规则包重新导入一次
**做法**:管理端「导出 → 规则包 → 选择 YAML → **预览差异** → 确认导入并全量重算」,导入随本次发布的新版规则包。
**为什么建议做**:旧包缺少本次修正的通道配置(几个双计项目的团体通道口径、纯团体项目该走「按成绩自动排名」还是「人工名次」等),**不重新导入就不会生效**。
⚠️ **动手前先看清这个前提**:**导入会按规则包重写各小项的计分通道配置**——规则包覆盖到的小项,库里现有的通道会被整包替换。所以:
- **建议先导入、再按需要手工微调个别项目**;顺序反过来(先微调再导入),手工改动会被这次导入覆盖掉;
- 导入前先看「预览差异」里列出的通道增删改,确认没有把现场专门配过的项目改掉;发现被改,导入后到「基础数据 → 计分通道」改回来即可(保存后该小项会重算);
- 导入会**全量重算积分并刷新榜单**,尽量安排在**没有正在进行的项目**时做;
- 导入后正是上面那三处口径变化的生效点,请对着 ② 逐条看一遍榜单。
### ⑤ 升级时可能遇到的拦截(这两处以前会静默通过)
- **导入规则包时**:如果这份规则包存在**配置冲突**——典型情形是某个小项的**名次是靠人工录入的**(例如球类、拔河这类由裁判判名次的项目),规则包却给它配了**「按成绩自动排名」**(或「按队内平均」)的通道——导入会被**整包拒收**,一个字节都不写,并直接说明**是哪个小项、为什么不行、怎么改**(给这个小项单独写一段人工名次的通道配置,或调整规则包的匹配条件别套到它身上)。升级前这种情况是「先把通道换掉、紧接着重算时才报错」,名次表会停在半空(分数还在、奖牌却清零),自愈与重试导入都会因为同一个小项再失败一次——**现在不会留下这种坏状态**。
- **保存积分模板时**:如果**分值表里配的名次超过了「录取名次」**(例如分值表配到第 7 档、录取名次还留着 6),保存会被**拒绝**并说明怎么改:要么把录取名次改成 7、要么改成 0(0 = 不按名次封顶),要么删掉超出录取名次的那几档(例子里的第 7 档)。升级前这种配置能安静存下来,但第 7 档及以后在榜上恒为 0 分,界面上看不出任何异常——**现在会在保存这一步就说清楚**。
### ⑥ 升级后 5 分钟核对
1. 启动一次 Console,看运行日志 / `logs\operations\` 当天文件:应能看到 `0022` 与 `0023` 两条迁移记录,没有别的报错;
2. 刷新管理端「积分榜」:**单位总分榜、个人积分榜的数字与升级前一致**(除了 `0022` 清掉的历史脏数据);**单位奖牌榜的先后可能变了**(现在按金 → 银 → 铜排);
3. **看到「同分单位的先后变了」不要当故障**:重导规则包会把排序口径按规则包的值写回(本赛会包是 总分 → 金 → 银 → 铜 → 单位编码),**变的是顺序,分数与奖牌一件不变**(见 ② 第 3 条);
4. 打开「基础数据 → 计分通道」,选中一个双计项目(例如团体引体向上),确认「聚合口径」一列是**「平均」**——不切换就与升级前口径一致;
5. 打开「成绩录入」页:已发布的行右侧应**并排**「修改本条」与「作废本条」两个按钮;点一下成绩格会弹确认框(**点「取消」什么都不做**);
6. 按 ④ 导入新版规则包,导入后核对该项目的计分通道与榜单;
7. 用《上线检查清单》过一遍。
### ⑦ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 已发布成绩怎么改(修改 / 作废的区别) | 《使用手册》4.10;《常见问题》Q98 |
| 单位明细里的运动员 / 来源 / 已修订 | 《使用手册》8.1、8.3、17.3 |
| 团体分的「平均 / 总和」口径 | 《使用手册》10.4;《常见问题》Q15 |
| 单位奖牌榜为什么与积分榜顺序不同 | 《使用手册》8.2 |
| 导入被拒 / 保存模板被拒是什么原因 | 本文件 ⑤ |
| 迁移与安装 | 本文件 ① ③;《部署指南》3.1、7.5 |
---
## dev_0.5.0
### 一句话
**没有数据迁移,旧赛事项目包照常导入**:本版改的是「大屏控制 → 局域网大屏」卡片的取证逻辑——地址改为**按地址类别**判定(`169.254` 自动配置地址不再被排除),并新增**宽松兜底 / 默认路由推断 / 手动添加地址**三层,空态会说明被跳过的网卡与原因。以前卡片会把「自动配置地址」当成没有可用地址,现已修正。
### ① 局域网大屏卡片改为按地址类别判定
- **以前**:只取「接口 Up 且非回环」的网卡,并把**链路本地地址(`169.254.x.x`)也排除**,理由写的是「DHCP 没拿到地址才自配的,说明网络不健康」——那是对网络健不健康的**猜测**,不是地址能不能用的**事实**。
- **现场形态**:有机器就在 **`169.254` 自动配置网段**(本网段没有 DHCP,设备靠链路本地地址互访),平板实测能访问 `http://169.254.79.190:19540/display`,网络与防火墙全通;而卡片却因为那条猜测显示「未检测到局域网地址」——**那是误判**。
- **现在**:只排除四类「作为对端访问目标没有意义」的地址——**回环、未指定(`0.0.0.0`)、组播、广播**;**链路本地(自动配置)地址与私网、全局地址一样进候选**,只是**排在最后**并带一句说明「自动配置地址:本网段没有 DHCP,同网段设备可以互相访问」。判定全部走标准库谓词,**不抄一份网段字面量到代码里**(抄错或漏一段就会变成「明明有地址却说没有」,正是这次要修的毛病)。
### ② 新增三层兜底(宽松兜底 / 默认路由推断 / 手动添加地址)
| 层次 | 触发时机 | 卡片表现 |
| --- | --- | --- |
| 严格轮 | 正常机器(网卡 up 位读得到) | 地址照常列出,不加提示 |
| **宽松兜底** | 严格轮一无所获时(Windows 上部分驱动 / 虚拟网卡**读不到 up 位**) | 不再要求 up 位,把地址捡回来并提示「网卡状态读不到(可能是驱动或虚拟网卡),地址本身可用,打不开就换下面一条」 |
| **默认路由推断** | 前两轮都为空时 | 问操作系统「去局域网走哪块网卡」(UDP Dial:只查路由表、**不发一个包**),地址提示「这条地址是按系统默认路由推断出来的(网卡枚举里没有它),地址本身可用,打不开就换下面一条」 |
| **手动添加地址** | 以上都没给出你要的网段时 | 卡片下方「手动添加地址」填入 `ipconfig` 里的 IPv4 地址,点「添加」立刻出链接与二维码;手填的**排第一条**、带「手动」徽标、可「删除」,记在浏览器本地**刷新不丢**(最多 10 个) |
严格轮有结果就绝不跑宽松轮,前两轮任意一轮有结果就绝不跑路由探测——只有真的一个地址都拿不到时才会多花那几次本地 UDP connect,正常机器上一次都不会发生。
### ③ 空态会说明被跳过的网卡与原因
- 空态从一句「未检测到局域网地址(可能是没插网线 / 只有回环)。」改成逐条列出**检查过、但没贡献地址**的网卡与原因,例如「没找到可用的局域网地址。已检查:以太网(接口未连接)、WLAN(只有 IPv6 地址)。」;四种原因是「接口未连接」「只有 IPv6 地址」「接口没有地址」「回环接口」,**最多列 5 条**,网卡更多时其余折叠成「**等共 N 块网卡**」;
- 老服务端不返回这份清单时,显示的仍是原来那句,行为与升级前完全一致。
### ④ 没有数据迁移
- 本版**没有任何数据库迁移**,也没有设置项迁移;旧赛事项目包照常导入、切换、导出,已有榜单数字与升级前一致。
### ⑤ 升级后 3 分钟核对
1. 启动 Console,打开 `logs\console.log`:没有意外报错;正常应有一行「局域网地址:…(网卡名)」,一个地址都没有时会是一条带原因的 WARN,方便直接看出该修哪张网卡;
2. 用录入员及以上账号进「大屏控制」页,确认「局域网大屏」卡片列出地址;只有 `169.254.x.x` 的机器上应能看到它、并带「自动配置地址」那句说明;
3. 用平板 / 手机扫第一个地址的二维码,确认能打开大屏;
4. 自动检测为空时试一次「手动添加地址」(填 `ipconfig` 里的地址),确认立刻出链接与二维码;
5. 局域网设备连不上的机器,先确认装的时候选的是哪一项:选**「为所有用户安装」**的,安装程序提权时已经自动放行入站 **19540**(防火墙里能看到规则 `Scoreboard Console (TCP 19540)`);选「仅为我安装」的,按《部署指南》7.5 的命令手工放行一次;
6. 用《上线检查清单》过一遍。
### ⑥ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 三类地址的含义、手动添加地址 | 《使用手册》第 9 节 |
| 防火墙放行与排障常识 | 《部署指南》7.5、7.9 |
| 空态原因与自检工具 | 《常见问题》Q101 |
| 接口字段与判定顺序 | `devdocs/05` 大屏控制与运维 |
---
## dev_0.4.0
### 一句话
**没有数据迁移,旧赛事项目包照常导入**:本版修了两个现场问题(kiosk 窗口误点穿、kiosk 窗口被任务栏盖住)并新增一个功能(大屏控制页的「局域网大屏」卡片)。⚠️ 唯一要留意的:**老机器配置文件里的 `display.ignoreMouse: true` 已废弃、不再生效**——升级后大屏窗口自动变成「不穿透」,想恢复穿透要改用新键名。
### ① kiosk 窗口不再点击穿透,旧键 `display.ignoreMouse` 已废弃
- **以前**:多屏 kiosk 窗口默认开启 `setIgnoreMouseEvents(true)`,本意是「不接收误触」,但它的真实语义是「**本窗口完全忽略鼠标**」——点击会落到大屏**后面**的窗口或桌面上,现场想防的误触反而变成误点别的东西;被忽略鼠标的窗口也点不活、被别的窗口盖住后抢不回前台。
- **现在**:大屏窗口**默认吞掉鼠标点击、不穿透**,点击不会漏到后面的窗口或桌面,被盖住后点一下就能回到最前。
- **开关改名**:`display.ignoreMouse` → **`display.allowClickThrough`**(默认 `false`)。旧键现在**完全不读**——老机器配置文件里那个 `ignoreMouse: true` 不会再让大屏穿透。
- **为什么换键名而不是只改默认值**:旧版默认就是穿透,而且旧版模板已经把 `ignoreMouse: true` 写进了现场机器的配置文件(`%LOCALAPPDATA%\ScoreboardConsole\console\config.json`),而 Console 的规矩是**已存在的用户配置绝不覆盖**——光改默认值救不了老机器,配置文件里那个显式 `true` 会一直压着默认值;也没法区分「操作员刻意要穿透」和「旧模板留下的 true」。换个新键名,旧文件里的旧键自然失效,现场不动配置文件就回到「不穿透」。
- **升级后第一次启动**,如果配置文件里还留着旧键,Console 会在 `logs\console.log` 里记一条**中文警告(只记一次,不随大屏重排重复刷)**,原文是:
> 警告:配置项 display.ignoreMouse 已废弃、不再生效:本机配置文件里写的 ignoreMouse: true 会被忽略。大屏窗口现在默认「不穿透」,点击不会再漏到大屏后面的窗口或桌面;要让大屏恢复点击穿透,请改用 display.allowClickThrough: true
(`ignoreMouse` 后面跟的值会原样照抄你配置文件里写的内容。)**旧键的值一律忽略,也不会被自动改写进你的配置文件。**
- **确实需要穿透**(把大屏当纯展示层、同一块屏上还要操作别的窗口)才显式写 `display.allowClickThrough: true`,代价是:点击会漏到大屏后面的窗口 / 桌面(误触会点到别的东西),大屏也点不活。
### ② kiosk 窗口现在压得住任务栏
- **以前**:先 `setKiosk(true)` 再 `setBounds(...)`,在 Windows 上会把窗口从真正的全屏态拽回「恰好铺满该屏的无边框窗口」——它不是置顶层,**任务栏与任何拖到这块屏上的窗口都能盖在它上面**;再叠加上一条的穿透,大屏被盖住后还点不活。
- **现在**:多屏 kiosk 窗口固定置顶在 **`screen-saver` 层级**(Windows 上 `setAlwaysOnTop(true)` 的默认层级 `floating` 仍画在任务栏**下面**,只有 pop-up-menu 及以上才压得住任务栏)。效果:**任务栏盖不住它,别的窗口拖到这块屏上也盖不住它,被盖住后点一下就能回到最前**。
- 调用顺序固定为「**先 `setBounds` 定位 → 再 `setKiosk(true)` → 最后 `setAlwaysOnTop(true, 'screen-saver')`**」,并加了「已经是对的状态就直接返回」的守卫,避免重排时反复进出 kiosk 导致大屏白闪。窗口化(单屏调试态)会把置顶摘掉。
### ③ 大屏控制页新增「局域网大屏」卡片
- 卡片列出主机在局域网里**可用的地址**,拼成完整链接(形如 `http://192.168.1.5:19540/display`):链接可点开,旁边有**复制**按钮(复制成功短暂显示「已复制」),**第一个地址还带二维码**,手机扫码即可打开;
- 地址与端口由服务端 `GET /api/system/network` 下发(真实监听端口与路径,不是写死的),按现场最可能用到的顺序排(`192.168.*` → `10.*` → `172.16–31.*` → 其它);
- 没有可用地址时显示「未检测到局域网地址(可能是没插网线 / 只有回环)。」——这不是故障,表示主机当前没有别的设备能连上的地址;
- 这张卡片**需要录入员(recorder)及以上**登录才看得到,只读访客会被提前拦住。
### ④ 没有数据迁移
- 本版**没有任何数据库迁移**,也没有设置项迁移;旧赛事项目包照常导入、切换、导出,已有榜单数字与升级前一致。
- 配置文件里那份旧键我们**不会**替你删改(现场那份原样留着,人自己决定),它只是不再生效。
### ⑤ 升级后 3 分钟核对
1. 启动 Console,打开 `logs\console.log`:确认没有意外的报错;
2. 看多屏大屏:窗口应当压住任务栏、点一下能回到最前,且**点击不会再点到桌面或后面的窗口**(即不穿透);
3. 若有老机器配置文件里写着 `ignoreMouse: true`,日志里应能看到上面那条「已废弃」警告——这是正常的,行为已是「不穿透」;
4. (可选)确实要穿透的机器:在 `%LOCALAPPDATA%\ScoreboardConsole\console\config.json` 里写 `"allowClickThrough": true`,重启 Console;
5. 用录入员及以上账号进「大屏控制」页,确认右侧有「局域网大屏」卡片,点「复制」能复制链接、手机能扫第一个地址的二维码打开大屏;
6. 用《上线检查清单》过一遍。
### ⑥ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 多屏 kiosk 的鼠标 / 置顶行为 | 《部署指南》6.2 配置表、7.4 |
| 「局域网大屏」卡片怎么用 | 《使用手册》第 9 节 |
| 接口与字段 | `devdocs/05` 大屏控制与运维 |
---
## dev_0.3.0
### 一句话
**旧版赛事项目包仍可导入**:本版只有一条迁移(**0021**),只给破纪录登记表加一列可空的「理由」。升级后榜单数字应当与升级前一致;新增四个现场入口(作废 / 重新录入成绩、作废已批准的破纪录、录入历史纪录、仪表盘四张新卡片)。
### ① 迁移只有一条(0021),而且只是「加一列」
- 迁移 **`0021_record_breaks_note.sql`**:给 `record_breaks` 表加一列 **`note`**(TEXT,**可空**,默认 NULL)——记「这条破纪录登记为什么被驳回 / 作废」。
- 它**只加列**:不重建表、不改任何既有数据行;老登记的 `note` 保持 `NULL`(「本来就没有理由」是事实,不会被写成一条假理由)。
- ✅ **旧版赛事项目包仍可导入**。导入一个不含 `note` 列的旧包后,它**成为当前赛事时(切换过去、服务端启动打开赛事库时)会自动补跑迁移**,**不需要任何手工处理**;旧的破纪录登记、纪录库、成绩与积分一行不丢。
- 备份同理:升级前的备份文件(旧 `event.db`)照常能恢复,恢复后再打开时也会自动补迁移。
### ② 四个新入口
| 入口 | 位置 | 做什么 |
| --- | --- | --- |
| **作废本条 / 重新录入** | 成绩录入页每行的「操作」列 | 手滑填错了不必整组撤销发布:已发布的行仍然是锁的,但可以点「作废本条」(**必填原因**)让这一条退出名次与积分;已作废的行显示红徽标「已作废」,点「重新录入」(必填原因)退回草稿,改完再发布本组。两者都**立即重算并推大屏**,不受「分批发布时实时更新榜单」这个延迟结算开关影响 |
| **已批准的破纪录 / 作废** | 破纪录页新增的「已批准的破纪录」卡片 | 批错的破纪录可以撤回:点「作废」(**必填原因**)→ 撤回该笔加分、重算推榜,并把该级别的当前纪录**恢复为上一条** |
| **新增历史纪录 / 删除** | 破纪录页「纪录库」卡片 | 赛前手工登记历史纪录(小项 / 级别 / 成绩值或文本 / 保持人 / 保持单位 / 创造日期);每行可「删除」,删的是当前纪录时会恢复上一条。**「来源」列现在真的会显示「历史」或「本届」**(以前没有历史录入入口,实际只会是「本届」) |
| **仪表盘四张新卡片** | 仪表盘 | 今天的小项(按排期 + 进度)、草稿待发布、待确认破纪录、大屏在线数;旧卡片保留 |
### ③ 「拒绝」从内存改持久带来的行为变化
- 以前点「拒绝」只在**本机浏览器里**把这条疑似破纪录藏起来,刷新就回来。现在改成**先登记再驳回**:服务端会登记一条破纪录记录并立即驳回(理由写「现场判定不是破纪录」),**刷新后不再出现**;谁在什么时候否掉了哪一条,也能在审计日志里查到。
- ⚠️ **升级前在本机「拒绝」过的疑似破纪录,升级后刷新会重新出现一次**——因为那次拒绝从来没有写到服务端。重新点一次「拒绝」即可(这次会落到服务端)。
- 只有真的写不进去时(示例数据模式 / 未连接服务端)才退回本机隐藏,提示会如实说明「刷新页面后该条会重新出现」。
### ④ 升级后 5 分钟核对
1. 打开一次「成绩录入」页,确认表格最后一列是「操作」;
2. 打开「破纪录」页,确认多出「已批准的破纪录」卡片,且「纪录库」卡片有「新增历史纪录」按钮与每行的「删除」;
3. 打开仪表盘,确认多出今天的小项 / 草稿待发布 / 待确认破纪录 / 大屏在线数四张卡片;
4. 旧赛事包核对:导入一个**升级前导出的赛事项目包**并切换为当前赛事,确认能正常打开、破纪录与纪录库数据都在(迁移 0021 会自动补跑);
5. 用《上线检查清单》过一遍。
### ⑤ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 手滑填错一条成绩怎么改 | 《使用手册》4.10;《常见问题》Q98 |
| 破纪录批错了 / 怎么拒绝 | 《使用手册》6.1;《常见问题》Q99 |
| 历史纪录怎么录 | 《使用手册》6.2;《常见问题》Q100 |
| 仪表盘四张卡片 | 《使用手册》第 3 节;开发侧 `devdocs/07` §7 |
---
## dev_0.2.0
### 一句话
**没有需要迁移的数据**:这一版是 100 多项缺陷与体验修复的合集(含一次改名、几处口径收紧)。升级后榜单数字应当与升级前一致。
### ① 三件升级前必须知道的事
**1)「团体奖牌榜」改名为「单位奖牌榜」**,导出件也跟着改了名:
- 界面上:大屏控制页的切页下拉、大屏奖牌榜页标题、管理端「积分榜」页的页签,都叫 **单位奖牌榜**;
- 导出件:下载文件名由 `团体奖牌明细.xlsx` 改为 **`单位奖牌明细.xlsx`**,Excel 里的工作表名同步改为 **`单位奖牌榜`** / **`单位奖牌明细`**。
→ **如果你把旧文件名写进了对账脚本、打印模板或交接文档,记得改**。
- **旧名仍然可用**:老链接(`?page=团体奖牌榜`)与老配置(`display.pages` 里写 `medals` 或旧名)照常生效,不用改。
**2)审计日志的动作前缀统一了**(`entries.import` → `entry.import`,`entries.import.resolve` → `entry.import.resolve`):
- **升级前落库的历史记录不会跟着改**——它们仍写着旧前缀。所以**查历史时请用子串 `import` 筛**(新旧都能筛到);用 `entry.` 只能筛到升级之后的记录。审计是只追加的,我们不会改写历史。
**3)密码长度改成按「字符」数**(原来是按字节):
- 下限仍是 8 **位**,但现在按字符算:**7 个汉字(原来 21 字节能过)现在会被拒**;`3 个汉字 + 5 个字母`(8 字符)正常通过。
- 上限仍是 72 字节(bcrypt 的边界),文案里会分别写清「位」与「字节」。
### ② 现场会看到的变化
- **导出件里的「未结算」**:开了延迟结算时,「已发布但那一组还没结算」的行,导出的「分项成绩表 / 全部 / 全部(单页)」现在写 **名次 `—` / 积分 `—` / 状态 `未结算`**(成绩照常打印)。原来这三列是「空名次 + 0 分 + 有效」,读起来像「算出来就是 0 分」。
- **基础数据包导入遇到「已彻底删除的单位」**:那一行**整行跳过**并在导入结果里说明原因(不再更新它的字段、也不会把它翻出来);要让单位回来,先到「基础数据 → 参赛单位」勾选「显示已彻底删除的单位」再点「恢复」。
- **报名名单导入换了单位会明确提示**:「第 N 行:某某 换了单位,原单位 A 在本组别的报名已移出,已改在单位 B 加入」——数据行为没变(一直是这样),现在会说出来了。
- **「从已有名单勾选报名」有冲突时不再报「已加入」**:会明确提示「有 N 行没有加入,需要逐条确认」,并在页内列出是哪几行。
- **导出核对更省事**:单位积分明细的「成绩」列与分项成绩表、个人明细**逐字一致**(原来少个单位,如 `11.58` vs `11.58 秒`);空单位的「单位积分明细」也会打印末行「合计」。
- **收不到回执的危险操作不再误导**:一键恢复请求超时/断连时,提示由「恢复未执行」改为「**没收到回执,恢复可能已经生效**」,并单独放宽了超时时间;两个管理员同时点恢复时,第二个会拿到「正在恢复,请稍后」。
### ③ 部署相关的两处
- **赛事包上传上限是 512MB**(名单 CSV 与基础数据包那一档仍是 32MB,赛事包刻意放宽——它要装字体、背景图、各单位 logo;字体单个就允许 20MB)。超限会提示「解析上传失败」。
- **反向代理(nginx 等)**:若以前遇到「登录一定 403」,本版起错误提示会指明原因与修法;正解是让代理透传原 Host(`proxy_set_header Host $host;`),或配置可信代理并把原 Host 透传在 `X-Forwarded-Host` 上。**不要**为了绕过它把校验放宽——那等于开登录 CSRF 的口子。
- 顺带:**丢了 CSRF Cookie 不再等于「能看不能写」**——管理面板会自动补发,症状消失后无需再刷新页面。
### ④ 升级后 5 分钟核对
1. 打开服务管理窗口的运行日志:**这一次升级没有那条「通道名次自愈」记录是正常的**(本版没有新迁移,不需要重算);若看到它,说明你从上上版直接跳过来,等它跑完即可;
2. 刷新积分大屏与管理面板:**单位总分榜、单位奖牌榜、个人积分榜的数字与升级前一致**;
3. 随便挑一个小项导出一次「分项成绩表」,确认表头与列都对;
4. 用《上线检查清单》过一遍。
### ⑤ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 榜名/导出文件名的变化 | 本文件 ①;《使用手册》8.2、11.1 |
| 导出里三种「还没出结果」的行 | 《使用手册》11.1;《常见问题》Q90 |
| 基础数据包遇到已删除的单位 | 《使用手册》11.4;《常见问题》Q88 |
| 恢复与安全副本保留份数 | 《部署指南》8.3;《常见问题》Q40 |
| 反代/登录 403 | 《部署指南》7.x 与应用内提示 |
---
## dev_0.1.8
### 一句话
修掉了一个**会多算单位总分**的计分缺陷;奖牌改成可以按小项、按通道开关;报名名单认人改成**以证件号为准**。
### ① 升级后必须补的一件事(本版唯一需要人工补录的地方)
**「团体引体向上」这类「个人+团体」项目的团体名次,要到成绩录入页补录一遍。**
原因是旧版**没有录团体名次的地方**:这类项目的团体分是拿**个人名次顶替**着算出来的(所以会算多)。本版改成从「团体名次」区块读,**没录就是 0 分**。
- 补录位置:**成绩录入**页 → 选中该小项与组别 → 表格下方 **「团体名次」** 卡片 → 按单位填名次 → **保存团体名次**(留空 = 清空该单位;名次允许并列;个人名次不受影响)。
- 如果某单位不参加该项,留空即可。
- **不想手填的替代方案**:把该小项的团体通道从「手动名次」改成「按队内平均」(**基础数据 → 计分通道**),系统会按每队成员成绩自动算团体名次。
**两种口径二选一,由赛会规则决定**——「团体引体向上」这条现在还挂着旧模板(手动名次),要按领导定的口径确认一次。
### ② 分数会变,这是对的(不是坏了)
- **单位总分**:旧版在「个人+团体」项目上会把**个人**名次当成**团体**名次、按团体表再发一次分。实测某队在成绩没改的情况下,第一次发布 45 分、再点一次发布变 85 分。
本版已修正:**同一份数据无论发布几次,结果完全一致**。
- 所以升级后如果你之前录过并发布过这类项目,**单位总分会出现变化**(变小是正常的,那是修正后的值)。按 ① 把团体名次补录完,再核对一次即可。
- **个人积分不受影响**(个人通道的算法没变);奖牌数可能变化(见 ③)。
### ③ 现场会看到的新东西
**奖牌可以开关了**(三层,从粗到细):
1. 小项级:**基础数据 → 大项 / 小项 → 编辑小项**,「选项」里有 **「该项启用奖牌结算」**(**默认勾上**)。取消 = 这个小项只出积分、一块牌都不发;
2. 通道级:**基础数据 → 计分通道**,表里多了 **「奖牌通道」**列,两个开关——**「发奖牌」**(这条通道的名次发不发牌)与 **「个人奖牌并入单位金牌榜」**(个人项目拿的牌算不算进单位金牌总数);
3. 名次仍然只发给**前三名**(并列口径不变)。
> ⚠️ 迁移默认把三个开关都设成**开**,也就是和升级前一致,不会让既有小项突然掉牌。要改哪个小项,按赛事规则逐个去关。
**成绩录入页多了「团体名次」卡片**——只在配了「团体名次 = 手动名次」通道的小项上出现;纯团体项目(篮球等)和「按队内平均」的项目不会出现,那是正常的。
**报名名单认人改成以证件号为准**:匹配顺序 **证件号 → 号码布 → 姓名 + 单位**。同一份表里同一证件号出现多次 = 同一个人报多个组别(会给提示,不再报错);只有「同证件号 + 同一个小项同一个组别」才会进冲突面板问你保留哪一条。
**下面这些动作现在会立刻重算并刷新大屏,即使管理员开了「延迟结算」**:
撤销发布 / 作废单条成绩 / 批量退赛·恢复·移出报名 / **报名名单导入改了状态**(例如把某人改成退赛)。
「延迟结算」只影响**发布成绩**这一件事(不因一批成绩跳动榜单),不会让退赛、作废这类「谁还算数」的改动被拖着。
### ④ 其它修复
- 管理员**撤销会话 / 停用账号 / 改密码**后,那台机器上还开着的实时连接会立刻断开,不再继续收数据;
- 访客(guest)身份收不到系统配置类的实时推送;
- 导出一份不存在的小项 / 单位、手填名次填 0 或负数、性别或年龄填了非法值 → 现在是**明确的错误提示**,不再是「服务端异常」;
- **示例数据模式**(后端连不上时的演示模式)下,批量停用 / 批量或单条彻底删除会被拦下并提示,不会假成功;
- **服务管理窗口**:显示器短暂只剩一块(拔线 / 电视待机)之后,再把扩展屏插回来会**自动恢复全屏**,不用重启程序;
- **自定义大屏模板**:嵌套过深或体积过大的模板会给出明确提示,不会让大屏白屏。
### ⑤ 升级后 5 分钟核对
1. 打开服务管理窗口的**运行日志**,看有没有那两行自愈记录(`检测到通道名次为空但已有已发布成绩…` / `一次性全量重算完成…`),**这是正常的**;
2. 刷新积分大屏 / 管理面板:**奖牌榜不是全 0**;
3. **单位总分与升级前一致**(除了 ② 说的「个人+团体」项目);
4. 打开一次成绩录入页,确认该录团体名次的小项上有**「团体名次」**卡片;
5. 打开一次**基础数据 → 大项 / 小项**,确认「该项启用奖牌结算」是按赛事规则勾的;
6. 用《上线检查清单》从头过一遍。
### ⑥ 详细说明在哪
| 想了解 | 看 |
| --- | --- |
| 奖牌开关怎么用 / 什么时候关 | 《使用手册》10.2(小项)、10.4(计分通道) |
| 奖牌榜没牌 / 金牌数不对怎么查 | 《常见问题》Q94 |
| 团体名次怎么录 / 为什么没有那一块 | 《使用手册》4.9、《常见问题》Q95 |
| 升级后奖牌榜是空的 | 《部署指南》3.4、《常见问题》Q96 |
| 名单导入怎么认人、怎么填 | 《报名名单导入规范》 |
| 延迟结算下哪些动作会立刻生效 | 《使用手册》4.8、《常见问题》Q91 |
| 历史成绩版本重放与团体名次 | 《常见问题》Q97(已知限制) |
---
## dev_0.1.7 及更早
本文件从 **dev_0.1.8** 起维护;更早版本的改动不再逐版补记。若需要,可在《使用手册》与当时的发布记录里查。