# 志愿通当前接口文档 ## 1 文档范围 本文档描述当前 Spring Boot 服务中已经实现并通过实库验证的接口,包括: - 数据审核台接口 `/api/**` - P0 考生端公共接口 `/api/v1/**` - 数据发布与版本切换接口 `/api/admin/v1/publications/**` 本文档不包含规划中但尚未实现的院校推荐、专业详情、用户、收藏和志愿表接口。 ## 2 基本约定 ### 2.1 服务地址 本地开发地址: ```text http://127.0.0.1:8080 ``` 前端开发环境通过 Vite 将 `/api` 代理到该地址。 ### 2.2 数据格式 - 请求和响应编码:UTF-8 - JSON 请求头:`Content-Type: application/json` - 时间口径:`Asia/Shanghai` - 审核台 SQL 查询结果主要使用 `snake_case` - P0 公共接口和发布校验接口使用 `camelCase` - 全局配置不输出值为 `null` 的字段,因此部分可选字段可能不出现在 JSON 中 ### 2.3 当前安全状态 当前服务尚未接入登录、角色和权限校验。以下写接口和管理接口只能部署在受控内网环境: - `PUT /api/reviews/{entityType}/{entityKey}` - `/api/admin/v1/**` 正式开放公网前必须增加管理员认证、角色权限、操作审计和接口限流。 ### 2.4 通用错误 业务参数错误通常返回 HTTP 400: ```json { "message": "year 必须在 2000 到 2100 之间" } ``` 请求参数类型错误或 Bean Validation 校验失败由 Spring Boot 返回 HTTP 400,响应中通常包含: ```json { "timestamp": "2026-09-06T10:00:00+08:00", "status": 400, "error": "Bad Request", "message": "...", "path": "/api/..." } ``` 未处理异常返回 HTTP 500。当前数据详情不存在时实现上返回 HTTP 400,而不是 HTTP 404。 ## 3 接口总览 | 分类 | 方法 | 路径 | 说明 | | --- | --- | --- | --- | | 系统 | GET | `/api/health` | 服务健康检查 | | 审核台 | GET | `/api/dashboard` | 数据规模、覆盖和审核总览 | | 审核台 | GET | `/api/metadata` | 查询筛选项和数据集元数据 | | 审核台 | GET | `/api/collection-scopes` | 查询各省各年度采集范围 | | 审核台 | GET | `/api/data/{dataset}` | 通用数据集分页查询 | | 审核台 | GET | `/api/data/{dataset}/{id}` | 通用数据详情 | | 审核台 | PUT | `/api/reviews/{entityType}/{entityKey}` | 提交审核结论 | | 审核台 | GET | `/api/reviews/{entityType}/{entityKey}/history` | 查询审核历史 | | P0 公共 | GET | `/api/v1/meta/admission-contexts` | 查询省份招录上下文与数据可用性 | | P0 公共 | GET | `/api/v1/score-ranks/convert` | 分数与位次互换 | | 发布管理 | GET | `/api/admin/v1/publications/datasets` | 查询支持发布校验的数据集 | | 发布管理 | POST | `/api/admin/v1/publications/validate` | 执行只读发布前质量门禁 | | 发布管理 | GET | `/api/admin/v1/publications` | 查询发布历史和当前版本 | | 发布管理 | POST | `/api/admin/v1/publications` | 创建不可变公共快照 | | 发布管理 | POST | `/api/admin/v1/publications/{id}/publish` | 切换当前版本或回滚 | | 发布管理 | POST | `/api/admin/v1/publications/{id}/withdraw` | 撤回版本 | ## 4 系统接口 ### 4.1 健康检查 ```http GET /api/health ``` 响应示例: ```json { "status": "ok", "service": "志愿通数据审核后台" } ``` 该接口只表示 Web 服务能够响应,不代表所有数据集均已审核或具备发布条件。 ## 5 审核台接口 ### 5.1 数据总览 ```http GET /api/dashboard ``` 响应字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `schools` | number | 院校主档记录数 | | `gansuSchools` | number | 甘肃省院校数 | | `groups` | number | 院校专业组总数 | | `majorPlans` | number | 专业招生计划总数 | | `majorLines` | number | 专业录取线总数 | | `cutoffLines` | number | 院校或专业组投档线总数 | | `scorePoints` | number | 2025 年一分一段记录数 | | `controlLines` | number | 2025 年控制线记录数 | | `unmatchedCutoffLines` | number | 未匹配稳定院校 ID 的投档线数 | | `pendingReviews` | number | 尚未形成终态审核结论的记录数 | | `cutoffBreakdown` | array | 按科类、层次和段次汇总的投档线统计 | | `coverage` | array | 2025 年各省各数据集覆盖与缺口 | | `reviewStats` | array | 按审核状态汇总的记录数 | `cutoffBreakdown` 元素字段: ```text subject_category, education_level, segment_code, record_count, matched_count, min_score, max_score ``` `coverage` 元素字段: ```text province_name, dataset_name, subject_category, segment_code, coverage_status, record_count, notes ``` ### 5.2 筛选元数据 ```http GET /api/metadata ``` 响应字段: | 字段 | 类型 | 说明 | | --- | --- | --- | | `provinces` | string[] | 院校主档中出现的省级地区 | | `educationLevels` | string[] | 院校培养层次 | | `ownershipTypes` | string[] | 公办、民办等办学性质 | | `subjects` | string[] | 招录数据中的原始科类值 | | `controlLineLevels` | string[] | 控制线层次 | | `segments` | string[] | 原始批次或段次值 | | `categories` | string[] | 招生类别 | | `reviewStatuses` | string[] | 审核状态枚举 | | `admissionYears` | number[] | 已建档年份,当前为 2022 至 2026 | | `datasets` | string[] | 通用数据查询支持的数据集代码 | 审核状态: | 值 | 含义 | | --- | --- | | `pending` | 待审核,或尚无 `review_records` 记录 | | `approved` | 已通过 | | `needs_review` | 需要复核 | | `rejected` | 已驳回 | ### 5.3 省份年度采集范围 ```http GET /api/collection-scopes ``` 当前接口返回全部省份和全部建档年份,不支持分页和筛选。 响应元素字段: | 字段 | 说明 | | --- | --- | | `collection_scope_id` | 采集范围主键 | | `province_name` | 招生省份 | | `admission_year` | 招生年度 | | `collection_status` | `not_collected`、`partial`、`collected` 或 `verified` | | `priority_level` | `low`、`normal` 或 `high` | | `status_note` | 数据范围和缺口说明 | | `first_collected_at` | 首次采集时间 | | `last_collected_at` | 最近采集时间 | | `batch_count` | 批次规则记录数 | | `plan_release_count` | 招生计划发布批次数 | | `group_count` | 院校专业组数 | | `major_plan_count` | 专业招生计划数 | | `major_line_count` | 专业录取线数 | | `score_point_count` | 一分一段记录数 | | `control_line_count` | 控制线记录数 | | `cutoff_line_count` | 投档线记录数 | | `coverage_item_count` | 覆盖说明记录数 | ### 5.4 通用分页查询 ```http GET /api/data/{dataset} ``` 通用查询参数: | 参数 | 必填 | 默认值 | 说明 | | --- | --- | --- | --- | | `page` | 否 | `1` | 页码,服务端限制为 1 至 100000 | | `size` | 否 | `20` | 每页数量,服务端限制为 1 至 200 | | `keyword` | 否 | - | 模糊搜索;部分数据集不支持 | | `reviewStatus` | 否 | - | `pending`、`approved`、`needs_review`、`rejected` | | `sort` | 否 | 数据集默认排序 | 只接受各数据集声明的排序代码 | | `direction` | 否 | `desc` | 只有 `asc` 表示升序,其他值均按降序处理 | | `minScore` | 否 | - | 仅分数类数据集生效 | | `maxScore` | 否 | - | 仅分数类数据集生效 | 分页响应: ```json { "items": [], "total": 94, "page": 1, "size": 20, "totalPages": 5 } ``` 每条记录都会附加以下审核字段;没有值时可能省略: ```text review_status, reviewer_name, review_note, reviewed_at ``` #### 5.4.1 `schools` 全国院校 - `entityType`:`school` - 关键词搜索:院校名称、教育部代码、城市、主管部门 - 筛选参数:`province`、`educationLevel`、`ownership`、`schoolStatus` - 排序代码:`name`、`province`、`updatedAt` - 主要字段:`school_id`、`moe_school_code`、`official_name`、`province_name`、`city_name`、`authority_name`、`education_level`、`ownership_type`、`school_status`、`official_website`、`admission_website`、`first_seen_year`、`last_seen_year`、`source_title`、`source_url` 示例: ```http GET /api/data/schools?page=1&size=20&province=北京市&keyword=大学&sort=name&direction=asc ``` #### 5.4.2 `groups` 院校专业组 - `entityType`:`admission_group` - 关键词搜索:院校名称、院校代号、专业组代码、专业组名称 - 筛选参数:`province`、`subject`、`segment`、`category`、`year`、`matched` - 排序代码:`school`、`segment`、`groupCode` - `matched=true` 表示已匹配 `school_id`,`matched=false` 表示未匹配 - 主要字段:`admission_group_id`、`admission_year`、`admission_category`、`subject_category`、`batch_name`、`segment_code`、`source_school_code`、`school_name_raw`、`group_code`、`group_name`、`school_id`、`moe_school_code`、`source_title`、`source_url` #### 5.4.3 `major-plans` 专业招生计划 - `entityType`:`major_plan` - 关键词搜索:院校名称、院校代号、专业名称、专业代号、备注 - 筛选参数:`province`、`subject`、`segment`、`category`、`year` - 排序代码:`school`、`major`、`planCount` - 主要字段:`major_plan_id`、`admission_year`、`admission_category`、`subject_category`、`batch_name`、`segment_code`、`source_school_code`、`school_name_raw`、`group_code`、`major_code`、`major_name`、`subject_requirements`、`plan_count`、`tuition_yuan_per_year`、`study_years`、`campus_name`、`notes`、`source_row_number`、`source_title`、`source_url` #### 5.4.4 `major-admissions` 专业录取线 - `entityType`:`major_admission` - 关键词搜索:院校名称、院校代号、专业组、专业名称、专业代码、专业备注 - 筛选参数:`province`、`subject`、`segment`、`educationLevel`、`category`、`year`、`matched` - 分数参数:`minScore`、`maxScore`,作用于 `min_score` - 排序代码:`score`、`rank`、`school`、`major` - 主要字段:`major_line_id`、`admission_year`、`admission_category`、`subject_category`、`education_level`、`batch_name`、`source_school_code`、`school_name_raw`、`group_code`、`major_code`、`major_name`、`major_note`、`subject_requirements`、`min_score`、`min_rank`、`max_score`、`avg_score`、`admit_count`、`school_province`、`school_nature`、`is_985`、`is_211`、`school_id`、`moe_school_code`、`source_row_number`、`source_title`、`source_url` #### 5.4.5 `score-ranks` 一分一段 - `entityType`:`score_rank` - 不支持关键词搜索 - 筛选参数:`province`、`subject`、`year` - 分数参数:`minScore`、`maxScore`,作用于 `score` - 排序代码:`score`、`rank` - 主要字段:`score_rank_id`、`admission_year`、`admission_category`、`subject_category`、`score`、`same_score_count`、`cumulative_count`、`rank_from`、`rank_to`、`source_title`、`source_url` #### 5.4.6 `control-lines` 省级控制线 - `entityType`:`control_line` - 关键词搜索:备注 - 筛选参数:`province`、`subject`、`educationLevel`、`category`、`year` - 分数参数:`minScore`、`maxScore`,作用于 `culture_score` - 排序代码:`score`、`level` - 主要字段:`control_line_id`、`admission_year`、`admission_category`、`subject_category`、`education_level`、`culture_score`、`professional_score`、`notes`、`source_title`、`source_url` #### 5.4.7 `cutoff-lines` 院校或专业组投档线 - `entityType`:`cutoff_line` - 关键词搜索:院校名称、院校代号、专业组代码、专业组名称 - 筛选参数:`province`、`subject`、`segment`、`educationLevel`、`category`、`year`、`matched` - 分数参数:`minScore`、`maxScore`,作用于 `cutoff_score` - 排序代码:`score`、`school`、`groupCode` - 主要字段:`cutoff_line_id`、`admission_year`、`admission_category`、`subject_category`、`education_level`、`batch_name`、`segment_code`、`source_school_code`、`school_name_raw`、`group_code`、`group_name`、`cutoff_score`、`cutoff_rank`、`control_score`、`score_diff`、`admit_count`、`school_province`、`school_nature`、同分排序项、`volunteer_number`、`school_id`、`moe_school_code`、`source_title`、`source_url` 同分排序项字段: ```text raw_total_score, chinese_math_sum, chinese_or_math_max, foreign_language_score, first_choice_subject_score, second_choice_subject_max, second_choice_subject_second ``` #### 5.4.8 `batches` 招生批次与段次 - `entityType`:`admission_batch` - 关键词搜索:批次名称、段次代码 - 筛选参数:`province`、`segment`、`educationLevel`、`category`、`year` - 排序代码:`segment`、`level` - 主要字段:`admission_batch_id`、`admission_year`、`admission_category`、`education_level`、`segment_code`、`batch_name`、`volunteer_mode`、`max_group_volunteers`、`max_majors_per_group`、`solicitation_count`、`source_title`、`source_url` #### 5.4.9 `releases` 招生计划发布批次 - `entityType`:`plan_release` - 关键词搜索:发布标题、计划轮次 - 筛选参数:`province`、`year`、`coverageStatus` - `coverageStatus` 实际匹配数据库字段 `coverage_scope` - 排序代码:`publishedOn`、`title` - 主要字段:`plan_release_id`、`admission_year`、`release_title`、`plan_round`、`coverage_scope`、`published_on`、`plan_count`、`source_title`、`source_url` #### 5.4.10 `sources` 数据来源档案 - `entityType`:`data_source` - 关键词搜索:发布机构、标题、SHA-256 - 筛选参数:`sourceType` - 排序代码:`publishedOn`、`publisher` - 主要字段:`source_id`、`source_type`、`publisher`、`title`、`landing_page_url`、`file_url`、`published_on`、`retrieved_at`、`sha256`、`raw_file_path`、`notes` #### 5.4.11 `coverage` 数据覆盖与缺口 - `entityType`:`dataset_coverage` - 关键词搜索:数据集名称、缺口说明 - 筛选参数:`province`、`coverageStatus`、`subject`、`segment`、`year` - 排序代码:`dataset`、`count` - 主要字段:`coverage_id`、`dataset_name`、`admission_year`、`admission_category`、`subject_category`、`segment_code`、`coverage_status`、`record_count`、`notes`、`source_title`、`source_url` 覆盖状态: | 值 | 含义 | | --- | --- | | `complete_public_snapshot` | 当前公开来源中的完整快照 | | `partial_public_snapshot` | 仅有部分公开数据或关键字段缺失 | | `unavailable_publicly` | 暂未取得公开全量数据 | ### 5.5 通用数据详情 ```http GET /api/data/{dataset}/{id} ``` 返回对应数据集的完整列表字段、审核字段以及: ```json { "review_history": [] } ``` 当 `dataset=schools` 时额外返回: - `external_codes`:省级招生代码和外部代码映射 - `campuses`:校区、地址、坐标核验状态等信息 路径中的 `id` 和 `entityKey` 应进行 URL 编码。 ### 5.6 提交审核结论 ```http PUT /api/reviews/{entityType}/{entityKey} Content-Type: application/json ``` 支持的 `entityType`: ```text school admission_group major_plan major_admission score_rank control_line cutoff_line admission_batch plan_release data_source dataset_coverage ``` 请求体: ```json { "status": "approved", "reviewer": "reviewer-001", "note": "已与考试院原始公告核对" } ``` 字段约束: | 字段 | 必填 | 说明 | | --- | --- | --- | | `status` | 是 | `pending`、`approved`、`needs_review` 或 `rejected` | | `reviewer` | 是 | 审核人员姓名或账号标识,不能为空 | | `note` | 否 | 审核说明 | 响应示例: ```json { "reviewId": 123, "entityType": "score_rank", "entityKey": "456", "status": "approved" } ``` 该操作会覆盖当前审核结论,同时向 `review_audit_logs` 追加不可覆盖的历史记录。 ### 5.7 审核历史 ```http GET /api/reviews/{entityType}/{entityKey}/history ``` 响应元素字段: ```text review_log_id, previous_status, new_status, reviewer_name, review_note, created_at ``` 结果按操作时间倒序排列。 ## 6 P0 公共接口 ### 6.1 省份招录上下文 ```http GET /api/v1/meta/admission-contexts ``` 查询参数: | 参数 | 必填 | 默认值 | 说明 | | --- | --- | --- | --- | | `year` | 否 | `2025` | 招生年度,允许 2000 至 2100 | | `province` | 否 | - | 省份全称;不传时返回该年度所有建档省份 | 示例: ```http GET /api/v1/meta/admission-contexts?year=2025&province=河北省 ``` 响应示例: ```json { "year": 2025, "items": [ { "province": "河北省", "collectionStatus": "collected", "examMode": "three_plus_one_plus_two", "examModeSource": "verified_publication", "dataVersion": "2025.exam-mode.v1", "publishedAt": "2026-09-06T01:12:00", "sourcePublisher": "中华人民共和国教育部", "sourceTitle": "对十三届全国人大二次会议第5836号建议的答复", "sourceUrl": "https://www.moe.gov.cn/", "subjects": [ { "code": "HISTORY", "name": "历史类", "sourceValues": ["历史类"] }, { "code": "PHYSICS", "name": "物理类", "sourceValues": ["物理类"] } ], "groupCount": 0, "majorPlanCount": 0, "majorAdmissionCount": 0, "scoreRankCount": 0, "controlLineCount": 0, "cutoffLineCount": 0, "warnings": [ "尚未发布一分一段,暂不支持分数位次转换", "尚未发布省级控制线", "尚未发布院校或专业组投档线", "尚未发布专业录取线" ] } ] } ``` `examMode` 当前可能值: | 值 | 含义 | | --- | --- | | `three_plus_one_plus_two` | 3+1+2 | | `three_plus_three` | 3+3 | | `traditional` | 传统文理科 | | `unknown` | 配置异常或尚未配置;正常已发布记录不会返回该值 | 当前 `examModeSource` 固定为 `verified_publication`。接口只读取 `public_province_exam_configs` 的当前发布版本,不再根据一分一段科类推断考试模式。 `dataVersion` 和 `publishedAt` 用于定位具体配置快照;来源字段用于核验追溯。 各项数量表示已经发布到公共读模型中的记录数,不是内部审核业务表的原始记录数。 当数据缺失时,`warnings` 可能包含: ```text 该省份当前为部分采集或未采集状态 尚未发布一分一段,暂不支持分数位次转换 尚未发布省级控制线 尚未发布院校或专业组投档线 尚未发布专业录取线 ``` ### 6.2 分数与位次转换 ```http GET /api/v1/score-ranks/convert ``` 查询参数: | 参数 | 必填 | 默认值 | 说明 | | --- | --- | --- | --- | | `province` | 是 | - | 省份全称 | | `year` | 否 | `2025` | 招生年度 | | `admissionCategory` | 否 | `普通类` | 招生类别,必须与来源数据一致 | | `subject` | 是 | - | 原始科类名称或标准科类代码 | | `score` | 条件必填 | - | 分数;与 `rank` 必须且只能提供一个 | | `rank` | 条件必填 | - | 位次,必须大于 0;与 `score` 必须且只能提供一个 | 当前标准科类代码: | 代码 | 标准名称 | 可识别来源值示例 | | --- | --- | --- | | `PHYSICS` | 物理类 | 物理类、物理科目组合 | | `HISTORY` | 历史类 | 历史类、历史科目组合 | | `SCIENCE` | 理科 | 理科、理工类 | | `ARTS` | 文科 | 文科、文史类 | | `COMPREHENSIVE` | 综合 | 综合、不分科类 | | `VOCATIONAL` | 中职升学 | 中职升学 | 分数转位次: ```http GET /api/v1/score-ranks/convert?province=河北省&year=2025&admissionCategory=普通类&subject=PHYSICS&score=650 ``` 响应示例: ```json { "province": "河北省", "year": 2025, "admissionCategory": "普通类", "subjectCode": "PHYSICS", "subjectName": "物理类", "sourceSubject": "物理类", "queryType": "score", "requestedValue": 650, "score": 650.0, "rankFrom": 3106, "rankTo": 3294, "sameScoreCount": 189, "cumulativeCount": 3294, "sourceTitle": "河北省2025年一分一段", "sourceUrl": "https://example.gov.cn/score-ranks/2025", "dataVersion": "2025.1", "publishedAt": "2026-09-10T10:00:00" } ``` 位次转分数: ```http GET /api/v1/score-ranks/convert?province=河北省&year=2025&admissionCategory=普通类&subject=PHYSICS&rank=3106 ``` 转换规则: - 分数查询要求一分一段中存在精确分数,当前不自动取临近分数。 - 位次查询使用闭区间 `rankFrom <= rank <= rankTo`。 - `rankFrom` 是该分数的最佳位次,`rankTo` 是该分数的最末位次。 - 科类标准代码会解析为该省该年实际存在的来源科类值。 - 如果同一标准科类对应多个来源值,传入接口实际返回的 `sourceSubject` 最明确。 - 查询只使用 `current_dataset_publications` 指向的 `public_score_rank_points` 快照。 - 当前尚未发布任何一分一段版本;完成审核和发布后该接口才返回转换结果。 常见错误: ```json { "message": "score 和 rank 必须且只能提供一个" } ``` ```json { "message": "当前省份和年份尚未发布一分一段公共版本" } ``` ```json { "message": "一分一段中没有该精确分数" } ``` ## 7 发布与版本管理接口 ### 7.1 支持的数据集 ```http GET /api/admin/v1/publications/datasets ``` 响应: ```json [ "control-lines", "groups", "major-plans", "major-admissions", "score-ranks", "cutoff-lines", "province-exam-configs" ] ``` 返回顺序不应作为前端业务逻辑依据。 ### 7.2 发布前质量门禁 ```http POST /api/admin/v1/publications/validate Content-Type: application/json ``` 该接口只读,不会创建发布版本,也不会修改审核状态。 请求体: ```json { "province": "河北省", "year": 2025, "dataset": "score-ranks" } ``` 字段约束: | 字段 | 必填 | 说明 | | --- | --- | --- | | `province` | 是 | 省份全称,不能为空 | | `year` | 是 | 2000 至 2100 | | `dataset` | 是 | 必须来自支持的数据集接口 | 响应示例: ```json { "province": "河北省", "year": 2025, "dataset": "score-ranks", "sourceRecordCount": 1088, "publishableRecordCount": 0, "blockedRecordCount": 1088, "unapprovedRecordCount": 1088, "unmatchedSchoolCount": 0, "invalidRecordCount": 0, "qualityGrade": "A", "passed": false, "issues": [ { "code": "UNAPPROVED_RECORDS", "severity": "error", "affectedRecords": 1088, "message": "存在尚未通过人工审核的记录" } ] } ``` 字段说明: | 字段 | 说明 | | --- | --- | | `sourceRecordCount` | 指定省份、年份、数据集的源记录总数 | | `publishableRecordCount` | 已审核通过且满足结构质量条件的记录数 | | `blockedRecordCount` | 当前不能发布的记录数 | | `unapprovedRecordCount` | 未处于 `approved` 状态的记录数 | | `unmatchedSchoolCount` | 未匹配稳定 `school_id` 的记录数;无院校维度的数据集恒为 0 | | `invalidRecordCount` | 关键字段缺失或数值无效的记录数 | | `qualityGrade` | 结构质量等级 A、B、C、D,不包含人工审核进度 | | `passed` | 只有存在数据且全部记录均可发布时为 `true` | | `issues` | 阻断原因列表 | 当前问题代码: | 代码 | 严重级别 | 说明 | | --- | --- | --- | | `DATASET_EMPTY` | fatal | 指定范围没有数据 | | `UNAPPROVED_RECORDS` | error | 存在未审核通过记录 | | `UNMATCHED_SCHOOLS` | error | 存在未匹配稳定院校 ID 的记录 | | `INVALID_KEY_FIELDS` | error | 查询或推荐所需关键字段无效 | 质量等级与 `passed` 是两个不同概念。例如数据结构可以评为 A,但如果尚未经过人工审核,`passed` 仍为 `false`。 ### 7.3 查询发布版本 ```http GET /api/admin/v1/publications?province=河北省&year=2025&dataset=province-exam-configs ``` 三个查询参数均可省略。响应中的 `current=true` 表示该版本是当前公共查询实际使用的版本。 ### 7.4 创建公共快照 ```http POST /api/admin/v1/publications Content-Type: application/json ``` ```json { "province": "河北省", "year": 2025, "dataset": "score-ranks", "version": "2025.1", "publisher": "data-admin" } ``` 创建操作会重新执行质量门禁。只有全部记录通过时才创建 `draft` 版本,并把已审核记录复制到对应的不可变公共快照表;创建版本不会自动切换线上当前版本。 当前可生成快照的数据集: - `province-exam-configs` → `public_province_exam_configs` - `score-ranks` → `public_score_rank_points` - `cutoff-lines` → `public_school_admission_stats` - `major-admissions` → `public_major_admission_stats` ### 7.5 发布、回滚与撤回 ```http POST /api/admin/v1/publications/{publicationId}/publish?publisher=data-admin ``` 该操作把版本状态改为 `published`,并原子替换同一省份、年份、数据集的当前版本指针。把历史 `published` 版本再次调用本接口即可回滚。 ```http POST /api/admin/v1/publications/{publicationId}/withdraw?publisher=data-admin ``` 撤回当前版本时会同时删除当前指针,公共接口随即停止读取该版本。已撤回版本不能重新发布,需要创建新版本。 发布版本响应的主要字段: ```text publicationId, province, year, dataset, version, status, sourceRecordCount, publishedRecordCount, qualityGrade, current, publishedBy, publishedAt, createdAt ``` ## 8 PowerShell 调用示例 查询河北 2025 招录上下文: ```powershell Invoke-RestMethod ` -Uri 'http://127.0.0.1:8080/api/v1/meta/admission-contexts?year=2025&province=河北省' ``` 分数转位次: ```powershell Invoke-RestMethod ` -Uri 'http://127.0.0.1:8080/api/v1/score-ranks/convert?province=河北省&year=2025&subject=PHYSICS&score=650' ``` 执行发布校验: ```powershell $body = @{ province = '河北省' year = 2025 dataset = 'score-ranks' } | ConvertTo-Json Invoke-RestMethod ` -Method Post ` -Uri 'http://127.0.0.1:8080/api/admin/v1/publications/validate' ` -ContentType 'application/json; charset=utf-8' ` -Body $body ``` ## 9 当前接口限制 1. 尚无 OpenAPI 或 Swagger 页面,本文档与代码同步维护。 2. 尚无统一响应包装,审核台和 P0 接口命名风格不同。 3. 尚未实现认证授权,审核和管理接口不可直接暴露公网。 4. 审核台通用数据接口仍直接查询内部业务表;P0 公共接口已经与其隔离,只读当前公共版本。 5. 目前仅考试模式已经发布;一分一段、投档线和专业录取线仍需逐条审核后才能生成公共版本。 6. 分数转换只支持精确分数,不做插值和临近值匹配。 7. 数据详情不存在时当前返回 400,后续应改为 404。 8. 当前没有接口版本化的审核台路由,后续计划迁移至 `/api/admin/v1/**`。 ## 10 后续文档维护规则 新增或修改接口时,应同步更新: - 路径和 HTTP 方法 - 请求参数与默认值 - 请求和响应示例 - 枚举值 - 错误条件 - 鉴权要求 - 数据来源、审核状态和质量限制 下一阶段接入 Springdoc OpenAPI 后,应以自动生成的 OpenAPI 描述作为字段级契约,本文档保留业务说明、调用示例和重要限制。