feat: 运动员彻底删除(真物理删除 + 重算积分)+ 报名表 status 容错 + 部署包带导入规范
## 运动员「彻底删除」= 真删除
`DELETE /api/athletes/{id}?purge=1`(不带参数仍是「停用」软删除)。在一个事务里:
删积分流水(含已作废历史流水)→ 删破纪录登记 → 删成绩 → 删报名 → 删人员 →
对受影响的 (小项, 组别) 调 recomputeLedgerTx + applyComputedRanks 重算流水与名次 →
bumpEvent/bumpStandings 推大屏 → 审计 athlete.purge(含删除规模)。
响应带 {deletedEntries, deletedResults, deletedLedger, deletedBreaks, recomputedEvents}。
必须先删 results 再删 entries(results.entry_id 无 ON DELETE);流水按 athlete_id / entry_id /
result_id 三种引用一把清,漏一种就留悬挂。
管理端「运动员」行加「彻底删除」按钮 + 危险确认框(如实写明报名与成绩一并删除、
相关小项排名与积分会重算),成功 toast 报出删除规模。
## 报名表 status 列容错
新增 entry_status.go 的 normalizeImportStatus:大小写不敏感(DNS/Registered 都认),
认「正常/退赛/弃赛/请假/取消资格/犯规/未出场/未到/缺席」等中文别名,留空即 registered,
认不出则给中文行级错误并跳过该行。此前原样入库,撞 entries.status 的 CHECK 约束后
抛原始 SQLite 错误,填表人看不懂。
## 修 isUniqueViolation 把 CHECK 失败误报成「已存在」
SQLite 的 CHECK / NOT NULL 失败也带 "constraint failed",旧匹配把「小项 status 取值非法」
报成 409「小项编码已存在」,现场会去找一个根本不存在的重名编码。收紧为只认
"unique constraint failed"。实测:重复编码仍 409;非法 status 不再误报。
## 安装包平铺《报名名单导入规范》
deploy/prepare-extra.mjs 改清单式,部署包根目录除 使用说明.txt 外新增
报名名单导入规范.txt。
测试:服务端 12 包全绿(新增 athlete_purge_test.go、entry_status_test.go);
前端 vue-tsc 通过、166 例全过;Console 语法检查 17 文件。
另在真二进制 + 真 SQLite 上跑通破坏性路径:删人后本人痕迹全为 0、他人不受影响、
榜单按新排序重算、foreign_key_check 无悬挂。docs/ 与 devdocs/ 同步更新。
This commit is contained in:
1 parent
22ab49e73a
commit
9d4ee0946c
22 files changed
+1264
-54
No files matched your search
+38
-6
@@ -323,9 +323,35 @@
|
||||
|
||||
1. 点「新增运动员」,填写姓名 *、性别、年龄、所属单位 *、工号 / 学号、证件号、号码布等(年龄可留空,填了必须是 0–120 的整数);
|
||||
2. **证件号(如身份证号)与号码布二者取其一**即可唯一标识一个人,用于区分重名;两个人员不能共用同一个证件号,也不能共用同一个号码布,重复会被拒绝;没有身份证信息的人可以只填号码布。已有历史数据两项可以都为空;
|
||||
3. 「编辑」修改,「停用」后不再出现在新报名选择中;
|
||||
3. 每行有三个动作:**编辑**、**停用**(停用后按钮变成「启用」)、**彻底删除**;
|
||||
4. 个人项目的报名项会关联到运动员,团体项目可以留空。
|
||||
|
||||
**停用与彻底删除的区别**
|
||||
|
||||
| 状态 | 人员列表里 | 还能被报名选中吗 | 他名下的报名 / 成绩 / 积分 | 能恢复吗 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 启用(默认) | 在 | 能 | 保留 | —— |
|
||||
| 停用 | 还在(标记「已停用」) | 不能 | **保留** | 点「启用」即可 |
|
||||
| 彻底删除 | **不在了** | 不能 | **一并删除** | 恢复不了 |
|
||||
|
||||
「停用」是软删除,只是不让他再报名;「彻底删除」是**真删除**。操作步骤:
|
||||
|
||||
1. 点该行右侧红色的「彻底删除」;
|
||||
2. 在确认框里核对提示(会写明报名与成绩一并删除、相关小项的排名与积分会重算),再点一次「彻底删除」;
|
||||
3. 完成后页面给出删除规模,例如「已彻底删除「张伟」:报名 1 条、成绩 1 条、积分流水 2 条,已重算 1 个小项的积分与名次」。
|
||||
|
||||
**「彻底删除」会永久删掉什么**
|
||||
|
||||
- 这个人的**人员档案**:从运动员名册里消失,报名选择器里也选不到,界面上再也恢复不了;
|
||||
- 他名下的**报名**与**成绩**;
|
||||
- 这些成绩产生的**积分流水**(含已作废的历史流水)与**破纪录记录**。
|
||||
|
||||
删掉成绩会改变同组其他人的名次与得分,所以系统在同一个动作里**按新排序重算受影响小项的排名与积分**,并把结果推到大屏。因此:
|
||||
|
||||
- 已经有成绩的比赛,删人**会让名次和积分发生变化**(例如原来的第二名升到第一、得分跟着变),删完请核对一下榜单;
|
||||
- **只是想暂时不让他报名**,请用「停用」——它保留全部历史数据,随时可以再启用;
|
||||
- 该人的姓名也不会再出现在「分项成绩表」「个人积分榜」上:这些榜单是现算的,数据删了他就不在榜里。
|
||||
|
||||
### 10.7 报名导入
|
||||
|
||||
报名有两种方式,都在本页完成:**从已有名单勾选**适合零散补报,**表格导入**适合批量录入。
|
||||
@@ -354,15 +380,21 @@
|
||||
1. 点「下载 CSV 模板」获取表头样例;
|
||||
2. 表头共 11 列:`event_code`、`category`、`team_code`、`athlete_name`、`id_card`、`gender`、`age`、`bib`、`seed`、`status`、`member_names`(大小写不敏感)。其中 `id_card`(证件号)、`gender`(性别)、`age`(年龄)为可选列,缺失不影响导入,其余列必须包含;
|
||||
3. **只要有姓名的行,`id_card` 与 `bib` 必须至少填一个**,否则该行报错并跳过;`gender` 只认「男」「女」,其他值忽略;`age` 可留空,填了必须是 0–120 的整数;同一份文件里同一个证件号或同一个号码布重复出现时,重复的行会报错;
|
||||
4. 人员匹配顺序:
|
||||
4. **`status` 列很宽容**:大小写不敏感(`DNS`、`Registered`、`registered` 都认),也认中文别名——
|
||||
- `正常` / `正常参赛` / `参赛` → 正常参赛;
|
||||
- `退赛` / `弃赛` / `请假` → 退赛;
|
||||
- `取消资格` / `犯规` → 取消资格;
|
||||
- `未出场` / `未到` / `缺席` → 未出场。
|
||||
留空即「正常参赛」。真正认不出的写法会给出中文行级错误、该行跳过,例如「第 12 行:status「已报到」无法识别,只能填 registered / scratched / dq / dns(或留空)」;
|
||||
5. 人员匹配顺序:
|
||||
1. 先按 `id_card` 匹配已有人员;
|
||||
2. 没匹配到,再按 `bib`(号码布)匹配;
|
||||
3. 还没匹配到,按「姓名 + 单位」匹配且该人员证件号为空,视为同一人,把表里给的证件号 / 号码布 / 年龄补进去(不算冲突);如果该人员已有号码布且与表里不同,则算冲突;
|
||||
4. 都没匹配到则新建人员(姓名、性别、年龄、单位、证件号、号码布);
|
||||
5. `bib` 列会同时写入人员档案与报名记录;从已有名单勾选生成的报名也会带上人员的证件号(优先)或号码布;
|
||||
6. 把 `.csv` 或 `.xlsx` 拖入虚线框,或点击选择文件(单个文件不超过 16MB;xlsx 只解析第一个工作表);
|
||||
4. 都没匹配到则新建人员(姓名、性别、年龄、单位、证件号、号码布)——被「彻底删除」的人(见 10.6)档案已经不在库里,匹配不到他,再次导入会当作**新人员**重新建档,他以前的报名与成绩不会回来;
|
||||
6. `bib` 列会同时写入人员档案与报名记录;从已有名单勾选生成的报名也会带上人员的证件号(优先)或号码布;
|
||||
7. 把 `.csv` 或 `.xlsx` 拖入虚线框,或点击选择文件(单个文件不超过 16MB;xlsx 只解析第一个工作表);
|
||||
- **CSV 编码不用管**:UTF-8、带 BOM 的 UTF-8(Excel 的「CSV UTF-8」)、GBK / GB18030(中文 Windows 上 Excel「另存为 CSV」的默认编码)、UTF-16 都能直接导入,中文不会乱码,服务端会自动识别;
|
||||
7. 点「开始导入」,页面显示**新增 / 更新 / 跳过**数量;匹配不到的行会跳过并回显行号,修正后可重新上传。
|
||||
8. 点「开始导入」,页面显示**新增 / 更新 / 跳过**数量;匹配不到的行会跳过并回显行号,修正后可重新上传。
|
||||
|
||||
**人员信息冲突的处理**
|
||||
|
||||
|
||||
@@ -280,3 +280,45 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
|
||||
同一层还有 `config.yaml`(服务端配置)、`console\config.json`(Console 配置)与 `rules\`(规则包目录),也都在安装目录之外,同样不会被覆盖安装或卸载删掉。
|
||||
|
||||
要换位置:改 `%LOCALAPPDATA%\ScoreboardConsole\console\config.json` 里的 `server.dataDir`(支持绝对路径,相对路径按安装目录解析),重启 Console 生效。Console 会把这个目录用 `-data` 传给服务端,**它优先于 `config.yaml` 里的 `dataDir`**,所以只改 `config.yaml` 是不生效的。详见部署指南第 3.4 节与第 3.5 节。
|
||||
|
||||
**Q56:运动员为什么删不掉?怎么彻底删掉一个人?**
|
||||
|
||||
「基础数据 → 运动员」每行有三个动作:**编辑**、**停用**(已停用的人显示为「启用」)、**彻底删除**。以前只提供「停用」,所以看着像「删不掉」;现在点该行右侧红色的「彻底删除」,在二次确认框里再点一次「彻底删除」即可,删完页面会给出规模提示,例如「已彻底删除「张伟」:报名 1 条、成绩 1 条、积分流水 2 条,已重算 1 个小项的积分与名次」。它删掉什么、为什么会让榜单变化,见 Q57。
|
||||
|
||||
**Q57:停用和彻底删除有什么区别?**
|
||||
|
||||
| 动作 | 人员列表里 | 还能被报名选中吗 | 他名下的报名 / 成绩 / 积分 | 能恢复吗 |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| 停用 | 还在(标「已停用」) | 不能 | 保留 | 点「启用」即可 |
|
||||
| 彻底删除 | **不在了** | 不能 | **一并删除** | 恢复不了 |
|
||||
|
||||
- **停用**是软删除:人还留在名单里,只是不再出现在新报名的选择里;历史报名、成绩与积分全部保留;随时可以再启用。只是想暂时不让他报名,用它就够了。
|
||||
- **彻底删除是真删除**:人员档案,以及他名下的报名、成绩、由这些成绩产生的积分流水(含已作废的历史流水)与破纪录记录,都会从库里删掉,界面上无法恢复。删完他也就不再出现在人员列表、报名选择和各类榜单里。
|
||||
- **删人会改动榜单**:删掉成绩会改变同组其他人的名次与得分,所以系统会在删除的同时**按新排序重算受影响小项的排名与积分**并推送到大屏。已经有成绩的比赛,删人后原来的第二名可能升到第一、得分跟着变,删完请核对一下榜单。
|
||||
- 已经发布的比赛要改人,更稳妥的做法是撤销发布、改好成绩再重新发布(见 Q8);「彻底删除」是给「这个人根本不该出现在系统里」的情况用的。
|
||||
|
||||
**Q58:删掉的人怎么又出现在名单里了?**
|
||||
|
||||
彻底删除之后,如果又在报名表里导入同一个人(同一个证件号或号码布),他会以**全新的档案**重新出现在运动员名单里——因为旧档案已经连同他的报名与成绩一起删掉了,系统按证件号 / 号码布找不到他,就当作新人员建档。所以名单里突然多出一个「以前删过的人」,通常就是某次导入带回来的。
|
||||
|
||||
- 新出现的这条是**全新的记录**:以前的报名、成绩与积分不会回来,需要重新录;
|
||||
- 不想他再出现,就让各单位不要把这个人填进报名表;确实不该有的,再「彻底删除」一次即可。
|
||||
|
||||
**Q59:报名表的 status 能填中文吗?**
|
||||
|
||||
能。`status` 列**大小写不敏感**(`DNS`、`Registered`、`registered` 都认),也认这些中文别名:
|
||||
|
||||
- `正常` / `正常参赛` / `参赛` → 正常参赛;
|
||||
- `退赛` / `弃赛` / `请假` → 退赛;
|
||||
- `取消资格` / `犯规` → 取消资格;
|
||||
- `未出场` / `未到` / `缺席` → 未出场。
|
||||
|
||||
留空就是「正常参赛」。这四个是**报名**状态,和「成绩录入」里每个成绩的状态(有效 / DNS / DQ / DNF / 退赛,见 Q11)是两回事。逐列说明见 [报名名单导入规范](./报名名单导入规范.md)。
|
||||
|
||||
**Q60:为什么导入报 status「xxx」无法识别?**
|
||||
|
||||
说明那一行的 `status` 填了系统不认的词(例如「已报到」「未参赛」)。这一行会被跳过并给出中文提示,其余行照常导入:
|
||||
|
||||
> 第 12 行:status「已报到」无法识别,只能填 registered / scratched / dq / dns(或留空)
|
||||
|
||||
改法:换成四个标准词之一(`registered` / `scratched` / `dq` / `dns`,大小写都行)或 Q59 里的中文别名,也可以直接留空(= 正常参赛),改完重新上传即可。对照表见 [报名名单导入规范 · 常见报错怎么办](./报名名单导入规范.md#六常见报错怎么办)。
|
||||
+17
-11
@@ -30,7 +30,7 @@
|
||||
| `age` | 可选 | 年龄,0–120 的整数 | `26` |
|
||||
| `bib` | 可选 | 号码布 | `101` |
|
||||
| `seed` | 可选 | 道次 / 种子,随便写或留空 | `种子1` |
|
||||
| `status` | 可选 | 报名状态,只能填 4 个英文小写词之一(见下) | `registered` |
|
||||
| `status` | 可选 | 报名状态:4 个英文词(大小写都行)或等价的中文别名(见下) | `registered` |
|
||||
| `member_names` | 可选 | 团体项目的队员名单,多人用 `/` 隔开 | `张三/李四/王五` |
|
||||
|
||||
> 「必须」指的是**这一列的表头要有**。至于每格里能不能留空,看下面第三节逐列的说明。
|
||||
@@ -74,17 +74,21 @@
|
||||
### `seed` 道次 / 种子
|
||||
自由填写,可以留空。系统只做记录,不参与算分、不影响名次。
|
||||
|
||||
### `status` 报名状态 —— 只能写这 4 个英文词
|
||||
**必须小写,不能用中文,也不能大写**:
|
||||
### `status` 报名状态 —— 英文词或中文别名都认
|
||||
**大小写不敏感**(`registered`、`Registered`、`DNS` 都认),也可以直接写中文:
|
||||
|
||||
| 写法 | 含义 |
|
||||
|---|---|
|
||||
| `registered` | 正常参赛 |
|
||||
| `scratched` | 退赛 / 弃赛 |
|
||||
| `dq` | 取消资格 |
|
||||
| `dns` | 未出场 |
|
||||
| 英文写法 | 等价的中文别名 | 含义 |
|
||||
|---|---|---|
|
||||
| `registered` | `正常` / `正常参赛` / `参赛` | 正常参赛 |
|
||||
| `scratched` | `退赛` / `弃赛` / `请假` | 退赛 / 弃赛 |
|
||||
| `dq` | `取消资格` / `犯规` | 取消资格 |
|
||||
| `dns` | `未出场` / `未到` / `缺席` | 未出场 |
|
||||
|
||||
留空 = `registered`(正常参赛)。**填了别的词(包括 `DNS` 这种大写、或「退赛」中文)这一行会被跳过**,所以表里尽量留空,特殊情况再填。
|
||||
留空 = `registered`(正常参赛),拿不准就留空,特殊情况再填。
|
||||
|
||||
真正**认不出**的写法(例如「已报到」「未参赛」):这一行会被跳过,并给出中文行级提示,其余行照常导入。
|
||||
|
||||
> 第 12 行:status「已报到」无法识别,只能填 registered / scratched / dq / dns(或留空)
|
||||
|
||||
### `member_names` 队员名单
|
||||
团体项目用这一列写队员,多人之间用 `/`、`,` 或 `,` 分开:
|
||||
@@ -141,7 +145,7 @@
|
||||
- [ ] `category` 与系统里的组别名一字不差
|
||||
- [ ] 个人行都有姓名,且都有证件号或号码布
|
||||
- [ ] 一份表里没有重复的证件号、没有重复的号码布
|
||||
- [ ] `status` 只用了那 4 个英文小写词或留空
|
||||
- [ ] `status` 只用那 4 个英文词(大小写都行)或第三节列的中文别名,不写别的词;拿不准就留空
|
||||
- [ ] 全表没有因为"怕麻烦"把某些列删掉——**表头 8 个必须列一个都不能少**(哪怕整列是空的)
|
||||
|
||||
---
|
||||
@@ -159,6 +163,7 @@
|
||||
| 第 N 行:小项 XXX 没有组别 | 该小项一个组别都没配 | 先在「组别」里配好,再导入 |
|
||||
| 第 N 行:填写了 athlete_name 就必须填 id_card 或 bib | 个人行缺两项唯一标识 | 补证件号或号码布;确实都没有的,请先在「运动员」里登记 |
|
||||
| 第 N 行:证件号 / 号码布 … 在报名表内重复出现 | 同一份表里同一个人出现了两次 | 删掉重复行(同一个人报多个项目时,`event_code` 必须不同) |
|
||||
| 第 N 行:status「xxx」无法识别 | `status` 填了系统不认的词(4 个标准词以外的英文,或第三节没列的中文) | 改成 `registered` / `scratched` / `dq` / `dns`(大小写都行)或第三节列的中文别名,也可以留空(= 正常参赛);改完重新上传 |
|
||||
| 提示「冲突」,人员没有写入 | 这个人在系统里已有记录,但姓名 / 性别 / 年龄 / 单位 / 号码布跟表里**对不上** | 在导入结果里逐条选「保留已有数据」或「使用新数据」,选完再提交 |
|
||||
| 文件传不上去 | 超过 16MB | 拆分上传,或改用 xlsx |
|
||||
| 只导入了第一张表 | xlsx 只读第一个工作表 | 把要导入的数据放在第一个工作表里 |
|
||||
@@ -174,6 +179,7 @@
|
||||
2. **重复上传同一份表是安全的**,不会把名单变成两份。改完再传一遍就行。
|
||||
- ⚠️ 但要注意「更新」是**整条覆盖**:表里空着的格会把系统里原来的值清掉(队员名单、道次、号码布都会被清空),`status` 空着会被重置成「正常参赛」。如果之前手工调整过某些人的状态,**重传前请在表里把 `status` 写清楚**。
|
||||
3. 名单导入后,到「成绩录入」里录成绩、发布,积分榜就会自动更新。
|
||||
4. **被「彻底删除」的人,导入时会以新人员建档**:管理员彻底删除某个人时,他的档案连同他名下的报名与成绩会一起从库里删掉;之后表里再出现同一个证件号或号码布,系统匹配不到旧档案,会把他当作**新人员**重新建档——名单里多出一条「以前删过的人」通常就是这么来的。新档案是全新的,他以前的报名、成绩与积分不会回来,需要重新录。
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -39,6 +39,8 @@ deploy\build.bat
|
||||
> 文件名中的 `0.1.0` 来自 `console\package.json` 的版本号,会随版本升级变化;以 `dist\console\` 下的实际文件名为准。
|
||||
>
|
||||
> 目标机器**不需要** Go / Node / pnpm,也不联网;上述工具只用于构建机。
|
||||
>
|
||||
> 安装包与免安装包解出来的根目录里,除程序与配置模板外还平铺着两份用户文档 `使用说明.txt`、`报名名单导入规范.txt`(由构建脚本从 `docs\` 暂存,见 3.3)。
|
||||
|
||||
---
|
||||
|
||||
@@ -78,9 +80,13 @@ deploy\build.bat
|
||||
├── config.json # Console 配置模板(首次启动复制到用户配置目录)
|
||||
├── config.yaml # 服务端配置模板(同上)
|
||||
├── rules\ # 规则包模板(同上)
|
||||
├── 使用说明.txt # 用户手册,记事本直接打开
|
||||
├── 报名名单导入规范.txt # 报名表填写规范,可直接转发给各单位填表人
|
||||
└── logs\console.log # 首次运行生成:运行日志
|
||||
```
|
||||
|
||||
> 根目录里那两份 `.txt` 与 `scoreboard.exe`、`config.yaml`、`config.json`、`scoreboard.png`、`rules\` 平铺在同一层,是构建时从 `docs\` 暂存进包的用户文档:`使用说明.txt` 即使用手册,`报名名单导入规范.txt` 可直接发给填表人(两者都按纯文本存放,用记事本打开即可,中文不会乱码)。改动了仓库里的 `docs\` 文档后需要**重新打包**才会更新到包内。
|
||||
|
||||
配置、规则与数据**都不在安装目录里**,各是独立的一处(详见 3.4、3.5):
|
||||
|
||||
```
|
||||
|
||||
Reference in new issue
Block a user