feat(import): 报名导入支持中文表头,并给出中/英两套模板下载

需求:主人要「CSV 模板的表头能改一下,或者提供两个按钮,一个中文表头一个英文表头」。

- 解析器加**中文别名**(英文仍是规范名:取值、报错、纯英文模板、勾选导出都用它)。
  12 列,顺序即模板列序:项目编码 / 组别 / 单位编码 / 姓名 / 证件号 / 性别 / 年龄 /
  号码布 / 种子 / 批次 / 状态 / 队员名单;另认一批同义写法(小项编码、参赛单位编码、
  运动员姓名、身份证号、道次、批次号、报名状态…)。
  Go 别名表 == 前端 COLUMN_ALIASES == 导入规范文档表格,三方逐列逐名一致(脚本核对)。
- **向后兼容**:纯英文表头一字不改照常导入;回归用**字面量**(不复用常量)钉死老 11 列表头
  与大写/空格变体,避免有人改常量把回归一起改掉。
- **中英可任意混排**,但**同一列出现两种写法(或写两遍)整份拦下**并说明——两列都可能带数据,
  静默取其一等于丢另一列。容错沿用既有先例:BOM(含格子中间的 U+FEFF)、全角空格/全角 ASCII、
  首尾空格、大小写。
- 缺列报错**中英并列**(「缺少列 athlete_name(姓名)」),现场拿中文模板的人一眼看懂。
- 前端两个下载按钮:「下载模板(中文表头)」「下载模板(英文表头)」,列序与列数完全一致,
  文件名可区分;示例数据模式(mock)同步,避免两条路径产出不同模板。
- 文档 `docs/报名名单导入规范.md` 补两套表头与「两套都能导入」的说明(原内容未删)。

端到端(真服务端 + curl):中文模板填两行 → {"created":2} 且库中值取自中文列;
英文模板同一份数据 → {"updated":2} 不重复建档;缺列与表头重复分别给出上述人话报错。
自检:gofmt / go build / go vet / go test 全绿;vue-tsc + 前端 754 例全过。
This commit is contained in:
AskaEth committed 2026-09-13 21:55:37 +08:00
1 parent b1c6d5d54a
commit 9951a69938
8 files changed
+713 -53

No files matched your search

+50 -19
View File
@@ -3,45 +3,75 @@
> 这份文件说明**报名名单应该做成什么样子、每一列怎么填**,用于把各单位报上来的名单一次性导入积分榜系统。
> 给负责收表、填表的同志看即可,不需要懂系统内部。
>
> 配套模板可在系统里直接下载:**基础数据 → 报名导入 → 下载 CSV 模板**。
> 配套模板可在系统里直接下载:**基础数据 → 报名导入 →「中文表头」/「英文表头」**(两个文件列数与列顺序完全一样,只有表头语言不同,按手上表格的样子选)。
---
## 一、先看懂三件事
1. **用什么软件做表**:Excel 或 WPS 都行,做完存成 `.xlsx` 或 `.csv` 都可以(推荐 `.csv`,系统兼容性最好,不用管编码)。
2. **表格长什么样**:**第一行是表头**(固定的 12 个英文列名),**从第二行开始每人一行**。不要合并单元格,不要在表头上方再加标题行、说明行。
2. **表格长什么样**:**第一行是表头**(固定的 12 个列名,**中文、英文两套任选其一**,见第二节),**从第二行开始每人一行**。不要合并单元格,不要在表头上方再加标题行、说明行。
3. **编码不能自己编**:表里的「小项编码」「单位编码」「组别名称」必须是系统里已经配好的,**照抄系统里的写法**。系统里没有的编码,这一行会被跳过并报错。
---
## 二、表头(第一行的列名)
一共 12 列。**列名请直接用下面这套英文名,不要翻译成中文**;列的**先后顺序可以随便调**,多出来的列系统会忽略。
一共 12 列。系统**同时认两套表头**——英文一套、中文一套,**两套都能导入**,也可以**中英混着写**(每一列各自认名字,例如英文 `event_code` 配中文「姓名」)。**英文是规范列名**:老的英文模板一个字都不用改,照常导入;中文只是给习惯看中文的人用的同义写法。
下载模板时有两个按钮,按手上表格的样子选:
- 「**中文表头**」→ 文件 `entries-template-zh.csv`
- 「**英文表头**」→ 文件 `entries-template-en.csv`
两个文件**列数与列顺序完全一样,只有表头语言不同**,示例行也一样。列的**先后顺序可以随便调**,多出来的列系统会忽略。
| 英文表头(规范列名) | 中文表头(同义写法) | 这一列是 |
|---|---|---|
| `event_code` | 项目编码(也认「小项编码」) | 小项编码 |
| `category` | 组别(也认「组别名称」) | 组别名称 |
| `team_code` | 单位编码(也认「参赛单位编码」) | 参赛单位编码 |
| `athlete_name` | 姓名(也认「运动员姓名」) | 运动员姓名;团体项目这一列留空 |
| `id_card` | 证件号(也认「身份证号」) | 证件号,可缺省 |
| `gender` | 性别 | 可缺省 |
| `age` | 年龄 | 可缺省 |
| `bib` | 号码布 | 号码布 |
| `seed` | 种子(也认「道次」) | 道次 / 种子 |
| `heat` | 批次(也认「批次号」) | 批次,可缺省 |
| `status` | 状态(也认「报名状态」) | 报名状态 |
| `member_names` | 队员名单 | 团体项目的队员名单 |
> **同一列只能写一次**:一份表里同时出现 `event_code` 和「项目编码」(或者干脆把同一列写了两遍),会被整份拦下并提示「报名表表头重复」,删掉多余的那一列再导入即可——系统不会替你猜该信哪一列,免得静默丢掉另一列的数据。
>
> 表头识别对**大小写、首尾空格、全角字母 / 全角空格、文件开头的 BOM** 都容错:`Event_Code`、「项目编码 」、「EVENT_CODE」都认。
下面是逐列要填什么(列名用英文规范名,括号里是中文表头的同义写法):
| 列名 | 是否必须 | 填什么 | 示例 |
|---|---|---|---|
| `event_code` | **必须** | 小项编码,抄系统里配好的 | `M100` |
| `category` | **必须** | 组别**名称**(中文,要跟系统里一字不差) | `男子30岁以下` |
| `team_code` | **必须** | 参赛单位编码,抄系统里配好的 | `F1` |
| `athlete_name` | **必须** | 运动员姓名。**团体项目这一列留空** | `张伟` |
| `id_card` | 可选 | 证件号(身份证号)。**系统的第一认人依据**;一个证件号只能属于一个人 | `110101199001011234` |
| `gender` | 可选 | 性别,只写「男」或「女」 | `男` |
| `age` | 可选 | 年龄,0–120 的整数 | `26` |
| `bib` | 可选 | 号码布;证件号为空时按它认人(同一个号码布不能给两个人) | `101` |
| `seed` | 可选 | 道次 / 种子,随便写或留空 | `种子1` |
| `heat` | 可选 | 批次号:1–999 的整数;**留空 = 未分批**(不参与算分,见下) | `1` |
| `status` | 可选 | 报名状态:4 个英文词(大小写都行)或等价的中文别名(见下) | `registered` |
| `member_names` | 可选 | 团体项目的队员名单,多人用 `/` 隔开 | `张三/李四/王五` |
| `event_code`(项目编码) | **必须** | 小项编码,抄系统里配好的 | `M100` |
| `category`(组别) | **必须** | 组别**名称**(中文,要跟系统里一字不差) | `男子30岁以下` |
| `team_code`(单位编码) | **必须** | 参赛单位编码,抄系统里配好的 | `F1` |
| `athlete_name`(姓名) | **必须** | 运动员姓名。**团体项目这一列留空** | `张伟` |
| `id_card`(证件号) | 可选 | 证件号(身份证号)。**系统的第一认人依据**;一个证件号只能属于一个人 | `110101199001011234` |
| `gender`(性别) | 可选 | 性别,只写「男」或「女」 | `男` |
| `age`(年龄) | 可选 | 年龄,0–120 的整数 | `26` |
| `bib`(号码布) | 可选 | 号码布;证件号为空时按它认人(同一个号码布不能给两个人) | `101` |
| `seed`(种子) | 可选 | 道次 / 种子,随便写或留空 | `种子1` |
| `heat`(批次) | 可选 | 批次号:1–999 的整数;**留空 = 未分批**(不参与算分,见下) | `1` |
| `status`(状态) | 可选 | 报名状态:4 个英文词(大小写都行)或等价的中文别名(见下) | `registered` |
| `member_names`(队员名单) | 可选 | 团体项目的队员名单,多人用 `/` 隔开 | `张三/李四/王五` |
> 「必须」指的是**这一列的表头要有**。至于每格里能不能留空,看下面第三节逐列的说明。
**表头大小写不敏感**:写 `Event_Code` 或 `event_code` 都认。
**表头大小写不敏感**:写 `Event_Code` 或 `event_code` 都认;换成中文表头(`项目编码`)也认,两套混着写同样可以。
---
## 三、逐列怎么填(重点)
> 下面每一列的小标题写的是**英文规范名**;用中文表头时列名换成第二节对照表里的中文写法(`event_code` = 项目编码、`category` = 组别、`team_code` = 单位编码、`athlete_name` = 姓名、`id_card` = 证件号、`gender` = 性别、`age` = 年龄、`bib` = 号码布、`seed` = 种子、`heat` = 批次、`status` = 状态、`member_names` = 队员名单),**填法完全相同**。
### `event_code` 小项编码 —— 必须填
在系统「基础数据 → 大项 / 小项」里给每个小项配的**编码**,比如 `M100`(男子100米)、`BB`(多人抓杆蛇形跑)。
填了系统里没有的编码,这一行会被跳过,提示「小项 XXX 不存在」。
@@ -166,7 +196,7 @@
## 五、导入前请先检查(自检清单)
- [ ] 第一行是那 12 个英文列名,没有被翻译、没有被合并单元格
- [ ] 第一行是那 12 个列名(**英文一套、中文一套都行**,也可以中英混着写,见第二节),没有被合并单元格、**同一列没有写两遍**
- [ ] 表头上方没有多余的标题行或空行
- [ ] `event_code`、`team_code` 都是从系统里抄的编码,没有空格
- [ ] `category` 与系统里的组别名一字不差
@@ -186,7 +216,8 @@
| 提示 | 原因 | 怎么办 |
|---|---|---|
| 第 N 行:event_code / team_code 必填 | 这两格至少有一格是空的 | 每行都必须有小项编码和单位编码 |
| 报名表缺少列 xxx | 表头少了这一列,或者列名被写成中文 / 有错别字 / 上面多了标题行 | 对照第二节的表头逐字核对;最稳的是重新下载模板,把数据粘进去 |
| 报名表缺少列 xxx(yyy) | 表头少了这一列,或者列名有错别字 / 上面多了一行标题行。括号里的中文与前面的英文是**同一列**的两种写法(例:`报名表缺少列 athlete_name(姓名)`) | 对照第二节的对照表逐字核对(中英两套都认,混着写也行);最稳的是重新下载模板,把数据粘进去 |
| 报名表表头重复:第 1 行里同一列出现了两种写法 | 同一列在表头里写了两次(例如既有 `event_code` 又有「项目编码」)——两列都可能带着数据,系统不知道该信哪一列 | 删掉多余的那一列(同一列只留一种写法),再重新上传 |
| 中文变成乱码 | 编码问题,**现在已修好**:Excel 另存的 GB18030 / GBK / UTF-8(带 BOM) / UTF-16(带 BOM) 都认 | **直接传原文件即可,不用转码**。唯一例外见下面两条 |
| 报名表编码无法识别:文件里混有无法解码的字节 | 这个文件**本身坏了**(复制粘贴、转换工具、半路截断都会这样):坏字节会被静默解成 `�`,导进去就是一串乱码人名,比报错更危险,所以系统直接拦下 | 用 Excel 打开**原文件**,另存为「CSV UTF-8」后再上传;如果另存后仍报同一句,说明原文件已经损坏,请找原始数据重新导出一份 |
| 文件像 UTF-16 但缺 BOM | 用记事本「另存为 Unicode」会产出**不带 BOM** 的 UTF-16;这种文件以前会被误报成「缺少列 event_code」,指向完全错误的方向 | 多数情况系统能自动认出字节序并正确导入;仍报此提示时,用 Excel 另存为「CSV UTF-8」 |
@@ -225,7 +256,7 @@
## 八、给填写人的最短提示(一页版)
> 1. 用系统里下载的模板,**第一行不要动**;
> 1. 用系统里下载的模板(**中文表头 / 英文表头都能用**,见第二节),**第一行不要动**、同一列不要写两遍;
> 2. **一个人一行**;一个人报几项就写几行;
> 3. `event_code`(小项)、`team_code`(单位)、`category`(组别)照抄系统里配好的,不自己编;
> 4. 每人要有**证件号或号码布**,至少一个;**证件号是系统认人的第一依据**(有就优先填、填准、别和人重号);没有证件号时号码布顶替它认人,**号码布也不能给两个人**;