From 720b508a2f069ffaeac71c15ab9d639252b09bd9 Mon Sep 17 00:00:00 2001 From: lion <120344285@qq.com> Date: Mon, 11 May 2026 14:13:04 +0800 Subject: [PATCH] =?UTF-8?q?=E6=8F=90=E4=BA=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/技术选型与规范.md | 2 +- docs/数据结构说明.md | 120 +- docs/评审评分-自定义表单与计分规则.md | 14 +- docs/需求规格说明书.md | 22 +- public/index.html | 2113 +++++++++++++++++++++++++ 5 files changed, 2194 insertions(+), 77 deletions(-) create mode 100644 public/index.html diff --git a/docs/技术选型与规范.md b/docs/技术选型与规范.md index 5fc7bce..87c700f 100644 --- a/docs/技术选型与规范.md +++ b/docs/技术选型与规范.md @@ -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`、数据库、宝塔部署等。) \ No newline at end of file diff --git a/docs/数据结构说明.md b/docs/数据结构说明.md index 59b3a2b..ddb9517 100644 --- a/docs/数据结构说明.md +++ b/docs/数据结构说明.md @@ -7,14 +7,14 @@ ## 一、文档关系 -| 内容 | 所在文档 § | -| ------------------------------- | --------------------------- | +| 内容 | 所在文档 § | +| ------------------------------------------------------- | ------------------------------------- | | 评审打分 Schema、计分规则、`line_total` / `team_sum` / `team_avg` | 《评审评分-自定义表单与计分规则.md》;本文 **§3.7、§3.9** | -| 报名数据存储、Schema 与表关系(是否每字段一表) | 本文 **§3.8** | -| 全表字段表、外键一览、**Mermaid ER 图(中文)** | 《后台管理-菜单与数据库设计》**§2.2~2.3** | -| 与本文 §3.8 对应的精简条目(DDL 文档内) | 《后台管理-菜单与数据库设计》**§2.0** | -| 多端品牌 JSON 示例 | 《后台管理-菜单与数据库设计》**第五节** | -| 管理端侧栏菜单、动态路由与权限锚点 | 《后台管理-菜单与数据库设计》**§1.1**;本文 **§3.5** | +| 报名数据存储、Schema 与表关系(是否每字段一表) | 本文 **§3.8** | +| 全表字段表、外键一览、**Mermaid ER 图(中文)** | 《后台管理-菜单与数据库设计》**§2.2~2.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** 对齐,可提供接口草稿后增补「接口 ↔ 表字段映射」一节。 \ No newline at end of file diff --git a/docs/评审评分-自定义表单与计分规则.md b/docs/评审评分-自定义表单与计分规则.md index 1542fdd..bd55d41 100644 --- a/docs/评审评分-自定义表单与计分规则.md +++ b/docs/评审评分-自定义表单与计分规则.md @@ -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** diff --git a/docs/需求规格说明书.md b/docs/需求规格说明书.md index 42c1924..1b5cbb2 100644 --- a/docs/需求规格说明书.md +++ b/docs/需求规格说明书.md @@ -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》§2~4) -- **评分表**(设计约定,名称示例 `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》 --- diff --git a/public/index.html b/public/index.html new file mode 100644 index 0000000..2836060 --- /dev/null +++ b/public/index.html @@ -0,0 +1,2113 @@ + + + + + + 2026江苏省新消费创新创业大赛 + + + +
+ + +
+
+
+ +
+ +

+ 江苏省新消费 + 创新创业大赛 +

+
+

主办单位:江苏省商务厅、共青团江苏省委

+

支持单位:省科技厅、省工业和信息化厅、省民政厅、省财政厅、省人力资源社会保障厅、省农业农村厅、省文化和旅游厅、省卫生健康委、省市场监管局、省广电集团

+

承办单位:元禾控股

+

战略合作单位:抖音电商、抖音生活服务

+
+
+
+ +
+ +
+
+
+
+
TRACKS
+

主题赛道

+
+
+
+ 01 +
+
特色消费
+

宠物经济、新国货与悦己消费、地标产品与老字号创新、汽车后市场服务等

+
+
+
+ 02 +
+
健康消费
+

医疗美容、减重与健康管理、运动与康复、科技与中医药、心理健康服务产业

+
+
+
+ 03 +
+
商文旅农融合
+

文旅IP创新、商业空间与首发经济、特色民宿与乡村旅游、文化创意空间、数字文娱、网络视听等

+
+
+
+ 04 +
+
消费+人工智能
+

智能消费硬件、数字消费、AI 内容创作等

+
+
+
+
+
+
+ +
+
+
+
+
GUIDE
+

参赛指南

+
+ +
+
+ 1 +

参赛报名

+

2026年6月-7月

+
+
+ 2 +

线上初赛

+

2026年8月

+
+
+ 3 +

线下复赛

+

2026年8月至9月

+
+ 苏州 + 徐州 + 镇江 + 南京 +
+
+
+ 4 +

总决赛

+

2026年10月

+
+
+ +
+
+

一等奖 1名

+ 10万元 +

现金奖励 + 最高500万股权投资支持

+
+
+

二等奖 4名

+ 5万元 +

现金奖励 + 最高500万股权投资支持

+
+
+

三等奖 15名

+ 2万元 +

现金奖励 + 最高500万股权投资支持

+
+
+ +
+
参赛项目应符合新消费产业发展政策导向,具有明确的市场需求和商业化前景,且不存在知识产权纠纷。
+
创业组参赛企业设立时间需不超过5年。
+
+
+
+
+
+ + +
+ + +