master
lion 2 months ago
parent 179e8e2d56
commit 720b508a2f

@ -3,4 +3,4 @@
> **说明**:本文档用于汇总栈版本、目录规范、环境变量与部署约定等。**当前仓库以实际 `composer.json` / `package.json` 及《需求规格说明书》引用为准**。
> **与近期报名/评审相关实现**:选手端锁定规则(截止时间 `signup_close_at`、`application_review_records` 等见《需求规格说明书》2a 节、《数据结构说明》3.7 节;**不要求在本页重复展开**,以免与代码迁移不一致。
正文待按团队规范补充PHP / Laravel、前端 `cxxfds-web`、数据库、宝塔部署等。)
正文待按团队规范补充PHP / Laravel、前端 `cxxfds-web`、数据库、宝塔部署等。)

@ -7,14 +7,14 @@
## 一、文档关系
| 内容 | 所在文档 § |
| ------------------------------- | --------------------------- |
| 内容 | 所在文档 § |
| ------------------------------------------------------- | ------------------------------------- |
| 评审打分 Schema、计分规则、`line_total` / `team_sum` / `team_avg` | 《评审评分-自定义表单与计分规则.md》本文 **§3.7、§3.9** |
| 报名数据存储、Schema 与表关系(是否每字段一表) | 本文 **§3.8** |
| 全表字段表、外键一览、**Mermaid ER 图(中文)** | 《后台管理-菜单与数据库设计》**§2.22.3** |
| 与本文 §3.8 对应的精简条目DDL 文档内) | 《后台管理-菜单与数据库设计》**§2.0** |
| 多端品牌 JSON 示例 | 《后台管理-菜单与数据库设计》**第五节** |
| 管理端侧栏菜单、动态路由与权限锚点 | 《后台管理-菜单与数据库设计》**§1.1**;本文 **§3.5** |
| 报名数据存储、Schema 与表关系(是否每字段一表) | 本文 **§3.8** |
| 全表字段表、外键一览、**Mermaid ER 图(中文)** | 《后台管理-菜单与数据库设计》**§2.22.3** |
| 与本文 §3.8 对应的精简条目DDL 文档内) | 《后台管理-菜单与数据库设计》**§2.0** |
| 多端品牌 JSON 示例 | 《后台管理-菜单与数据库设计》**第五节** |
| 管理端侧栏菜单、动态路由与权限锚点 | 《后台管理-菜单与数据库设计》**§1.1**;本文 **§3.5** |
---
@ -50,38 +50,38 @@
### 3.1 赛事与表单
- `competitions.form_schema_id` → 当前前台使用的 **`form_schema_definitions`** 记录(**选手报名**)。
- `competitions.form_schema_id` → 当前前台使用的 `**form_schema_definitions**` 记录(**选手报名**)。
- `competitions.review_form_schema_id`(可选)→ **评审打分表单** `review_form_schema_definitions`(或与报名表共用表加 `purpose`,见《评审评分-自定义表单与计分规则.md》§3.1**未绑定时** 使用 **系统默认评审 Schema**。
- `competitions.scoring_rules_json`(可选)→ **本场**计分与聚合规则;**空或未配置** 时使用 **系统默认规则**`line_total`、`team_sum`、`team_avg` 口径见 **§3.9** 与《评审评分》§4
- `form_schema_definitions.competition_id` 可为空:表示可复用的模版;也可能与某赛事同源,设计允许 **模版与场次双向前提**——注意避免循环配置的运营流程。
### 3.2 赛事与承诺书
- `competitions.pledge_document_id`**`legal_documents`**,用于正文版本与 **`content_hash`** 校验。
- `competitions.pledge_document_id``**legal_documents`**,用于正文版本与 `**content_hash**` 校验。
- `applications.pledge_document_id`**提交瞬间**的版本快照(与签署时间配合审计)。
### 3.3 选手与报名
- 一名 **选手** 在同一 **赛事** 下至多 **一条** `applications``(competition_id, participant_id)` 唯一)。
- 选手登录主体仅为 **`participants`**,不与管理员/评审员混表。
- 选手登录主体仅为 `**participants`**,不与管理员/评审员混表。
### 3.4 赛道
- **`competition_tracks`**`track_code` 在赛事内唯一;**简介**面向表单富展示。
- **`applications.track_code`**:存选手所选编码;**`track_snapshot`** 保存提交时标题冗余,便于历史展示。
- **`reviewer_scopes.track_code`**:须与 **`competition_id`** 下联的 `competition_tracks` 一致DDL 多为逻辑约束)。
- `**competition_tracks**``track_code` 在赛事内唯一;**简介**面向表单富展示。
- `**applications.track_code`**:存选手所选编码;`**track_snapshot**` 保存提交时标题冗余,便于历史展示。
- `**reviewer_scopes.track_code**`:须与 `**competition_id**` 下联的 `competition_tracks` 一致DDL 多为逻辑约束)。
### 3.5 管理员 RBAC
- **`roles` / `permissions` / `permission_role`**:定义权限全集与角色所含权限。
- **`admin_user_roles`**:仅为 **`admin_users`** 授权;**不包含**选手与评审。
- **管理后台侧栏与动态路由**:侧栏可见项及 **`cxxfds-web`** 中 **`router.addRoute`** 所注册的路由,应与当前用户实际拥有的 **`permissions.code`** 一致;菜单树由 **服务端接口** 按 RBAC 裁剪后返回,**不要求**为侧栏单独建立必选数据表。菜单元数据path、父子级、排序、图标等可由后端代码配置或与权限扩展字段绑定详见 **《后台管理-菜单与数据库设计.md》§1.1** 与《需求规格说明书》**FR-S-05**。
- `**roles` / `permissions` / `permission_role**`:定义权限全集与角色所含权限。
- `**admin_user_roles**`:仅为 `**admin_users**` 授权;**不包含**选手与评审。
- **管理后台侧栏与动态路由**:侧栏可见项及 `**cxxfds-web`** 中 `**router.addRoute**` 所注册的路由,应与当前用户实际拥有的 `**permissions.code**` 一致;菜单树由 **服务端接口** 按 RBAC 裁剪后返回,**不要求**为侧栏单独建立必选数据表。菜单元数据path、父子级、排序、图标等可由后端代码配置或与权限扩展字段绑定详见 **《后台管理-菜单与数据库设计.md》§1.1** 与《需求规格说明书》**FR-S-05**。
### 3.6 扩展字段
- **`applications.extra_json`**:动态表单中未落物理列的键值;详细读写与展示流程见 **§3.8**。
- **`competitions.settings`**:单场业务开关(上传策略覆盖等)。
- **`competitions.branding_json`**:多端展示文案与主题色等。
- `**applications.extra_json`**:动态表单中未落物理列的键值;详细读写与展示流程见 **§3.8**。
- `**competitions.settings`**:单场业务开关(上传策略覆盖等)。
- `**competitions.branding_json**`:多端展示文案与主题色等。
### 3.7 评审打分与报名锁定(需求已确认;实施时增补迁移)
@ -90,65 +90,67 @@
**表名建议:`application_review_scores`**(语义上可与单行 `application_reviews` 等价,项目内统一一名即可)
| 字段 | 含义 |
| --------------------------- | -------------------------------------- |
| `id` | 主键 |
| `application_id` | FK → `applications`ON DELETE CASCADE |
| `reviewer_id` | FK → `reviewers` |
| `review_schema_id` | **提交瞬间**绑定的评审表单版本FK → 评审 Schema 定义表),用于历史还原 |
| `payload_json` | 评审填报:各 **`number` 维度键值**、**`textarea` 评语** 等;**服务端按本场规则计算后** 写入 **`line_total`**(本条评审总分,见 §3.9 |
| `score`(可选/兼容) | **迁移或一维简版** 时可用于镜像 **`line_total`**,便于旧查询;新逻辑以 **`payload_json.line_total`** 为权威 |
| `created_at` / `updated_at` | 时间戳 |
| 字段 | 含义 |
| --------------------------- | ----------------------------------------------------------------------------------------------- |
| `id` | 主键 |
| `application_id` | FK → `applications`ON DELETE CASCADE |
| `reviewer_id` | FK → `reviewers` |
| `review_schema_id` | **提交瞬间**绑定的评审表单版本FK → 评审 Schema 定义表),用于历史还原 |
| `payload_json` | 评审填报:各 `**number` 维度键值**、`**textarea` 评语** 等;**服务端按本场规则计算后** 写入 `**line_total`**(本条评审总分,见 §3.9 |
| `score`(可选/兼容) | **迁移或一维简版** 时可用于镜像 `**line_total`**,便于旧查询;新逻辑以 `**payload_json.line_total**` 为权威 |
| `created_at` / `updated_at` | 时间戳 |
- **唯一约束**`UNIQUE(application_id, reviewer_id)`(每名评审对每条报名 **一轮**、一行记录)。
- **无**「通过/驳回」等评审状态列。
- **Schema 驱动**:评审页 **禁止** 硬编码业务打分项;填报键与 **`review_form_schema_definitions.schema_json`** 一致,与报名 §3.8 同源思路。
- **Schema 驱动**:评审页 **禁止** 硬编码业务打分项;填报键与 `**review_form_schema_definitions.schema_json`** 一致,与报名 §3.8 同源思路。
**选手端锁定**(由应用层判断,不必单独 `locked`与《需求规格说明书》§2a.1 一致):
1. 当前时间 **晚于** 对应赛事 **`competitions.signup_close_at`****该字段为空** 时本条不生效);或
2. 该 **`application_id`** 已产生 **评审侧锁定标记**。**设计口径** 为:**`application_review_scores` 中已有任意一行已提交成功的评审****任一评审员打分即锁整条报名**与《评审评分》§3.4 一致)。**当前工程实现(`cxxfds-service`** 另建表 **`application_review_records`**`application_id` FK`id`、`timestamps`**任意一行存在** 即视为「已有评委评审」,选手端 API 返回 `participant_may_edit=false` 并拒绝写操作。评审提交打分时 **应写入** `application_review_scores`(权威业务数据);**建议同时插入或后续改为仅以 scores 表判定锁定**,避免双源不一致。
1. 当前时间 **晚于** 对应赛事 `**competitions.signup_close_at`****该字段为空** 时本条不生效);或
2. 该 `**application_id`** 已产生 **评审侧锁定标记**。**设计口径** 为:`**application_review_scores` 中已有任意一行已提交成功的评审****任一评审员打分即锁整条报名**与《评审评分》§3.4 一致)。**当前工程实现(`cxxfds-service`** 另建表 `**application_review_records`**`application_id` FK`id`、`timestamps`**任意一行存在** 即视为「已有评委评审」,选手端 API 返回 `participant_may_edit=false` 并拒绝写操作。评审提交打分时 **应写入** `application_review_scores`(权威业务数据);**建议同时插入或后续改为仅以 scores 表判定锁定**,避免双源不一致。
### 3.8 报名数据的存储与只读渲染(评审端 / 管理后台)
#### 表单定义权威(自定义表单全覆盖)
- **报名表单的生成与字段全集**(含 **顺序、标签、类型、校验、必填、选项、展示控件****全部由** 当前赛事绑定的 **`form_schema_definitions.schema_json`** 控制;后台 **表单设计器 / Schema 配置** 为唯一配置入口。
- **报名表单的生成与字段全集**(含 **顺序、标签、类型、校验、必填、选项、展示控件****全部由** 当前赛事绑定的 `**form_schema_definitions.schema_json`** 控制;后台 **表单设计器 / Schema 配置** 为唯一配置入口。
- **不例外****姓名、手机、邮箱、毕业院校、企业名称、项目名称、赛道、地区、项目简介** 等,**均** 作为 Schema 中的字段项配置,**禁止**在选手报名表页面以「硬编码独立 input」方式绕过 Schema页面只实现 **通用 Schema 渲染器** + 特殊 `widget`)。
- **附件、承诺书签署** 等也以 Schema 字段形式出现(如 `type`: `file` / `pledge_signature`),由渲染器映射到上传与签署交互;存储仍走 **`application_files`** 及相关列,见下表。
- **附件、承诺书签署** 等也以 Schema 字段形式出现(如 `type`: `file` / `pledge_signature`),由渲染器映射到上传与签署交互;存储仍走 `**application_files`** 及相关列,见下表。
#### 存储落点
| 落点 | 内容 |
|------|------|
| **`applications` 表一行** | **身份与流程态**:如 `competition_id`、`participant_id`、`schema_id`、`status`、`submitted_at`;以及 **可选**与 Schema 约定的 **冗余物理列**(便于列表筛选、导出、旧系统兼容),列与字段 `key`**映射由实现约定**,非页面硬编码。历史 DDL 中出现的姓名、赛道等列可视为 **常用字段的镜像****新增业务字段若无列则一律进 `extra_json`**。 |
| **`applications.extra_json`** | Schema 中各字段 **`key` → 值****凡未映射到物理列** 的键值均在此(含未来增删字段)。 |
| **`application_files` + 存储** | 对应 Schema 中文件类字段产生的附件;`kind` 与 Schema/业务映射一致。 |
| 落点 | 内容 |
| ----------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `**applications` 表一行** | **身份与流程态**:如 `competition_id`、`participant_id`、`schema_id`、`status`、`submitted_at`;以及 **可选**与 Schema 约定的 **冗余物理列**(便于列表筛选、导出、旧系统兼容),列与字段 `key`**映射由实现约定**,非页面硬编码。历史 DDL 中出现的姓名、赛道等列可视为 **常用字段的镜像****新增业务字段若无列则一律进 `extra_json`**。 |
| `**applications.extra_json**` | Schema 中各字段 `**key` → 值****凡未映射到物理列** 的键值均在此(含未来增删字段)。 |
| `**application_files` + 存储** | 对应 Schema 中文件类字段产生的附件;`kind` 与 Schema/业务映射一致。 |
#### 是否「每个赛事 / 每个自定义字段各一张表」?(否)
- **不是。** 不会为「每场赛事的每一个自定义字段」分别建一张数据表;也不采用「每个报名、每个字段一行」的独立窄表作为**当前方案的主路径**(若未来有特殊审计需求可再讨论 EAV 扩展表,与下文并存)。
- **字段定义(有哪些、什么类型)**:统一存在表 **`form_schema_definitions`** 中,**一行代表某一版表单**`schema_json` 内用 JSON **列举多个字段**;赛事通过 **`competitions.form_schema_id`**(或发布策略)指向要用的 **`id`**
- **报名填报值(用户填了什么)**:统一存在表 **`applications`** 中,**一行代表「一名选手在某赛事的一条报名」**;多条报名 = 多行 `applications`,用 **`competition_id`** 区分赛事、**`schema_id`** 区分当时使用的表单版本;各自定义字段的值主要在 **`extra_json`**`key` 与 Schema 一致),少数热门字段可 **冗余到物理列** 便于筛选,见上表。
- **小结**:区分赛事靠 **`competition_id`**,区分使用哪套表单靠 **`schema_id`**,区分各字段取值靠 **同一条 `applications` 行内的 `extra_json`(及可选列)**——**不是**「每张表只存一个字段」。
- **字段定义(有哪些、什么类型)**:统一存在表 `**form_schema_definitions`** 中,**一行代表某一版表单**`schema_json` 内用 JSON **列举多个字段**;赛事通过 `**competitions.form_schema_id`**(或发布策略)指向要用的 `**id**`。
- **报名填报值(用户填了什么)**:统一存在表 `**applications`** 中,**一行代表「一名选手在某赛事的一条报名」**;多条报名 = 多行 `applications`,用 `**competition_id`** 区分赛事、`**schema_id**` 区分当时使用的表单版本;各自定义字段的值主要在 `**extra_json**``key` 与 Schema 一致),少数热门字段可 **冗余到物理列** 便于筛选,见上表。
- **小结**:区分赛事靠 `**competition_id`**,区分使用哪套表单靠 `**schema_id**`,区分各字段取值靠 **同一条 `applications` 行内的 `extra_json`(及可选列)**——**不是**「每张表只存一个字段」。
**与 Schema 的约定(实现层)**
- **权威定义****Schema + `schema_id`**。物理列仅为 **查询/报表友好** 的同步目标,**增减字段以改 Schema 为主**,不通过改报名页 HTML 增删。
- 提交时写入 **`applications.schema_id`**;展示时按 **该版本 Schema** 遍历字段 key**列(若映射)或 `extra_json`** 取值,规则同下「只读渲染」。
- 提交时写入 `**applications.schema_id`**;展示时按 **该版本 Schema** 遍历字段 key**列(若映射)或 `extra_json`** 取值,规则同下「只读渲染」。
#### 后台 / 评审端:报名详情如何渲染(只读)
1. 读取 **`applications`** 一行(含 `schema_id`、`extra_json`、各固定列)。
2. 加载 **`form_schema_definitions`**:优先 **`applications.schema_id`** 指向的版本,保证与 **提交瞬间** 字段定义一致。
3. 按 **`schema_json` 中字段数组顺序**(或约定 `sort`)遍历:
- 对每个字段 **`key`**:按团队维护的 **列映射表** 从 **`applications.{列}`** 取数,若无映射则从 **`extra_json[key]`** 取数。
- **展示用** 的文案、控件类型、选项来源:使用 Schema 内 `label`、`type`、`options` / `optionsRef`;列表展示期可减少实时字典请求,改用 **提交快照** 或缓存。
4. **文件类**:计划书/佐证/签名等以 **`application_files`** 按 `kind`(如 `plan`、`supporting`、`pledge_signature`)提供 **列表、下载、预览** 链接,与 Schema 中 `file` 字段配置一致。
5. **主题赛道**:列表/摘要可用 **`track_snapshot`**,或联 **`competition_tracks`** 取当前标题(历史以 snapshot 为准)。
1. 读取 `**applications**` 一行(含 `schema_id`、`extra_json`、各固定列)。
2. 加载 `**form_schema_definitions**`:优先 `**applications.schema_id**` 指向的版本,保证与 **提交瞬间** 字段定义一致。
3. 按 `**schema_json` 中字段数组顺序**(或约定 `sort`)遍历:
- 对每个字段 `**key`**:按团队维护的 **列映射表** 从 `**applications.{列}`** 取数,若无映射则从 `**extra_json[key]**` 取数。
- **展示用** 的文案、控件类型、选项来源:使用 Schema 内 `label`、`type`、`options` / `optionsRef`;列表展示期可减少实时字典请求,改用 **提交快照** 或缓存。
4. **文件类**:计划书/佐证/签名等以 `**application_files`** 按 `kind`(如 `plan`、`supporting`、`pledge_signature`)提供 **列表、下载、预览** 链接,与 Schema 中 `file` 字段配置一致。
5. **主题赛道**:列表/摘要可用 `**track_snapshot`**,或联 `**competition_tracks**` 取当前标题(历史以 snapshot 为准)。
**评审端**:报名详情区 **只读****打分** 走独立表 **`application_review_scores`**(见 §3.7),与报名表数据展示分离;打分界面由 **评审 Schema** 渲染§3.9)。
**评审端**:报名详情区 **只读****打分** 走独立表 `**application_review_scores`**(见 §3.7),与报名表数据展示分离;打分界面由 **评审 Schema** 渲染§3.9)。
**管理后台**:数据合并逻辑与评审端相同;可扩展导出、审计、关联 `participants` 手机号等。选手修改权限与锁定条件见《需求规格说明书》§2a。
@ -156,13 +158,15 @@
与《评审评分-自定义表单与计分规则.md》**第四节** 对齐的 **数据落点** 摘要:
| 约定 | 说明 |
|------|------|
| **评审表单定义** | 独立表 **`review_form_schema_definitions`**(或与 `form_schema_definitions` 共用并区分 `purpose``schema_json` 中为 **`number` 维度 + 评语** 等;也可只配 **一个 `number`**。 |
| **赛事绑定** | `competitions.review_form_schema_id`**未绑** → 代码/种子中的 **默认评审 Schema**。 |
| **`line_total`** | 单条评审记录的总分:对 **`payload_json`** 内各数值维度按 **`scoring_rules_json`(或默认)** 权重计算,**提交时写回 `payload_json`**,防篡改、便于列表直读。 |
| **`team_sum` / `team_avg`** | 对某 **`application_id`** 下 **已提交** 评审的 `line_total` 聚合:**总分求和**、**平均分 = 总和 / 已提交评审人数**(分母不含未评价、草稿)。列表可实时聚合或物化缓存。 |
| **`competitions.scoring_rules_json`** | **可空**;空=**系统默认计分**(维度权重、封顶、同分等以默认 JSON 或代码常量为准);非空则覆盖默认。 |
| 约定 | 说明 |
| ------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ |
| **评审表单定义** | 独立表 `**review_form_schema_definitions`**(或与 `form_schema_definitions` 共用并区分 `purpose``schema_json` 中为 **`number` 维度 + 评语** 等;也可只配 **一个 `number`**。 |
| **赛事绑定** | `competitions.review_form_schema_id`**未绑** → 代码/种子中的 **默认评审 Schema**。 |
| `**line_total`** | 单条评审记录的总分:对 `**payload_json**` 内各数值维度按 `**scoring_rules_json`(或默认)** 权重计算,**提交时写回 `payload_json`**,防篡改、便于列表直读。 |
| `**team_sum` / `team_avg**` | 对某 `**application_id**`**已提交** 评审的 `line_total` 聚合:**总分求和**、**平均分 = 总和 / 已提交评审人数**(分母不含未评价、草稿)。列表可实时聚合或物化缓存。 |
| `**competitions.scoring_rules_json`** | **可空**;空=**系统默认计分**(维度权重、封顶、同分等以默认 JSON 或代码常量为准);非空则覆盖默认。 |
---
@ -227,6 +231,6 @@
1. `**slug`** 最长字符集与保留字
2. `**track_code`** 命名规则(英文/拼音/数字)
3. `**promise_signature`** 仅存路径抑或同时保留缩略哈希
4. `**admin_operation_logs.payload**` 是否脱敏入库
4. `**admin_operation_logs.payload`** 是否脱敏入库
如需将本章与 **OpenAPI/Swagger JSON** 对齐,可提供接口草稿后增补「接口 ↔ 表字段映射」一节。

@ -63,17 +63,17 @@
在已有 `**UNIQUE(application_id, reviewer_id)`** 前提下,将「一轮提交」存为:
| 方案 | 内容 |
| ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **推荐** | `**review_schema_id`** + `**payload_json**`:键与 Schema 一致;**维度分**`{ "dim_innovation": 30, "dim_market": 25, "comment": "…" }`;提交后由服务端按 **本赛事 `scoring_rules_json`** 计算 `**line_total`(本条评审总分)** 写回 `payload_json`,保证与规则版本一致、防篡改。 |
| 备选 | 若干固定列 + `extra_json`,仍建议保留 `**schema_id`** 以便历史还原。 |
| 方案 | 内容 |
| ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| **推荐** | `**review_schema_id`** + `**payload_json`**:键与 Schema 一致;维度分 如 `{ "dim_innovation": 30, "dim_market": 25, "comment": "…" }`;提交后由服务端按 本赛事 `scoring_rules_json` 计算 `**line_total`(本条评审总分)** 写回 `payload_json`,保证与规则版本一致、防篡改。 |
| 备选 | 若干固定列 + `extra_json`,仍建议保留 `**schema_id`** 以便历史还原。 |
**物理主键**:仍建议单表 `**application_review_scores`**(名称可改为 `**application_reviews**` 若语义 broader**一行 = 一轮评审**。
**物理主键**:仍建议单表 `**application_review_scores`**(名称可改为 `**application_reviews`** 若语义 broader**一行 = 一轮评审**。
### 3.3 评审端渲染
与报名 **同一套路**:读 `**review_form_schema_definitions.schema_json`** → 通用渲染器 → 提交写 `**payload_json**`**禁止**评审页硬编码「分数+评语」以外的业务字段。
与报名 **同一套路**:读 `**review_form_schema_definitions.schema_json`** → 通用渲染器 → 提交写 `**payload_json`****禁止**评审页硬编码「分数+评语」以外的业务字段。
### 3.4 「锁定」判定(与需求对齐)
@ -155,7 +155,7 @@
1. **Phase 1与已确认口径对齐**
- 评审 Schema**多维度 `number` + 评语**;服务端按 **默认规则** 算 `**line_total`**。
- 评审记录表:`review_schema_id`、`payload_json`(含维度与 `**line_total**`)。
- 评审记录表:`review_schema_id`、`payload_json`(含维度与 `**line_total`**)。
- `competitions.scoring_rules_json`**可空**;空则 **§4.1**;非空则 **§4.2**。
- 列表/详情:展示 `**team_sum`、`team_avg`**(分母 = **已提交评审数**)。
2. **Phase 2**

@ -28,7 +28,7 @@
| 报名 | `applications`,某选手在某赛事下的一条填报记录 |
| 赛道 | `competition_tracks`,本场主题方向,含展示用简介 |
| 评审打分表单 | 由 `**review_form_schema_id`/`schema_json`** 定义的 **评审侧**字段(多 `number` 维度、评语等);与报名表单 **分离** |
| 计分规则 | `**competitions.scoring_rules_json`**(可空=系统默认):定义 `**line_total**`(单条评审总分)及 `**team_sum`/`team_avg**`(队伍聚合)计算方式 |
| 计分规则 | `**competitions.scoring_rules_json`**(可空=系统默认):定义 `**line_total`**(单条评审总分)及 `**team_sum`/`team_avg**`(队伍聚合)计算方式 |
| `line_total` | 单条评审记录的总分,通常由多维度按权重自动算出并写入 `**payload_json**` |
| `team_sum` | 某报名下 **已提交评审** 的 `line_total` **求和** |
| `team_avg` | 某报名下 **已提交评审** 的 `line_total`**算术平均**;分母 = **已提交人数** |
@ -63,7 +63,7 @@
### 2.3 管理员Admin Users
- 登录管理后台:支持 **账号 + 密码** 与 **手机号 + 短信验证码** **两种方式**(可并存,具体策略如「首次强制改密」由实现约定)
- 经 **角色与权限** 控制菜单与接口RBAC 仅挂管理员);**侧栏与可访问路由**由服务端按权限返回菜单树、前端 **`router.addRoute`** 动态注册,与 **FR-S-05**、《技术选型与规范》**§3.4** 一致
- 经 **角色与权限** 控制菜单与接口RBAC 仅挂管理员);**侧栏与可访问路由**由服务端按权限返回菜单树、前端 `**router.addRoute`** 动态注册,与 **FR-S-05**、《技术选型与规范》**§3.4** 一致
- 使用 **赛事切换器** 将列表与操作限定在 **当前赛事**(除全局系统项外)
---
@ -75,7 +75,7 @@
**未触发**下文任一锁定条件时,选手 **可保存草稿、修改字段与附件,并可多次正式提交**(后一次提交覆盖当前已提交内容,状态仍以服务端为准)。**仅当**满足 **任一** 锁定条件时,**禁止**选手对报名表进行 **修改、保存草稿变更、上传/删除附件与再次提交**API 与前端均需拦截并提示一致文案):
1. **报名已截止**:当前时间晚于本场赛事配置的 **报名截止时间**(见 `competition.signup_close_at`**未配置截止时间** 时不在本条拦截,但仍可能因条件 2 锁定)。
2. **已被评分**:该 **报名记录** 已存在 **至少一条** 评审侧落库记录,表示 **已有评委评审/打分**产品口径与《数据结构说明》§3.7 一致;**cxxfds-service** 当前以 **`application_review_records`** 是否存在行判定;**远期**可与 **`application_review_scores`** 合并为以正式评分为准的唯一来源)。
2. **已被评分**:该 **报名记录** 已存在 **至少一条** 评审侧落库记录,表示 **已有评委评审/打分**产品口径与《数据结构说明》§3.7 一致;**cxxfds-service** 当前以 `**application_review_records`** 是否存在行判定;**远期**可与 `**application_review_scores`** 合并为以正式评分为准的唯一来源)。
> 草稿与已提交:在锁定前,**草稿保存与再次完整提交** 均允许;截止或已评分后与正式提交一并锁定。
@ -138,13 +138,13 @@
### 3.5 系统管理(后台)
| ID | 需求描述 | 优先级 |
| ------- | ------------------------ | --- |
| FR-S-01 | **选手管理**:列表、禁用、备注、关联报名查看 | 高 |
| FR-S-02 | **管理员账号** + **角色与权限** | 高 |
| FR-S-03 | **操作审计日志** | 中 |
| FR-S-04 | **系统参数**(上传限制、短信开关等) | 中 |
| FR-S-05 | **动态菜单与动态路由**:管理后台左侧菜单(含 **系统管理** 下子项)由登录后接口按当前管理员 **角色权限** 返回菜单树;前端 **Vue Router** 使用 **`addRoute`** 动态注册业务路由,与侧栏递归渲染一致;无权限路由不可通过直接输入 URL 绕过(前端守卫 + 后端鉴权) | 高 |
| ID | 需求描述 | 优先级 |
| ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- | --- |
| FR-S-01 | **选手管理**:列表、禁用、备注、关联报名查看 | 高 |
| FR-S-02 | **管理员账号** + **角色与权限** | 高 |
| FR-S-03 | **操作审计日志** | 中 |
| FR-S-04 | **系统参数**(上传限制、短信开关等) | 中 |
| FR-S-05 | **动态菜单与动态路由**:管理后台左侧菜单(含 **系统管理** 下子项)由登录后接口按当前管理员 **角色权限** 返回菜单树;前端 **Vue Router** 使用 `**addRoute`** 动态注册业务路由,与侧栏递归渲染一致;无权限路由不可通过直接输入 URL 绕过(前端守卫 + 后端鉴权) | 高 |
### 3.6 前台(选手端)
@ -195,7 +195,7 @@
- `reviewer_scopes``(reviewer_id, competition_id, track_code)` 唯一
- `track_code` 须与 `competition_tracks` 业务一致(应用层或约束)
- `**competitions`**`review_form_schema_id`、`scoring_rules_json` 均可选;**空配置** 时 **评审 Schema / 计分** 回退 **系统默认**(见《评审评分-自定义表单与计分规则.md》§24
- **评分表**(设计约定,名称示例 `application_review_scores``(application_id, reviewer_id)` **唯一**;存 `**review_schema_id`、`payload_json`(含 `line_total`** 及时间戳;可选 `**score`** 兼容单列查询。**产品口径**上用于判定 §2a.1「已被评分」。**实现注意**`cxxfds-service` 另见 **`application_review_records`**(仅存 `application_id` 等),与 §2a.1 条件 2 对齐;`application_review_scores` 落库后建议与之统一或合并判定,避免双源。不设「评审通过/驳回」状态列。详见《数据结构说明》**§3.7、§3.9**。
- **评分表**(设计约定,名称示例 `application_review_scores``(application_id, reviewer_id)` **唯一**;存 `**review_schema_id`、`payload_json`(含 `line_total`** 及时间戳;可选 `**score`** 兼容单列查询。**产品口径**上用于判定 §2a.1「已被评分」。**实现注意**`cxxfds-service` 另见 `**application_review_records`**(仅存 `application_id` 等),与 §2a.1 条件 2 对齐;`application_review_scores` 落库后建议与之统一或合并判定,避免双源。不设「评审通过/驳回」状态列。详见《数据结构说明》**§3.7、§3.9**。
- 详细表结构见《数据结构说明.md》与《后台管理-菜单与数据库设计.md》
---

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save