fix: P0 计分根因 + 奖牌结算/奖牌通道 + 身份口径改回证件号 + 19 条 P1(dev_0.1.8)

## P0:双通道项目重复发布跳分(45→85→收敛)
results.rank 一列同时充当「个人名次输出」「手工名次输入」「榜单数据源」,
团体手工通道把个人名次当团体名次又按团体表发一遍分。
- 新增 channel_ranks(每个计分通道各自持久化名次,发布时全量重建)
  与 channel_manual_ranks(按单位录入的团体手工名次,故意不挂通道外键,
  避免规则包重导时级联删掉录入数据)
- results.rank 语义收窄为「只表示个人名次」,只由 scope=athlete 通道写回;
  团体手工名次的来源改为 TeamRanks 优先、团体报名项兜底,
  个人报名项的名次绝不进团体通道
- writeLedgerTx 内重建 channel_ranks;buildRanked / export.loadRanked /
  realtime.loadRanked 三份同源 SQL 一起改读新表
- 回归:发布两次流水与名次逐字节一致(domain + httpapi 各一条,含变异验证)

## 奖牌结算开关与奖牌通道(P1(5),新功能)
- events.award_medals + 通道 count_to_medals / count_to_team_medals
  (迁移默认 1,升级不改变既有榜单)
- 单位榜入选 = 小项结算奖牌 && 通道发奖牌 && 前三名 &&(团体项目 || 个人奖牌并入单位)
- 个人榜只取个人通道;金牌榜与积分榜同源同数据、按通道过滤独立计算
- 前端:小项「该项启用奖牌结算」、通道「发奖牌/个人奖牌并入单位金牌榜」、
  录入页新增「团体名次」区块(含新接口 GET/PUT .../team-ranks)

## 身份口径改回证件号(P1(15),推翻第三十六轮)
- 匹配顺序恢复 证件号 → 号码布 → 姓名+单位;新增 athleteByIDCard
- 同表重复证件号 = 同一人报多个组别(notices 提示,不报错);
  只有「同证件号 + 同小项同组别」才是真重复(conflicts[].duplicate)
- 补齐后端缺失但前端/文档已在依赖的三处契约

## 其余 P1
- 安全:会话撤销断开 ws、实时层按角色裁剪、整库快照限流(含 hello 路径,
  被限流的请求挂起并由心跳兜底补发,不丢刷新)
- 错误分级:手填名次非正数 / gender / 组别年龄 / 导出不存在的小项与单位 /
  积分模板 awardRanks → 400 或 404,不再 500
- 算分一致性:破纪录加分看得失状态;批量退赛·恢复·移出、作废成绩、
  报名导入改状态一律无条件重算推榜(不受延迟结算约束,与实时模式逐字节等价)
- 配置改动触发重算:通道 / 小项参数 / 积分模板
- 升级自愈:channel_ranks 空而已有已发布成绩时,启动时一次性全量重算
  (服务对外监听之前完成,避免升级后奖牌榜全 0)
- 示例数据模式下破坏性操作被阻断,不再假成功
- Console:修复「只剩一块屏」后屏幕监听器被永久摘掉
- 大屏模板引擎:嵌套深度与体积安全阀,任何输入都不抛异常

## 文档
- docs/:使用手册(奖牌开关、奖牌通道、团体名次、枚举列留空口径)、
  常见问题(奖牌排查、升级后奖牌榜为 0、历史重放已知限制)、
  部署指南、上线检查清单
- 版本 dev_0.1.7 → dev_0.1.8(console/package.json 同步)

自检:服务端 13 包 ×2 全绿;前端 vue-tsc + 449 例 ×2 + pnpm build;
Console 35 例 + 语法检查。
This commit is contained in:
AskaEth committed 2026-09-11 21:47:07 +08:00
1 parent 53a0cb225c
commit 45edfbeb71
115 files changed
+10104 -755

No files matched your search

+3 -1
View File
@@ -37,11 +37,13 @@
- [ ] 同页的**大屏配置**:上传大屏会标、选大屏背景图,填大屏标题 / 副标题、轮播间隔与主题色(上传的图片随赛事项目包一起导出/导入)
- [ ] 同页的**字体**:确认**标题字体**与**正文字体**已选好(默认、四款内置字体,或自己上传的字体);选完点「保存」,并核对大屏上标题与正文显示正常。上传的字体存在赛事项目的 `uploads\fonts\` 里,**导出赛事项目包会一并带走、导入后不用重新上传**(见使用手册 14.3、部署指南 8.5)
- [ ] **登录有效期按赛程设好**:到「系统设置 → 登录有效期」把有效期设成覆盖本次比赛全部时段的时长(默认 **24 小时**、可调 **1–720** 小时,跨天比赛建议 **72 小时**),并核对页面顶部「当前会话将于 … 过期」;比赛期间操作员长时间不操作也不会掉线,但它不是「永不掉线」(见使用手册 14.4、常见问题 Q89)
- [ ] **收表口径已交代**:提醒各单位报名名单里的**号码布**是系统认人的唯一标识、不能重号(重号行会被跳过);证件号可选、但也不能与别人重号(见报名名单导入规范)
- [ ] **收表口径已交代**:提醒各单位报名名单里的**证件号**是系统认人的第一依据(有就优先填、填准,一人一号);没有身份证的人用**号码布**顶替,同一个号码布不能给两个人(重号行会被跳过);同一个人报多个组别时号码布可以重复(见报名名单导入规范)
- [ ] **赛事项目确认 / 导入**:到「导出 → 赛事项目包」核对**赛事项目列表**里带「当前」徽标的是本次要用的赛事;需要换赛事时先「导入 .zip」,再点「切换为当前赛事」(服务端会重启一次,页面显示「正在重启服务端…」,恢复后自动刷新)。账号与会话在数据目录的 `system.db` 里,**不受切换影响**,一般不用重新登录。这一步做完再往下走,否则后面看到的是别的赛事的数据
- [ ] **导入规则包**:`%LOCALAPPDATA%\ScoreboardConsole\rules\2026-驭电利刃杯军事运动会.yaml`,走「导出 → 规则包 → 选择 YAML → 预览差异 → 确认导入并全量重算」(规则目录在用户数据目录里,见部署指南 3.5)
—— 服务端不会自动加载规则包,必须导入一次
- [ ] 检查计分模板:个人前六名 `10/8/6/3/2/1`、团体 `15/10/8/4/2/1`、最后一名不得分
- [ ] **按赛事规则逐项核对过「奖牌结算开关」与「奖牌通道」**:到「基础数据 → 大项 / 小项」逐个确认要发牌的小项都勾着 **「该项启用奖牌结算」**(不该发牌的项目取消勾选);再到「基础数据 → 计分通道」逐项核对每条通道的 **「发奖牌」** 与(个人名次通道的)**「个人奖牌并入单位金牌榜」** 是否符合本场赛会规则。关掉的通道在「大项 / 小项」页的通道摘要里会标出 `不发奖牌` / `个人奖牌不并入单位榜`(见使用手册 10.2、10.4;查不出原因时按常见问题 Q94 逐条排除)
- [ ] **升级 / 首次启动后确认奖牌榜数字与上一场一致(不是全 0)**:本版新增迁移 0020,迁移只建表不回填,服务端会在下一次启动时自动全量重算补齐名次——「运行日志」里出现 `检测到通道名次为空但已有已发布成绩,正在执行一次性全量重算` 与 `一次性全量重算完成,通道名次与奖牌榜已补齐` 是正常的,不是报错;等它跑完后刷新「积分榜 → 团体奖牌榜」,与升级前的数字(或备份里的导出件)对一遍,**不能是全 0**(见部署指南 3.4、常见问题 Q96)
- [ ] 「只排名不计分」的项目(飞行人员战斗体能)导入后应显示为不计分
- [ ] 「基础数据 → 参赛单位」里各单位的 logo 都已上传(会显示在总积分榜、团体奖牌榜、分项成绩表与个人积分榜上)
- [ ] 同页核对**单位名单齐全、没有误删**:被「彻底删除」的单位不会出现在这个列表里(它的报名、成绩与积分仍在库里,积分榜照常显示它);发现少了就用它的编码导入一次报名表,它会重新出现(详见使用手册 10.1、常见问题 Q61–Q64)
+81 -20
View File
@@ -196,10 +196,33 @@
| **批量恢复** | 把选中的退赛者改回「正常参赛」 | —— |
| **批量移出报名** | 把选中的报名项**物理删除**,连同他的成绩与积分流水一起删掉 | **不可以**,需二次确认 |
- **批量退赛 / 恢复**会按新名次重算积分并推到大屏(若开了延迟结算,同样等该组录完才结算,见 4.6、10.5)。已经是「取消资格(dq)」「未出场(dns)」的行会被**跳过、不覆盖原判定**(跳过的人会在确认框里逐条列出原因,例如「已被判罚取消资格(dq),跳过」)。
- **批量移出报名**的确认框会列出**将被删除的人**(姓名|号码布|单位,超过 20 人只列前 20 并报剩余数量)以及**将重算的小项与组别**——看完再确认,删了不能恢复。
- **批量退赛 / 恢复**会**立即**按新名次重算积分并推到大屏——**延迟结算(见 10.5)也照算**,因为退赛 / 恢复改的是「谁还算数」,不是「录了多少」,名次和分数必须当场跟着改。已经是「取消资格(dq)」「未出场(dns)」的行会被**跳过、不覆盖原判定**(跳过的人会在确认框里逐条列出原因,例如「已被判罚取消资格(dq),跳过」)。
- **批量移出报名**的确认框会列出**将被删除的人**(姓名|号码布|单位,超过 20 人只列前 20 并报剩余数量)以及**将重算的小项与组别**——看完再确认,删了不能恢复;删除后同样**立即重算并推榜**,不受延迟结算影响。
- 一次最多处理 **500 条**报名项,超出请分批提交;有未保存的成绩修改时,请先「存草稿」再批量操作;示例数据模式下不能批量操作。
### 4.9 团体名次(按单位录入)
有些项目要按**单位**排团体名次(例如「团体引体向上」),但场上并没有一条"单位自己的成绩"可填——名次是裁判直接给定的。这类项目在录入页会多出一块 **「团体名次」** 卡片。
**什么时候会出现**:只有该组别配了「**团体名次 + 手动名次**」这两项都符合的计分通道时才会出现(通道在「基础数据 → 计分通道」配,见 10.4)。没配这样通道的小项,录入页**不显示**这块卡片——这是正常的,说明它的团体名次另有来源(例如篮球这类纯团体项目,走的是团体报名行上的名次,仍在成绩列表里录)。
**怎么填**:
1. 卡片里按**单位**一行一个输入框(单位清单取「基础数据 → 参赛单位」里启用中的单位,已「彻底删除」的单位不出现);
2. 在单位后面填名次(从 1 开始的正整数);**留空 = 清空该单位的名次**(不需要先填一个 0);
3. 填完点 **「保存团体名次」**;没有改动时按钮是灰的,改了才亮,卡片右上角会显示「未保存」。
**保存后会发生什么**:系统按新名次重算**该组别名次与积分**,并刷新积分榜与大屏(这一步与《个人名次》无关——**个人名次仍然在成绩列表里录**,团体名次只喂给团体通道)。保存完成后会提示「团体名次已保存 · 该组名次与积分榜会按新名次重算」。
**要注意的**:
- **名次重复允许并列**(服务端按积分模板的并列口径处理),但输入框会描红并提示 `名次 N 重复 X 次,允许并列,请确认是否为想要的结果`——确认无误可以照常保存;
- **名次超出参赛单位数**同样会提示(多半是笔误),但**不挡保存**:改不改由你决定;
- **个人名次不受影响**:这块卡片改的是单位,成绩表里每个人的名次、分数一行都不动;
- **中途离开会提醒**:有未保存的团体名次时,切走会有确认框(和未保存的成绩一样);
- **权限**:读得到成绩的人都能看到这块卡片(访客只读,输入框置灰并写明原因);**能保存的是录入员及以上**(与成绩录入同权限)。示例数据模式下不能保存;
- 团体名次是**独立保存**的:点「保存团体名次」只提交这块卡片,不会顺手发布成绩;成绩仍然要另外「发布」。
---
## 5. 成绩审核
@@ -395,10 +418,24 @@
### 10.2 大项 / 小项
1. 左侧选择或新增大项(编码、名称、简称、默认积分模板、排序);
2. 右侧维护该大项下的小项:点「新增小项」,填写编码、名称、类型(个人 / 团体 / 对抗 / 比赛 / 个人+团体)、录入方式(自动排名 / 手动名次)、成绩类型(时间 / 距离 / 计数 / 得分 / 无成绩)、比较方式(越小越好 / 越大越好 / 不比较)、状态、是否计分等;
2. 右侧维护该大项下的小项:点「新增小项」,填写编码、名称、类型(个人 / 团体 / 对抗 / 比赛 / 个人+团体)、录入方式(自动排名 / 手动名次)、成绩类型(时间 / 距离 / 计数 / 得分 / 无成绩)、比较方式(越小越好 / 越大越好 / 不比较)、状态、是否计分、**是否结算奖牌**等;
3. 小项行上的「配置组别」「配置计分通道」可直接跳到对应分区;
4. 删除大项 / 小项会二次确认。
**「该项启用奖牌结算」开关**(新增)
小项表单下方的「选项」里,"是否计分"旁边有一个 **「该项启用奖牌结算」** 勾选框,**默认勾上**。
- **勾上(默认)**:这个小项按名次发奖牌——第 1 名金、第 2 名银、第 3 名铜,和以前一样;
- **取消勾选**:这个小项的**名次与积分照常计算、照常上屏**,但**一块奖牌都不发**——金牌榜(团体奖牌榜)与个人积分榜的奖牌列里都不再出现它。
什么时候该关掉它?**"算分但不发牌"的项目**——例如赛会规则只记名次分、不设金银铜的项目,或者现场临时决定不发牌、但分数仍要计入单位总分的项目。
> 注意别和「计分」搞混:**取消勾选「计分」**的项目(只排名不计分)本来就不发奖牌,那种情况不用动这里;**「该项启用奖牌结算」管的是"计分的项目里哪些要发牌"**。
>
> 它保存后立即生效:系统会马上重算该小项,金牌榜随之更新。想恢复发牌,把勾重新勾上保存即可。
> 这是"小项级"的总闸;某个小项里**单独某条计分通道**不发牌,另有开关,见 10.4。
**「个人+团体」是什么**
用于团体与个人赛事合并的项目:同一条成绩会同时按个人通道与团体通道记分(具体通道见 10.4「计分通道」)。
@@ -438,7 +475,24 @@
3. 点「保存全部」整体替换该小项的通道配置;
4. 标记为「不计分」的小项,通道可以保存但不参与积分计算;
5. 「名次来源」选「按队内平均」时,把同一个单位(或个人)在该组别的成绩**取平均**后排名,并列按积分模板的并列口径处理(默认顺延);平均值分母取录入页选的「平均值口径」——`只算有效成绩`时是本单位有有效成绩的条数(一个人都没有效成绩的单位不参与团体排名、不得分),`全部报名人员都计入`时是本单位在该组别的报名条数(没成绩的按 0 计入)。报名表里 `status` 不是 `registered` 的报名项(弃赛 / 取消)既不算参与,也不进分母;
6. 每条通道有一个「计入单位总分」开关,默认打开。关掉后该通道的分只记在个人头上,不进单位总分——「个人+团体」项目的个人通道就靠它做到只记个人。
6. 每条通道有一个「计入单位总分」开关,默认打开。关掉后该通道的分只记在个人头上,不进单位总分——「个人+团体」项目的个人通道就靠它做到只记个人;
7. 每条通道还有一个**「奖牌通道」**列,里面是两个开关(都默认打开):
| 开关 | 默认 | 关掉之后 |
| --- | --- | --- |
| **发奖牌** | 打开(该通道的名次发奖牌) | 这条通道算出来的名次**只出积分、不发奖牌**:名次与分数照旧,金牌榜与个人榜里不再为它记牌 |
| **个人奖牌并入单位金牌榜** | 打开 | 只对「名次范围 = 个人名次」的行显示。关掉后这条通道的个人奖牌**仍然进个人积分榜的奖牌列**,但**不计入单位的金牌榜**(团体奖牌榜 / 单位总分榜的金银铜) |
怎么用:
- **什么该关「发奖牌」**:一条通道只用来给分、名次不该算奖牌时——例如个人通道的分要记、但这批名次不是赛会正式名次;
- **什么该关「个人奖牌并入单位金牌榜」**:某个个人项目**不按单位计牌**时(单位金牌榜只统计团体项目的牌子、或该项目被判定为个人项目不计入单位成绩);
- 「名次范围 = 团体名次」的行**不显示**第二个开关:团体名次本来就是记在单位头上的,不存在「个人奖牌并入单位」这回事;
- 两个开关**都在「保存全部」之后生效**,保存后系统会重算该小项并更新榜单;
- 这些开关只决定**发不发牌、算不算单位榜**,**不改变积分**(积分由「计入单位总分」与积分模板决定,见第 6 条)。
> 三个层次一起决定一枚奖牌:**小项的「该项启用奖牌结算」(见 10.2)→ 通道的「发奖牌」→ 名次在前三**。三者都满足才有奖牌;「计入单位金牌榜」再决定这枚牌算不算到单位头上。
> 想知道某个小项到底发不发牌:在「大项 / 小项」页选中它,页面下方「当前小项的计分通道」摘要里,关掉的开关会直接标出 **`不发奖牌`** 与 **`个人奖牌不并入单位榜`**。
### 10.5 积分模板
@@ -457,7 +511,7 @@
### 10.6 运动员
1. 点「新增运动员」,填写姓名 *、性别、年龄、所属单位 *、工号 / 学号、证件号、号码布等(年龄可留空,填了必须是 0–120 的整数);
2. **号码布是单人的唯一标识**,同名同姓的人靠它区分,两个人的号码布不能重复;**证件号(如身份证号)是可选的档案信息**,报名导入**不按证件号认人**,但系统里**一个证件号也只能属于一个人**,与别人重复同样会被拒绝。没有身份证信息的人只填号码布就行;两项都不填也能保存档案,但这样的人员**不能在「报名导入 → 个人报名」里勾选**(系统认不出是谁)。已有历史数据两项可以都为空;
2. **证件号(如身份证号)是单人的唯一标识**,同名同姓的人靠它区分,两个人的证件号不能重复;**没有身份证信息的人只填号码布**,此时号码布顶替证件号认人(报名导入会先按证件号认人,没有证件号或库里那条证件号为空时再按号码布认人),两个人的号码布同样不能重复。两项都不填也能保存档案,但这样的人员**不能在「报名导入 → 个人报名」里勾选**(系统认不出是谁)。已有历史数据两项可以都为空;
3. 每行有三个动作:**编辑**、**停用**(停用后按钮变成「启用」)、**彻底删除**;
4. 个人项目的报名项会关联到运动员,团体项目可以留空;
5. **多选与批量操作**:列表每行有勾选框,表头是「全选当前筛选结果」(只勾当前筛出来的人)。选中后顶部出现「已选 N 人」与 **批量停用** / **批量彻底删除** 两个按钮,整批只提交一个请求,不用一个个点;**批量彻底删除**会先预览将删掉谁、重算哪些小项,确认后才执行,规则与单个「彻底删除」完全一致(见下)。
@@ -515,41 +569,47 @@
1. 点「下载 CSV 模板」获取表头样例;
2. 表头共 12 列:`event_code`、`category`、`team_code`、`athlete_name`、`id_card`、`gender`、`age`、`bib`、`seed`、`heat`、`status`、`member_names`(大小写不敏感)。其中 `id_card`(证件号)、`gender`(性别)、`age`(年龄)、`heat`(批次)为可选列,缺失不影响导入,其余列必须包含;
3. **只要有姓名的行,`id_card` 与 `bib` 必须至少填一个**,否则该行报错并跳过;`gender` 只认「男」「女」,其他值忽略;`age` 可留空,填了必须是 0–120 的整数;**同一份文件里同一个号码布重复出现会报错并跳过**(号码布是唯一标识);同一个证件号重复出现**不再报错**,但证件号撞上系统里**另一个人**时会报「证件号 X 已被另一个人占用(姓名 Y,号码布 Z)」并跳过该行;
4. **`status` 列很宽容**:大小写不敏感(`DNS`、`Registered`、`registered` 都认),也认中文别名——
3. **只要有姓名的行,`id_card` 与 `bib` 必须至少填一个**,否则该行报错并跳过;`gender` 只认「男」「女」,其他值忽略;`age` 可留空,填了必须是 0–120 的整数;**证件号是系统认人的第一依据**,同一个证件号在同一份文件里重复出现**不报错**(同一个人报多个组别时会重复,导入结果里会给一条「证件号 XXXX 在本表中出现 N 次(同一人报名多个组别)」提示);同一小项同一个组别里出现两次同样的证件号才按**真重复**进冲突列表;**同一个号码布给了两个不同的人会报错并跳过**(同一个人报多个组别时号码布可以重复);
4. 人员匹配顺序(**证件号是单人的唯一标识**):
1. 先按 `id_card`(证件号)匹配:命中即认作同一人;姓名 / 性别 / 年龄 / 单位 / 号码布与他的档案对不上时进「冲突」列表,等你逐条决定(见下);
2. 证件号为空、或库里那条还没登记证件号,再按 `bib`(号码布)匹配:命中即认作同一人,差异同样进「冲突」列表;
3. 证件号与号码布都没找到,再按「姓名 + 单位」找:
- 恰好一人,两边给的证件号(或号码布)对得上或有一边没填 → 认作同一人,表里给的证件号 / 号码布 / 年龄会**回填**进他的档案(不算冲突),重传不带证件号的名单不会把每个人复制一份;
- 恰好一人,但他已有**另一个**证件号(或号码布)且与表里不同 → 按「**同名的另一个人**」新建档案,并在导入结果里单独列出(姓名 / 单位 / 原证件号或号码布 / 新证件号或号码布)提醒核对,**不算错误、不拦截**;
- 多人 → 分不清是谁,进「冲突」列表;
4. 都没匹配到则新建人员(姓名、性别、年龄、单位、证件号、号码布)——被「彻底删除」的人(见 10.6)档案已经不在库里,匹配不到他,再次导入会当作**新人员**重新建档,他以前的报名与成绩不会回来;
5. **一个证件号只能属于一个人**:表里给的证件号若已是别人的,这一行会按证件号认到**那个人**,姓名 / 单位等对不上就进冲突列表让你决定;确实无法认到(例如同时又给了别人的号码布)时会报「证件号 X 已被另一个人占用(姓名 Y,号码布 Z)」并跳过,不会把证件号抢过来;
5. **`status` 列很宽容**:大小写不敏感(`DNS`、`Registered`、`registered` 都认),也认中文别名——
- `正常` / `正常参赛` / `参赛` → 正常参赛;
- `退赛` / `弃赛` / `请假` → 退赛;
- `取消资格` / `犯规` → 取消资格;
- `未出场` / `未到` / `缺席` → 未出场。
留空即「正常参赛」。真正认不出的写法会给出中文行级错误、该行跳过,例如「第 12 行:status「已报到」无法识别,只能填 registered / scratched / dq / dns(或留空)」;
5. 人员匹配顺序(**号码布是单人的唯一标识,证件号不参与认人**,只作为档案信息写入 / 更新):
1. 先按 `bib`(号码布)匹配:命中即认作同一人;姓名 / 性别 / 年龄 / 单位 / 号码布与他的档案对不上时进「冲突」列表,等你逐条决定(见下);
2. 号码布为空、或按号码布没找到,再按「姓名 + 单位」找:
- 恰好一人、且他还没有号码布 → 认作同一人,表里给的号码布 / 证件号 / 年龄会**回填**进他的档案(不算冲突);
- 恰好一人、且他已有号码布 → 分两种:表里**没给号码布**(或与他相同)时**仍判同一人**(重传不带号码布的名单不会把每个人复制一份);表里**给了号码布且与他不同**时才按「**同名的另一个人**」新建档案,并在导入结果里单独列出(姓名 / 单位 / 原号码布 / 新号码布)提醒核对,**不算错误、不拦截**;
- 多人 → 分不清是谁,进「冲突」列表;
3. 都没匹配到则新建人员(姓名、性别、年龄、单位、证件号、号码布)——被「彻底删除」的人(见 10.6)档案已经不在库里,匹配不到他,再次导入会当作**新人员**重新建档,他以前的报名与成绩不会回来;
4. 证件号不参与认人,但**一个证件号只能属于一个人**:表里给的证件号若已被别人占用,该行会报「证件号 X 已被另一个人占用(姓名 Y,号码布 Z)」并跳过,不会把证件号抢过来;
6. `bib` 列会同时写入人员档案与报名记录;从已有名单勾选生成的报名也会带上人员的证件号与号码布;
7. 把 `.csv` 或 `.xlsx` 拖入虚线框,或点击选择文件(单个文件不超过 16MB;xlsx 只解析第一个工作表);
- **CSV 编码不用管**:UTF-8、带 BOM 的 UTF-8(Excel 的「CSV UTF-8」)、GBK / GB18030(中文 Windows 上 Excel「另存为 CSV」的默认编码)、UTF-16 都能直接导入,中文不会乱码,服务端会自动识别;
8. 点「开始导入」,页面显示**新增 / 更新 / 跳过**数量;匹配不到的行会跳过并回显行号,修正后可重新上传。
> **导入会同步重算受影响的小项与组别**:报名名单改的是「谁还算数」(新建报名、或把正常参赛改成退赛 / 取消资格 / 未出场),所以导入完成后系统会按新名单重算这些组别的名次与积分,并刷新榜单与大屏——**不受「分批发布时实时更新榜单」这个延迟结算开关影响**(同 4.8 的批量退赛)。「只改了姓名 / 号码布 / 批次」这类不影响算分的改动不会白算一遍。
**人员信息冲突的处理**
导入时如果按号码布(或「姓名 + 单位」唯一命中)找到的人在系统里已有记录,但表里的姓名、性别、年龄、单位或号码布与他的档案不一致,这个人会被列为**冲突**,本次不写入(该人的报名也不会创建)。处理办法:
导入时如果按证件号(或号码布、「姓名 + 单位」唯一命中)找到的人在系统里已有记录,但表里的姓名、证件号、性别、年龄、单位或号码布与他的档案不一致,这个人会被列为**冲突**,本次不写入(该人的报名也不会创建)。处理办法:
1. 导入结果里会单独列出冲突人员,每条显示已有数据、新数据,以及不一致的字段(含年龄与号码布);
1. 导入结果里会单独列出冲突人员,每条显示已有数据、新数据,以及不一致的字段(含证件号、年龄与号码布);
2. 用左侧复选框选中一条或多条(也可以全选),再点「保留已有数据」或「使用新数据」:
- **保留已有数据**:人员字段沿用系统里已有的,按这个人的信息建 / 更新报名;
- **使用新数据**:用表里的姓名、性别、年龄、单位、号码布等更新该人员,再建 / 更新报名;
- **使用新数据**:用表里的姓名、证件号、性别、年龄、单位、号码布等更新该人员,再建 / 更新报名;
3. **没有做决定的冲突不会被写入**,可以稍后再处理;全部处理完后冲突列表清空。
- 有一种冲突卡片底部写着**「本表内重复行」**:同一证件号 + 同一个小项同一个组别在表里出现了两次。这种卡片上可能一个字段都没高亮,是正常的——两条本来就可能一模一样。**保留已有** = 已经导入的那条报名保持不动,**使用新数据** = 用这一行的值覆盖它。
> 「从已有名单勾选」走的是同一个导入通道,人员匹配与冲突处理规则完全一致。
**「同名的另一个人」提醒(不是冲突)**
如果表里某人的号码布与库里「同名 + 同单位」的人不同,系统按**同名的另一个人**给他**新建档案**,并在导入结果里单独列出一块:`以下 N 人按同名的另一个人新建了档案(号码布不同)`,逐条显示 `姓名(单位):原有号码布 XXX → 新号码布 XXX`。这些行**已经导入成功、不会拦截**,只是提醒你核对号码布有没有写错;若确认是本人写错了号,到「基础数据 → 运动员」把档案里的号码布改回来、并删掉多出来的那条档案即可。
如果表里某人的证件号(或号码布)与库里「同名 + 同单位」的人不同,系统按**同名的另一个人**给他**新建档案**,并在导入结果里单独列出一块:`以下 N 人按同名的另一个人新建了档案(证件号 / 号码布不同)`,逐条显示 `姓名(单位):证件号 XXX → XXX;号码布 XXX → XXX`。这些行**已经导入成功、不会拦截**,只是提醒你核对证件号与号码布有没有写错;若确认是本人写错了号,到「基础数据 → 运动员」把档案里的号改回来、并删掉多出来的那条档案即可。
同一证件号在本表里出现多次时,导入结果里还会给一条 `证件号 XXXX 在本表中出现 N 次(同一人报名多个组别)` 的提示——这是**正常情况**,只提醒你别把不同的人写成同一个证件号。
种子等字段无法在勾选界面填写,仍需通过表格导入;号码布取自人员档案,勾选时会自动写入报名。团体报名登记的队员名单只存姓名,不会带动运动员档案。
@@ -631,8 +691,9 @@
- **按编码匹配**:单位 / 大项按编码,小项按编码,组别按「小项编码 + 组别名」;**存在就更新、不存在就新建**;
- **绝不删除**:文件里没有的行(表里没有、或整张工作表没放)**不会被删掉**,也不会被停用;
- **列不在表里 = 不动该字段**(**布尔列也一样**——把整列「启用」删掉再导回,**不会**把所有停用的单位/大项改成启用);**列在表里但格子留空 = 按该列的默认口径处理**:简称 / 颜色 / 场地 / 备注等文本列与年龄上下限会**清空**,权重留空按 1、启用 / 计分 / 计破纪录等布尔列留空按「是」,**排序留空则保持原来的值**(**四张表口径一致**,单位 / 大项留空同样不会被改写)。改数据前先想清楚这一点;
- **枚举列是唯一的例外:列在表里但格子留空 = 不改动,不是"取默认值"**。小项的**类型 / 结果模式 / 结果类型 / 比较方式 / 状态 / 平均口径**、组别的**性别**都属于这一类:留空就沿用这一行在系统里原来的值(**只有新建的行**才用默认值,例如新建组别时性别留空 = 不限)。这么定是为了防手滑——表格里误清一格,不会把一个已发布的小项打回「待录入」、也不会把「团体」改成「个人」;
- **表头行可以不在第一行**:从系统导出的包表头在第 4 行(上面是标题与副标题),手工整理的表表头在第 1 行,两种都能识别(识别范围是前 20 行);
- **枚举列要填系统里的英文规范值**(表头是中文,容易踩):类型 `individual` / `team` / `match` / `individual_team`,录入方式 `auto` / `manual`,成绩类型 `time` / `distance` / `count` / `score` / `none`,比较方式 `asc` / `desc` / `none`,小项状态 `pending` / `ongoing` / `finished` / `published`,平均口径 `valid` / `all`;布尔列(启用 / 计分 / 计破纪录)填 **是 / 否**;组别表的「性别」填 **男 / 女**(留空 = 不限);
- **枚举列要填系统里的英文规范值**(表头是中文,容易踩):类型 `individual` / `team` / `match` / `individual_team`,录入方式 `auto` / `manual`,成绩类型 `time` / `distance` / `count` / `score` / `none`,比较方式 `asc` / `desc` / `none`,小项状态 `pending` / `ongoing` / `finished` / `published`,平均口径 `valid` / `all`;布尔列(启用 / 计分 / 计破纪录)填 **是 / 否**;组别表的「性别」填 **男 / 女**(列在表里但格子留空 = 不改动;新建的组别留空 = 不限);
- **最稳的用法**:先「导出基础数据包」,在导出件上直接改,再导回来——表头与取值天然对得上;手工整理的表格请照导出件的表头写;
- 被「彻底删除」的单位不在导出件里;导入**不会**把它翻出来(已有的隐藏记录只更新字段,仍是隐藏状态)。
+59 -11
View File
@@ -240,24 +240,25 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
不能一键撤销。纠错需要重新导入旧规则包,或逐项修正后重新发布。导入前请务必先「预览差异」。
**Q48:报名表里的证件号重复了怎么办?**
先分清两种「重复」,处理方式完全不同:
先分清三种「重复」,处理方式完全不同:
- **同一份表里同一个证件号出现多次**:**不再报错**,照常导入(同一个人报多项时,证件号本来就会重复)。证件号只是**档案信息,不参与认人**。
- **证件号已经登记在系统里另一个人名下**(姓名、号码布都对不上):这一行会报 `第 N 行:证件号 X 已被另一个人占用(姓名 Y,号码布 Z)` 并**跳过该行**。系统里一个证件号只能属于一个人(避免把两个人的身份弄混)。处理办法:先核对证件号是不是抄错了——不是这个人的,把这一格留空即可(只填号码布也能导入);确实是他的,先到「基础数据 → 运动员」把另一条档案里的证件号清掉或改对,再重新上传。
- **同一份表里同一个证件号出现多次**:**不报错**,照常导入——证件号是**人员的唯一标识**,同一个证件号就是同一个人(同一个人报多个组别时本来就会重复)。导入结果里会给一条提示:`证件号 XXXX 在本表中出现 N 次(同一人报名多个组别)`,只是在提醒你别把不同的人写成同一个证件号。
- **同一证件号 + 同一个小项同一个组别**:这才是**真重复**(同一个人在同一组里被写了两遍)。这一行会进「冲突」列表,由你选**保留已有**(已导入的那条报名不动)或**使用新数据**(用这一行覆盖它)。
- **证件号已经登记在系统里另一个人名下**:这一行会**按证件号认到那个人**,姓名 / 单位等对不上就进「冲突」列表让你决定;只有实在认不到(例如同时又给了别人的号码布)时才会报 `第 N 行:证件号 X 已被另一个人占用(姓名 Y,号码布 Z)` 并**跳过该行**。处理办法:先核对证件号是不是抄错了——不是这个人的,把这一格留空即可(只填号码布也能导入);确实是他的,先到「基础数据 → 运动员」把另一条档案里的证件号清掉或改对,再重新上传。
- **在「运动员」里新增 / 编辑时提示证件号重复**:同上,说明该证件号已属于另一个人。是同一个人的话直接用已有记录;证件号填错就改对。已有历史数据可以没有证件号。
详细步骤见 [使用手册 · 报名导入](./使用手册.md#107-报名导入)。
**Q49:人员没有身份证,只有号码布,能报名吗?**
可以,这正是**号码布作为唯一标识**的用法:在「运动员」里只填号码布也能保存;报名表里有姓名的行,`id_card` 与 `bib` 至少填一个就能导入;从已有名单勾选报名时,两项里有一项就能勾选。号码布会同时写入人员档案与报名记录。反过来,证件号只是**可选的档案信息**——只填证件号、没有号码布也能导入,但系统是**按号码布认人**的(号码布为空时按「姓名 + 单位」认),所以能编号码布就编上,重名重姓时才分得清。
可以。证件号是系统认人的**第一依据**,但没有身份证的人只填号码布也能用:号码布此时**顶替证件号认人**。在「运动员」里只填号码布也能保存;报名表里有姓名的行,`id_card` 与 `bib` 至少填一个就能导入;从已有名单勾选报名时,两项里有一项就能勾选。号码布会同时写入人员档案与报名记录。因为没有证件号,认人就全看号码布了——能编上号码布就编上,重名重姓、号码布还必须写成同一个人每次都用的那个号。
**Q50:号码布重复了怎么办?**
号码布是**单人的唯一标识**,系统不允许两个人员共用同一个号码布。
两个人**不能**共用同一个号码布(同一个人报多个组别时可以重复)。
- **在「运动员」里新增 / 编辑时提示重复**:说明该号码布已属于另一个人员。请先核对是不是同一个人:是,就直接用已有记录;不是,请检查号码布是否填错。
- **同一份报名表里号码布重复出现**:重复的行会报错并跳过,改好后重新上传。
- **号码布在系统里已有、但表里这个人跟他对不上**(姓名 / 性别 / 年龄 / 单位不同):会列为「冲突」,本次不写入(报名也不会创建),需要在导入结果里勾选后决定「保留已有数据」还是「使用新数据」。
- **表里某人的号码布与库里「同名 + 同单位」的人不同**:系统按「**同名的另一个人**」给他**新建档案**(不报错),并在导入结果里单独列出 `姓名(单位):原有号码布 XXX → 新号码布 XXX` 提醒核对。多半是号码布写错了:到「基础数据 → 运动员」把档案里的号改回来、删掉多出来的那条档案即可。
- **同一份报名表里,同一个号码布给了两个不同的人**:重复的那一行会报错并跳过,改好后重新上传。(同一个人报多个组别、号码布写成同一个,不报错。)
- **号码布在系统里已有、但表里这个人跟他对不上**(姓名 / 性别 / 年龄 / 单位不同):会列为「冲突」,本次不写入(报名也不会创建),需要在导入结果里勾选后决定「保留已有数据」还是「使用新数据」。表里同时给了**别人的证件号**时,会先按证件号认人,同样是进「冲突」列表。
- **表里某人的证件号(或号码布)与库里「同名 + 同单位」的人不同**:系统按「**同名的另一个人**」给他**新建档案**(不报错),并在导入结果里单独列出 `姓名(单位):证件号 XXX → XXX;号码布 XXX → XXX` 提醒核对。多半是证件号或号码布写错了:到「基础数据 → 运动员」把档案里的号改回来、删掉多出来的那条档案即可。
详细步骤见 [使用手册 · 报名导入](./使用手册.md#107-报名导入)。
@@ -308,7 +309,7 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
**Q58:删掉的人怎么又出现在名单里了?**
彻底删除之后,如果又在报名表里导入同一个人(同一个号码布,或同一「单位 + 姓名」),他会以**全新的档案**重新出现在运动员名单里——因为旧档案已经连同他的报名与成绩一起删掉了,系统按「号码布 → 姓名 + 单位」找不到他(证件号不参与认人),就当作新人员建档。所以名单里突然多出一个「以前删过的人」,通常就是某次导入带回来的。
彻底删除之后,如果又在报名表里导入同一个人(同一个证件号、或同一个号码布、或同一「单位 + 姓名」),他会以**全新的档案**重新出现在运动员名单里——因为旧档案已经连同他的报名与成绩一起删掉了,系统按「证件号 → 号码布 → 姓名 + 单位」都找不到他,就当作新人员建档。所以名单里突然多出一个「以前删过的人」,通常就是某次导入带回来的。
- 新出现的这条是**全新的记录**:以前的报名、成绩与积分不会回来,需要重新录;
- 不想他再出现,就让各单位不要把这个人填进报名表;确实不该有的,再「彻底删除」一次即可。
@@ -530,7 +531,7 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
录入、发布、看榜这些日常操作手机上都能做;赛事配置这类条目较多的操作仍建议在电脑上完成。如果某台手机上仍显示不全,请把**机型、浏览器与屏幕宽度**(或截图)告诉维护人员——目前适配覆盖到 390px 宽的窄屏,桌面端布局不受影响。
**Q86:号码布和证件号,哪个才是系统认人的依据?**
**号码布。** 报名导入时的匹配顺序是「号码布 → 姓名 + 单位」;**证件号不参与认人**,只作为可选的档案信息写入 / 更新。不过系统里**一个证件号仍然只能属于一个人**,撞上别人的证件号会明确报错并指出占用者(见 Q48)。完整匹配规则见[报名名单导入规范](./报名名单导入规范.md)。
**证件号。** 报名导入时的匹配顺序是「证件号 → 号码布 → 姓名 + 单位」:先按证件号认人;证件号为空、或库里的档案还没登记证件号时按号码布认;两者都没命中才按「姓名 + 单位」找,并把表里给的证件号 / 号码布**回填**进档案。系统里**一个证件号只能属于一个人**,撞上别人的证件号会按证件号认到那个人并进「冲突」列表(见 Q48)。号码布不再单独充当唯一标识,但仍然**不能给两个人共用**(同一个人报多个组别可以重复)。完整匹配规则见[报名名单导入规范](./报名名单导入规范.md)。
**Q87:怎么把报名名单导出来?**
到「导出 → 结果导出」页,往下找**「报名名单」**卡片:先按**小项 / 组别 / 单位 / 批次**筛选(都可以留空 = 不筛,即导全部),再点「导出报名名单」,得到 `报名名单.xlsx`。表里有 13 列:小项编码、小项名、组别、单位编码、单位名、姓名、证件号、号码布、批次、性别、年龄、状态(中文:正常参赛 / 已退赛 / 取消资格 / 未出场)、备注;号码布按文本导出,前导零不会丢。访客也能导出(只读)。
@@ -541,7 +542,7 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
- **导出**:一个工作簿四张工作表(单位 / 大项 / 小项 / 组别,组别表带所属小项编码);
- **导入**(**仅管理员**,只认 `.xlsx`):按编码匹配,**存在就更新、不存在就新建,绝不删除**(表里没有的行不会被删、也不会被停用)。先点「预览差异」看「新增 / 更新 / 无变化 / 错误」与逐行变化,确认后再点「**确认写入**」;**有错的行会跳过、合法的行照常写入**,行级错误是中文并带真实 Excel 行号(如 `单位 第 3 行:单位编码必填`)。
要点:**列不在表里 = 不动该字段**(**布尔列也一样**,缺整列 ≠ 取默认值);**列在表里但格子空**:文本列与年龄上下限清空,权重按 1、布尔列(启用 / 计分等)按「是」,**排序留空保持原值**(**四张表口径一致**,单位 / 大项留空同样不会被改写)。表头行在第 4 行(导出件)或第 1 行(手工表)都能识别;枚举列要填英文规范值、布尔列填「是 / 否」。**最稳的做法是从系统导出、改完再导回**。详见使用手册 11.4。
要点:**列不在表里 = 不动该字段**(**布尔列也一样**,缺整列 ≠ 取默认值);**列在表里但格子空**:文本列与年龄上下限清空,权重按 1、布尔列(启用 / 计分等)按「是」,**排序留空保持原值**(**四张表口径一致**,单位 / 大项留空同样不会被改写)。**只有枚举列例外:列在表里但格子空 = 不改动**(小项的类型 / 结果模式 / 结果类型 / 比较 / 状态 / 平均口径、组别的性别),留空就沿用原来的值,只有**新建的行**才用默认值(新建组别时性别留空 = 不限)——这样误清一格不会把已发布小项打回「待录入」、也不会把「团体」改成「个人」。表头行在第 4 行(导出件)或第 1 行(手工表)都能识别;枚举列要填英文规范值、布尔列填「是 / 否」。**最稳的做法是从系统导出、改完再导回**。详见使用手册 11.4。
**Q89:登录会不会用着用着被踢下线?「登录有效期」怎么设?**
默认有效期 **24 小时**,管理员可在「系统设置 → 登录有效期」里改成 **1–720 小时**(最长 30 天);比赛期间建议设成 **72 小时**。会话是**滑动续期**的:只要在有效期内继续操作(页面开着也会定期自动续期),到期时间就往后顺延——**不会因为「登录满 N 小时」被踢**。当前到期时间在右上角用户菜单与系统设置页都写着「当前会话将于 X 过期」。
@@ -559,6 +560,7 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
- **批量退赛**:标记弃权(0 分、不占名次),**随时可以批量恢复**;已经是「取消资格 / 未出场」的行会被跳过、不覆盖原判定;
- **批量移出报名**:**物理删除**报名项连同他的成绩与积分流水,**不可恢复**,确认框会列出将被删的人与将重算的小项 / 组别;
- 一次最多 500 条;有未保存的成绩修改时请先「存草稿」再操作。
- 这三个动作(以及**撤销发布**、**作废单条成绩**、**改积分模板 / 组别权重 / 计分通道**)都**立即重算并推榜**,**不受「分批发布时实时更新榜单」这个延迟结算开关影响**——它们改的是「谁还算数」「按什么规则算」,不是「录了多少」,留着旧分就会变成「榜上还有分、成绩却撤了」。延迟结算只作用于**发布成绩**这一步(见 Q90)。
运动员列表也有类似的多选与**批量停用 / 批量彻底删除**(见使用手册 10.6)。
@@ -580,3 +582,49 @@ Console 启动的多屏窗口默认每屏锁定一页。到「大屏控制」点
3. 核对预览后删除。若某张图在你打开页面之后刚被配到别处,服务端会**拒删并说明被谁引用**(宁可漏删、不误删)。
注意:这个页签**只管图片**,上传的字体在「赛事信息 → 字体库」里各自删除(被标题 / 正文字体引用的不能删);这些图片和字体都是文件,**备份的 `.db` 快照和「一键恢复」都不含它们**(见 Q37),要清点或搬迁请到 `data\event_projs\<项目名>\uploads\`。
**Q94:奖牌榜上一个牌都没有,或者金牌数不对,怎么查?**
按下面顺序一项项排除(都不需要改数据,改完保存会自动重算榜单):
1. **是不是刚升级完、第一次启动**?→ 见 Q96,那是升级后的正常现象,服务端会自己补齐;
2. **该小项关了「该项启用奖牌结算」吗**?到「基础数据 → 大项 / 小项」编辑这个小项,看「选项」里的**「该项启用奖牌结算」**有没有被取消勾选——取消后这个小项**只出积分、不发奖牌**(见使用手册 10.2);
3. **该小项的通道关了「发奖牌」吗**?到「基础数据 → 计分通道」选中该小项,看「奖牌通道」列里这条通道的**「发奖牌」**有没有被取消——取消后这条通道的名次只出积分、不发牌(见使用手册 10.4);关掉的通道在「大项 / 小项」页的通道摘要里会标出 `不发奖牌`;
4. **个人项目的牌子是不是被排除在单位金牌榜之外**?同一列的**「个人奖牌并入单位金牌榜」**被取消时,这些个人奖牌仍进**个人积分榜**的奖牌列,但**不进单位金牌榜**——所以「某单位的金牌数比现场数的少」多半是这一条;
5. **这个小项本身计分吗**?标记为「不计分」(只排名不计分)的小项**从来不发奖牌**,这是它本来的口径,不用去动上面那些开关;
6. **名次是不是还没结算**?如果管理员开了**延迟结算**(Q90),未结算的组名次显示 `—`,自然也没有奖牌;等该组录完,或在录入页点「立即结算」;
7. **奖牌只发给前三名**,而且**并列第 1 各记 1 金、不发银牌**(名次顺延口径,见 Q10)——「牌数比名次人数少」通常就是这个原因;
8. 还有一条**全局开关**在规则包里(`standings.medalCountsTeamEvents`,默认**计入**团体项目的奖牌),界面上没有勾选框;本赛会的规则包是「计入」,一般不需要动。只有导入过别的规则包时才会把它改掉,检查办法见 Q47。
**Q95:团体名次在哪里录?为什么有时候录入页没有那一块?**
团体名次在**「成绩录入」页**录:选中项目与组别后,成绩表格下面会有一块 **「团体名次」** 卡片,按**单位**一行一个输入框,填完点「保存团体名次」。**留空就清空该单位的名次**;名次重复允许并列(会提示确认,不挡保存);**个人名次不受影响**——它是另一套数据,每个人的名次仍然在成绩列表里录。
**录入页没有这一块是正常的**,说明这个项目**没有配「团体名次 + 手动名次」的计分通道**。常见情况:
- 纯团体项目(篮球、拔河等):团体名次就是那条**团体报名行上的名次**,仍在成绩列表里照常录,不需要这块卡片;
- 「个人+团体」项目:团体名次是**按队内成绩平均**算出来的,也不在这里录;
- 真的需要按单位手填名次(例如「团体引体向上」):到「基础数据 → 计分通道」给这个小项加一条**名次范围 = 团体名次、名次来源 = 手动名次**的通道并「保存全部」,回录入页就会出现这块卡片。
完整说明见使用手册 4.9。
**Q96:升级到新版本后,奖牌榜是空的(全是 0),怎么办?**
这是升级后的**正常现象,会自己好**。原因:本版把奖牌统计的数据来源换成了一张新的「通道名次」表,而升级脚本只**建表、不回填**历史名次——所以升级完成到第一次重算之间,奖牌榜会短暂是 0。
服务端**下一次启动时**会自动做一次全量重算把名次补齐(重算在对外提供服务之前跑完,所以大屏不会先亮出一帧全 0)。在 Console「运行日志」或 `logs\operations\` 当天文件里能看到这两行,**是正常的,不是报错**:
```
检测到通道名次为空但已有已发布成绩,正在执行一次性全量重算
一次性全量重算完成,通道名次与奖牌榜已补齐(events=… ledgerRows=… elapsed=…)
```
- 通常**几秒内**跑完(数据量大时稍久,日志里会写耗时);跑完后刷新管理端/大屏即可看到奖牌;
- 它**只在需要时跑一次**:表里已经有名次(说明重算过)时不会再触发;
- 如果看到的是 `通道名次自愈失败,奖牌榜可能仍为空`,那不是"坏了"而是重算没做完:**随便发布一次成绩**、或**重新导入一次规则包**都会触发重算,重算完奖牌就回来了;
- 想立刻确认数据没问题,也可以手动**重新导入一次规则包**(会全量重算)。
**Q97(已知限制):双计项目回看历史版本时,积分跟当时现场对不上?**
有这种可能,属于**已知限制,不影响当前榜单**。
- **哪些项目**:配了「团体名次 + 手动名次」通道的项目(也就是录入页会出现「团体名次」卡片的那类,例如「团体引体向上」);
- **什么现象**:在「变更历史」里展开某个历史版本时,页面会按**那一版保存下来的成绩**重新算一遍各单位分数。而**按单位录入的「团体名次」不在历史版本快照里**,所以回看时这些组别的团体分算不出来,各单位的分数增减可能与当时现场看到的略有差异;
- **不影响什么**:**当前榜单、大屏、导出全部是对的**(它们读的是库里现存的团体名次,与历史快照无关);只有「历史版本详情」里那一列**分数增减**(以及它影响的单位数)会因此偏小或对不上;
- 想核对当时的真实分数,以**当时的导出件**(成绩总表 / 单位积分明细)为准。
+25 -21
View File
@@ -25,10 +25,10 @@
| `category` | **必须** | 组别**名称**(中文,要跟系统里一字不差) | `男子30岁以下` |
| `team_code` | **必须** | 参赛单位编码,抄系统里配好的 | `F1` |
| `athlete_name` | **必须** | 运动员姓名。**团体项目这一列留空** | `张伟` |
| `id_card` | 可选 | 证件号(身份证号)。**只是档案信息,不参与认人**;一个证件号只能属于一个人 | `110101199001011234` |
| `id_card` | 可选 | 证件号(身份证号)。**系统的第一认人依据**;一个证件号只能属于一个人 | `110101199001011234` |
| `gender` | 可选 | 性别,只写「男」或「女」 | `男` |
| `age` | 可选 | 年龄,0–120 的整数 | `26` |
| `bib` | 可选 | 号码布,**单人的唯一标识**(同名同姓的人靠它区分) | `101` |
| `bib` | 可选 | 号码布;证件号为空时按它认人(同一个号码布不能给两个人) | `101` |
| `seed` | 可选 | 道次 / 种子,随便写或留空 | `种子1` |
| `heat` | 可选 | 批次号:1–999 的整数;**留空 = 未分批**(不参与算分,见下) | `1` |
| `status` | 可选 | 报名状态:4 个英文词(大小写都行)或等价的中文别名(见下) | `registered` |
@@ -63,11 +63,11 @@
### `id_card` 证件号 / `bib` 号码布 —— 有姓名就至少填一个
只要有姓名,**证件号与号码布至少要填一个**,否则无法确认是哪一个人,这一行会被跳过,提示「填写了 athlete_name 就必须填 id_card 或 bib」。
- **号码布是单人的唯一标识,也是系统认人的依据**:先按号码布找人,号码布为空或没找到时,再按「姓名 + 单位」找(完整顺序见本节的「系统怎么认人」)。
- **证件号是可选的档案信息,不参与认人**:它只写进 / 更新人员档案,用来登记身份;没有身份证、外聘人员只填号码布就行。
- **但一个证件号在系统里只能属于一个人**:如果表里给的证件号已经登记在**另一个人**名下(姓名、号码布都对不上),这一行会报 `证件号 X 已被另一个人占用(姓名 Y,号码布 Z)` 并跳过——证件号不会被抢过来,那个人也不会被改成表里的人。
- **同一个证件号在同一份表里重复出现不再报错**(同一个人报多项时本来就会重复),照常导入。
- **号码布不能在一份表里重复出现**:重号说明要么是填错、要么是把号码布给了两个人,重复的行会被跳过并报错。
- **证件号是系统认人的第一依据**:先按证件号找人;证件号为空、或库里的档案还没登记证件号时,再按号码布找;两者都没找到,才按「姓名 + 单位」找(完整顺序见本节的「系统怎么认人」)。
- **一个证件号在系统里只能属于一个人**。表里给的证件号如果已经登记在别人名下,系统会按这个证件号去认那个人,姓名 / 单位对不上就进「冲突」列表让你逐条决定——不会把证件号抢过来,也不会静默改档。**证件号填错是最容易认错人的地方,请照抄身份证,不要凭记忆写。**
- **没有身份证的人只填号码布也行**(外聘人员、临时工常见):此时系统按号码布认人,下次导入也要带同样的号码布。
- **同一个证件号在同一份表里重复出现不报错**(同一个人报多个组别时本来就会重复):系统当作同一个人,每个组别各落一条报名,并在导入结果里给一条提示「证件号 XXXX 在本表中出现 N 次(同一人报名多个组别)」。**但同一小项同一个组别里出现两次就是真重复**,会进「冲突」列表,由你决定保留已有还是改用表里这条。
- **号码布不是唯一标识**,但两个人不能共用一个号码布:把同一个号码布给了两个不同的人,这一行会报错并跳过。(同一个人报多个组别时号码布可以重复。)
- 号码布会同时写进人员档案和报名记录。
### `gender` 性别
@@ -117,15 +117,16 @@
- 团体项目**可以只报单位、不写队员**(这一列留空即可),队员名单以后还能补。
- 系统界面里会把这条名单显示成「张三、李四、王五」。
### 系统怎么认人(号码布 → 姓名 + 单位)
有姓名的行,系统按下面的顺序认人。**号码布是唯一标识,证件号只当档案信息,不参与这一步**:
### 系统怎么认人(证件号 → 号码布 → 姓名 + 单位)
有姓名的行,系统按下面的顺序认人。**证件号是唯一标识,号码布是它的替补,最后才靠「姓名 + 单位」兜底回填**:
| 情况 | 系统怎么处理 |
|---|---|
| 表里的号码布在系统里已有 | 认作**同一个人**;若表里的姓名 / 性别 / 年龄 / 单位 / 号码布与他的档案对不上,会进「冲突」列表等你逐条决定(保留哪一侧),该行本轮不写入 |
| 号码布为空,或按号码布没找到 | 按「**姓名 + 单位**」找:<br>· 找不到 → 新建人员档案;<br>· 恰好一人、且他**还没有号码布** → 认定是同一人,此时若表里给了号码布,会**回填**到他的档案;<br>· 恰好一人、且他**已有号码布**,但表里**号码布为空或与他相同** → 仍认定是同一人(重传不带号码布的名单不会把每个人复制一份);<br>· 恰好一人、他已有号码布、**且表里给的号码布与他不同** → 按「**同名的另一个人**」**新建档案**,并在导入结果里单独列出(姓名 / 单位 / 原号码布 / 新号码布)提醒你核对,**不拦截、不报错**;<br>· 多人 → 分不清是谁,进「冲突」列表等逐条决定 |
| 表里的**证件号**在系统里已有 | 认作**同一个人**;若表里的姓名 / 性别 / 年龄 / 单位 / 号码布与他的档案对不上,会进「冲突」列表等你逐条决定(保留哪一侧),该行本轮不写入 |
| 证件号为空,或系统里还没有人有这个证件号 | 再看**号码布**:号码布在系统里已有 → 认作同一个人(差异同样进「冲突」列表) |
| 证件号与号码布都没找到 | 按「**姓名 + 单位**」找:<br>· 找不到 → 新建人员档案;<br>· 恰好一人、两边给的证件号(或号码布)对得上或有一边没填 → 认定是同一人,表里给的证件号 / 号码布 / 年龄会**回填**到他的档案(不算冲突);<br>· 恰好一人、但他已有**另一个**证件号(或号码布)且与表里不同 → 按「**同名的另一个人**」**新建档案**,并在导入结果里单独列出(姓名 / 单位 / 原证件号或号码布 / 新证件号或号码布)提醒你核对,**不拦截、不报错**;<br>· 多人 → 分不清是谁,进「冲突」列表等逐条决定 |
> 「同名的另一个人」多半是号码布写错了。收到这条提醒时,先核对新号码布是不是本人:是别人(真的同名),确认无误即可;是本人写错了号,到「基础数据 → 运动员」把档案里的号码布改回来,并把多出来的那条新档案删掉。
> 「同名的另一个人」多半是证件号(或号码布)写错了。收到这条提醒时,先核对表里那个号是不是本人:是别人(真的同名),确认无误即可;是本人写错了,到「基础数据 → 运动员」把档案里的号改回来,并把多出来的那条新档案删掉。
---
@@ -170,8 +171,10 @@
- [ ] `event_code`、`team_code` 都是从系统里抄的编码,没有空格
- [ ] `category` 与系统里的组别名一字不差
- [ ] 个人行都有姓名,且都有证件号或号码布
- [ ] 一份表里**没有重复的号码布**(号码布是唯一标识,重号会报错)
- [ ] 证件号可以重复(同一个人报多项很正常),但每个证件号在系统里只属于一个人,别和别人的档案重号
- [ ] 证件号优先填、填准(**它是系统认人的第一依据**,填错最容易认错人)
- [ ] 一份表里**没有把同一个号码布给两个不同的人**(同一个人报多个组别时可以重复)
- [ ] 同一小项同一个组别里没有把同一个人写两遍(真重复会进「冲突」列表等决策)
- [ ] 每个证件号在系统里只属于一个人,别和别人的档案重号
- [ ] `status` 只用那 4 个英文词(大小写都行)或第三节列的中文别名,不写别的词;拿不准就留空
- [ ] `heat` 要么留空,要么是 1–999 的整数(不参与算分,只是录入分组)
- [ ] 全表没有因为"怕麻烦"把某些列删掉——**表头 8 个必须列一个都不能少**(哪怕整列是空的)
@@ -192,12 +195,12 @@
| 第 N 行:单位 XX 不存在 | `team_code` 写错,或该单位还没配 | 到「基础数据 → 参赛单位」核对 |
| 第 N 行:组别 XXX 不存在 | 组别名和系统里不一致,或该小项还没有这个组别 | 到「基础数据 → 组别」核对名称(注意别多字少字) |
| 第 N 行:小项 XXX 没有组别 | 该小项一个组别都没配 | 先在「组别」里配好,再导入 |
| 第 N 行:填写了 athlete_name 就必须填 id_card 或 bib | 个人行缺两项唯一标识 | 补证件号或号码布;确实都没有的,请先在「运动员」里登记 |
| 第 N 行:号码布 XX 在报名表内重复出现 | 同一份表里同一个号码布出现了两次 | 删掉重复行(同一个人报多个项目时,`event_code` 必须不同;同一个号码布也不能给两个人) |
| 第 N 行:证件号 X 已被另一个人占用(姓名 Y,号码布 Z) | 表里给的证件号已经登记在**另一个人**名下。证件号不参与认人,但系统里一个证件号只能属于一个人 | 先核对证件号是不是抄错了:**不是这个人**的,把这一格留空即可(只填号码布也能导入);**是他的**,先到「基础数据 → 运动员」把另一条档案里的证件号清掉或改对,再重新上传这一步列出的行 |
| 第 N 行:填写了 athlete_name 就必须填 id_card 或 bib | 个人行缺两项标识 | 补证件号或号码布;确实都没有的,请先在「运动员」里登记 |
| 第 N 行:号码布 XX 在报名表内重复出现 | 同一份表里,**两个不同的人**用了同一个号码布 | 删掉重复行或改成各自的号码布。(同一个人报多个项目时号码布可以重复;不同的人不能共用。) |
| 第 N 行:证件号 X 已被另一个人占用(姓名 Y,号码布 Z) | 表里给的证件号已经登记在**另一个人**名下,而这一行又没法按证件号认到那个人(例如同时又给了别人的号码布) | 先核对证件号是不是抄错了:**不是这个人**的,把这一格留空即可(只填号码布也能导入);**是他的**,先到「基础数据 → 运动员」把另一条档案里的证件号清掉或改对,再重新上传这一步列出的行 |
| 第 N 行:status「xxx」无法识别 | `status` 填了系统不认的词(4 个标准词以外的英文,或第三节没列的中文) | 改成 `registered` / `scratched` / `dq` / `dns`(大小写都行)或第三节列的中文别名,也可以留空(= 正常参赛);改完重新上传 |
| 第 N 行:heat 需要是 1-999 的整数(留空表示未分批) | `heat` 填了非整数、0、负数或超过 999 的值(如 `第1批`、`一组`、`1000`) | 改成 1–999 的整数,或者整格留空(= 未分批);批次只影响录入分组,不参与算分 |
| 提示「冲突」,人员没有写入 | 按号码布(或「姓名 + 单位」唯一命中)的人在系统里已有记录,但姓名 / 性别 / 年龄 / 单位 / 号码布跟表里**对不上** | 在导入结果里逐条选「保留已有数据」或「使用新数据」,选完再提交 |
| 提示「冲突」,人员没有写入 | 按证件号(或号码布、「姓名 + 单位」唯一命中)的人在系统里已有记录,但姓名 / 证件号 / 性别 / 年龄 / 单位 / 号码布跟表里**对不上** | 在导入结果里逐条选「保留已有数据」或「使用新数据」,选完再提交 |
| 文件传不上去 | 超过 16MB | 拆分上传,或改用 xlsx |
| 只导入了第一张表 | xlsx 只读第一个工作表 | 把要导入的数据放在第一个工作表里 |
@@ -209,11 +212,12 @@
- **新增**:这次新建的报名;
- **更新**:这个人本来就有这个项目的报名,用表里的信息覆盖了(**不会产生重复报名**);
- **跳过**:没能导入的行,会带着**行号**列出来,改好那几行重新上传即可。
- 另有一份**「按同名的另一个人新建了档案(号码布不同)」**清单,单独列出姓名 / 单位 / 原号码布 / 新号码布。它不是错误:这些行**已经导入成功**,只是提醒你核对号码布有没有写错(见第三节的「系统怎么认人」)。
- 另有一份**「按同名的另一个人新建了档案(证件号 / 号码布不同)」**清单,单独列出姓名 / 单位 / 原证件号或号码布 / 新证件号或号码布。它不是错误:这些行**已经导入成功**,只是提醒你核对证件号与号码布有没有写错(见第三节的「系统怎么认人」)。
- 同一证件号在本表里出现多次时,还会给一条**「证件号 XXXX 在本表中出现 N 次(同一人报名多个组别)」**的提示:这是正常的,只提醒你别把不同的人写成同一个证件号。
2. **重复上传同一份表是安全的**,不会把名单变成两份。改完再传一遍就行。
- ⚠️ 但要注意「更新」是**整条覆盖**:表里空着的格会把系统里原来的值清掉(队员名单、道次、号码布、**批次**都会被清空),`status` 空着会被重置成「正常参赛」。如果之前手工调整过某些人的状态或批次,**重传前请在表里把 `status`、`heat` 写清楚**。
3. 名单导入后,到「成绩录入」里录成绩、发布,积分榜就会自动更新。
4. **被「彻底删除」的人,导入时会以新人员建档**:管理员彻底删除某个人时,他的档案连同他名下的报名与成绩会一起从库里删掉;之后表里再出现同一个号码布(或同一「姓名 + 单位」),系统匹配不到旧档案,会把他当作**新人员**重新建档——名单里多出一条「以前删过的人」通常就是这么来的。新档案是全新的,他以前的报名、成绩与积分不会回来,需要重新录。
4. **被「彻底删除」的人,导入时会以新人员建档**:管理员彻底删除某个人时,他的档案连同他名下的报名与成绩会一起从库里删掉;之后表里再出现同一个证件号(或同一个号码布、同一「姓名 + 单位」),系统匹配不到旧档案,会把他当作**新人员**重新建档——名单里多出一条「以前删过的人」通常就是这么来的。新档案是全新的,他以前的报名、成绩与积分不会回来,需要重新录。
5. **被「彻底删除」的单位则相反,导入时会「复活」**:管理员彻底删除某个单位,只是把它从单位列表里移除,它的报名与成绩一条都没删;表里再出现这个 `team_code`,系统按编码复用原来那条单位记录,清掉删除标记并让它重新出现在列表里,**原有的报名、成绩与积分都还在**,也不会新建第二个同名单位。
6. **别一口气连传几十次**:写操作限 **120 次/分钟/用户**,超了会返回「操作过于频繁,请稍后再试」。正常一次导入只算一次;真被限了就等一分钟再传,不要连点。
@@ -224,7 +228,7 @@
> 1. 用系统里下载的模板,**第一行不要动**;
> 2. **一个人一行**;一个人报几项就写几行;
> 3. `event_code`(小项)、`team_code`(单位)、`category`(组别)照抄系统里配好的,不自己编;
> 4. 每人要有**证件号或号码布**,至少一个;**号码布是系统认人的唯一标识**(优先填、别重号),证件号只是可选档案信息、也不能和别人重号;
> 4. 每人要有**证件号或号码布**,至少一个;**证件号是系统认人的第一依据**(有就优先填、填准、别和人重号);没有证件号时号码布顶替它认人,**号码布也不能给两个人**;
> 5. 团体项目:姓名列留空,队员写进 `member_names`,多人用 `/` 隔开;
> 6. 拿不准的列**留空**,不要写「无」「/」「—」这类符号;
> 7. 表里**不要合并单元格**、不要加标题行、不要插图;
+17
View File
@@ -119,6 +119,22 @@ deploy\build.bat
> 升级到本版本后第一次启动,请打开 Console 的「运行日志」确认是否有迁移记录,并核对管理端里的赛事/账号数据是否完整。
**升级后奖牌榜可能短暂是空的(正常,会自己补齐)**
本版给赛事库加了一条新迁移(**0020**),并新增了一张存"通道名次"的表与三个奖牌开关列。迁移**只建表、不回填**历史名次,所以**老库升级后、服务端做第一次重算之前,奖牌榜(金 / 银 / 铜)会是 0**——这不是数据丢了。
服务端**下一次启动时会自动做一次全量重算**把名次补齐(这次重算在开始对外提供服务之前跑完,所以大屏不会先亮出一帧全 0)。在 Console「运行日志」或 `<数据目录>\logs\operations\` 的当天日志里能看到这两行,**是正常的,不是报错**:
```
检测到通道名次为空但已有已发布成绩,正在执行一次性全量重算
一次性全量重算完成,通道名次与奖牌榜已补齐
```
- 通常**几秒内**跑完(成绩多时稍久,日志里会写处理了几个小项与耗时);跑完后刷新管理端 / 大屏,奖牌就回来了;
- 这是**一次性**的:表里已经有名次(说明重算过)之后不会再触发;
- 若日志里出现 `通道名次自愈失败,奖牌榜可能仍为空;可重新发布成绩或导入规则包触发重算`,说明这次重算没做完(不影响服务启动):**随便发布一次成绩**,或**重新导入一次规则包**(会全量重算),奖牌同样会回来。升级前如果做过备份,先确认榜单数字与升级前一致再开赛(见《上线检查清单》)。
- 升级命令与首次启动的完整流程见 3.4 开头;这条迁移是**加列 / 建表**,可重复执行,不会改动任何既有数据行。
### 3.5 配置与规则放在哪里(升级/卸载也不会丢)
`config.json`、`config.yaml`、`rules\` 以前跟着安装包落在安装目录里,而**安装目录会被卸载器整个删掉**(覆盖安装会先静默跑一遍旧卸载器),所以用户改过的配置和规则包会一起没。本版本起它们也搬到**用户数据目录**(与数据目录同一处,安装目录里那三份只当模板):
@@ -519,6 +535,7 @@ http://<主机IP>:19540/display
- **按编码匹配,存在就更新、不存在就新建;绝不删除**:文件里没有的行不会被删,也不会被停用;
- **两步走**:先「预览差异」(新增 / 更新 / 无变化 / 错误 + 逐行变化,这一步不写库),确认后再点「**确认写入**」;**有错的行会跳过,合法的行照常写入**,行级错误带**真实 Excel 行号**(如 `单位 第 3 行:单位编码必填`);
- **列不在表里 = 不动该字段**(**布尔列也一样**:缺整列不等于「取默认值」,否则把「启用」列删掉再导回,会把所有停用的单位/大项静默改成启用);**列在表里但格子空**:文本列与年龄上下限清空,权重按 1、布尔列按「是」,**排序留空保持原值**(**四张表口径一致**,单位 / 大项留空同样不会被改写);
- **枚举列例外:列在表里但格子空 = 不改动**(不是「取默认值」)。小项的类型 / 结果模式 / 结果类型 / 比较 / 状态 / 平均口径,以及组别的性别,留空都沿用原值;只有**新建的行**才用默认值(新建组别时性别留空 = 不限)。这是为了防手滑——误清一格不会把已发布小项打回「待录入」、也不会把「团体」改成「个人」;
- 表头行在第 4 行(系统导出件,上面是标题与副标题)或第 1 行(手工整理的表)都能识别;枚举列要填英文规范值(如 `individual` / `time` / `published`),布尔列填「是 / 否」;
- 被「彻底删除」的单位不在导出件里,导入也**不会**把它翻出来(仍是隐藏状态);
- **这个包只含基础数据**,不含成绩、报名与规则;整场赛事的搬迁仍用赛事项目包(见 8.5)。赛前导出一份留底,现场改乱了可以导回对照。