2026-08-26 16:20:55 +08:00

1758 lines
45 KiB
YAML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 本文件由 @asteasolutions/zod-to-openapi 从 packages/shared/src/schemas/*.schema.ts 的 zod schema 自动反推生成。
# 若修改字段/端点,请修改 zod schema 后重新运行 openapi 生成脚本(见 architecture.md §二 / §5.1),勿手改本文件。
# 契约与 zod schema、请求运行时校验、z.infer 类型三者同源,永不失同步。
openapi: 3.0.3
info:
title: 备考中枢 API公务员考试备考数据中枢
version: 1.0.0
description: >
个人单用户公务员备考工具 REST API。数据底层为本地 JSON 文件,但对外保持 REST
semantic资源化 + HTTP 动词 + 版本号)。统一响应 ApiResponse<T>code=0 成功,
code!=0 失败。全 TypeScript无 any。本契约由 zod-openapi 从 zod schema 自动生成,
前端据此生成 TS 类型orval / @hey-api/openapi-ts与 MSW Mock。
servers:
- url: http://localhost:3000
description: 本地开发
tags:
- name: questions
description: 题库(真题录入 / 管理 / 导入 / 导出)
- name: practice
description: 刷题(抽题 / 提交作答判定)
- name: wrong-questions
description: 错题本(自动入本 / 错因标签 / 恢复)
- name: mock-exams
description: 模考记录与分模块分析
- name: shenlun
description: 申论写作 / 自评
- name: tasks
description: 备考计划任务 / 打卡
- name: stats
description: 数据中枢统计聚合
- name: settings
description: 偏好设置(含 AI 开关)
- name: data
description: 数据资产(导出 / 备份 / 还原)
paths:
# ============ 题库 Questions ============
/api/v1/questions:
get:
tags: [questions]
summary: 题库列表(支持分页 / 按模块 / 关键字筛选)
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- name: module
in: query
schema:
$ref: '#/components/schemas/ModuleKey'
- name: subject
in: query
schema:
$ref: '#/components/schemas/SubjectKey'
- name: q
in: query
schema:
type: string
- name: sort
in: query
schema:
type: string
enum: [created_at, difficulty]
description: 排序字段
- name: order
in: query
schema:
type: string
enum: [asc, desc]
responses:
'200':
description: 分页列表
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionListResponse'
'400':
$ref: '#/components/responses/BadRequest'
post:
tags: [questions]
summary: 录入题(单题)
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionCreate'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionResponse'
'400':
$ref: '#/components/responses/BadRequest'
'422':
$ref: '#/components/responses/ValidationError'
/api/v1/questions/import:
post:
tags: [questions]
summary: 批量导入真题(数组)
requestBody:
required: true
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/QuestionCreate'
responses:
'201':
description: 导入结果
content:
application/json:
schema:
$ref: '#/components/schemas/ImportResponse'
'422':
$ref: '#/components/responses/ValidationError'
/api/v1/questions/export:
get:
tags: [questions]
summary: 导出题库JSON 全量)
responses:
'200':
description: 导出的题库 JSON
content:
application/json:
schema:
type: array
items:
$ref: '#/components/schemas/Question'
/api/v1/questions/{id}:
get:
tags: [questions]
summary: 题目详情
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 题目详情
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionResponse'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [questions]
summary: 更新题目
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/QuestionResponse'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [questions]
summary: 删除题目
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ 刷题 Practice ============
/api/v1/practice/draw:
post:
tags: [practice]
summary: 抽题(按模块 / 错题优先 / 随机)
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/DrawRequest'
responses:
'200':
description: 抽题结果(题目列表)
content:
application/json:
schema:
$ref: '#/components/schemas/DrawResponse'
'400':
$ref: '#/components/responses/BadRequest'
/api/v1/practice/submit:
post:
tags: [practice]
summary: 提交作答并判定(答错自动进错题本)
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitAnswerRequest'
responses:
'201':
description: 判定结果(含是否入错题本)
content:
application/json:
schema:
$ref: '#/components/schemas/SubmitAnswerResponse'
'400':
$ref: '#/components/responses/BadRequest'
'422':
$ref: '#/components/responses/ValidationError'
# ============ 错题本 WrongQuestions ============
/api/v1/wrong-questions:
get:
tags: [wrong-questions]
summary: 错题本列表(按模块 / 状态 / 错因筛选)
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- name: module
in: query
schema:
$ref: '#/components/schemas/ModuleKey'
- name: status
in: query
schema:
$ref: '#/components/schemas/WrongQuestionStatus'
- name: reason
in: query
schema:
$ref: '#/components/schemas/WrongReason'
responses:
'200':
description: 错题本分页
content:
application/json:
schema:
$ref: '#/components/schemas/WrongQuestionListResponse'
/api/v1/wrong-questions/{id}:
get:
tags: [wrong-questions]
summary: 错题详情
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 错题详情
content:
application/json:
schema:
$ref: '#/components/schemas/WrongQuestionResponse'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [wrong-questions]
summary: 更新错题(打错因标签 / 批注 / 状态)
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/WrongQuestionUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/WrongQuestionResponse'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
/api/v1/wrong-questions/{id}/resolve:
post:
tags: [wrong-questions]
summary: 标记错题已掌握(移除待复习清单)
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 更新状态为 mastered
content:
application/json:
schema:
$ref: '#/components/schemas/WrongQuestionResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ 模考 MockExams ============
/api/v1/mock-exams:
get:
tags: [mock-exams]
summary: 模考列表
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- name: examType
in: query
schema:
$ref: '#/components/schemas/ExamType'
responses:
'200':
description: 模考分页
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamListResponse'
post:
tags: [mock-exams]
summary: 录入模考成绩
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamCreate'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamResponse'
'422':
$ref: '#/components/responses/ValidationError'
/api/v1/mock-exams/{id}:
get:
tags: [mock-exams]
summary: 模考详情(含分模块分析)
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 模考详情
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamResponse'
'404':
$ref: '#/components/responses/NotFound'
patch:
tags: [mock-exams]
summary: 更新模考记录
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/MockExamResponse'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [mock-exams]
summary: 删除模考记录
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ 申论 ShenLun ============
/api/v1/shenlun:
get:
tags: [shenlun]
summary: 申论列表
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- name: module
in: query
schema:
$ref: '#/components/schemas/ShenLunModuleKey'
responses:
'200':
description: 申论分页
content:
application/json:
schema:
$ref: '#/components/schemas/ShenLunListResponse'
post:
tags: [shenlun]
summary: 新建申论写作
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ShenLunCreate'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/ShenLunResponse'
'422':
$ref: '#/components/responses/ValidationError'
/api/v1/shenlun/{id}:
patch:
tags: [shenlun]
summary: 更新申论(自评 / 正文)
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ShenLunUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/ShenLunResponse'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [shenlun]
summary: 删除申论
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ 备考计划 Tasks ============
/api/v1/tasks:
get:
tags: [tasks]
summary: 任务列表
parameters:
- $ref: '#/components/parameters/Page'
- $ref: '#/components/parameters/Limit'
- name: status
in: query
schema:
$ref: '#/components/schemas/TaskStatus'
- name: planDate
in: query
schema:
type: string
format: date
responses:
'200':
description: 任务分页
content:
application/json:
schema:
$ref: '#/components/schemas/TaskListResponse'
post:
tags: [tasks]
summary: 创建任务
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TaskCreate'
responses:
'201':
description: 创建成功
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'422':
$ref: '#/components/responses/ValidationError'
/api/v1/tasks/{id}:
patch:
tags: [tasks]
summary: 更新任务(状态 / 完成量 / 打卡)
parameters:
- $ref: '#/components/parameters/Id'
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/TaskUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/TaskResponse'
'400':
$ref: '#/components/responses/BadRequest'
'404':
$ref: '#/components/responses/NotFound'
delete:
tags: [tasks]
summary: 删除任务
parameters:
- $ref: '#/components/parameters/Id'
responses:
'200':
description: 删除成功
content:
application/json:
schema:
$ref: '#/components/schemas/DeleteResponse'
'404':
$ref: '#/components/responses/NotFound'
# ============ 统计 Stats ============
/api/v1/stats/overview:
get:
tags: [stats]
summary: 数据中枢总览(总答题数 / 正确率 / 错因分布 / 连续打卡)
responses:
'200':
description: 统计总览
content:
application/json:
schema:
$ref: '#/components/schemas/StatsOverviewResponse'
/api/v1/stats/daily:
get:
tags: [stats]
summary: 日粒度趋势(近 N 天)
parameters:
- name: days
in: query
schema:
type: integer
minimum: 1
maximum: 365
default: 30
responses:
'200':
description: 日趋势
content:
application/json:
schema:
$ref: '#/components/schemas/StatsDailyResponse'
/api/v1/stats/module:
get:
tags: [stats]
summary: 分模块表现(考点×错因归因输入)
responses:
'200':
description: 模块统计
content:
application/json:
schema:
$ref: '#/components/schemas/StatsModuleResponse'
/api/v1/stats/monthly-report:
get:
tags: [stats]
summary: 月报复盘
parameters:
- name: month
in: query
schema:
type: string
format: yyyy-MM
responses:
'200':
description: 月报
content:
application/json:
schema:
$ref: '#/components/schemas/StatsMonthlyResponse'
# ============ 设置 Settings ============
/api/v1/settings:
get:
tags: [settings]
summary: 获取偏好设置
responses:
'200':
description: 设置
content:
application/json:
schema:
$ref: '#/components/schemas/SettingsResponse'
patch:
tags: [settings]
summary: 更新偏好设置
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/SettingsUpdate'
responses:
'200':
description: 更新成功
content:
application/json:
schema:
$ref: '#/components/schemas/SettingsResponse'
'422':
$ref: '#/components/responses/ValidationError'
# ============ 数据资产 Data ============
/api/v1/data/export:
post:
tags: [data]
summary: 导出全部数据为备份 JSON
responses:
'200':
description: 备份 JSON含 schema 版本)
content:
application/json:
schema:
$ref: '#/components/schemas/BackupPayload'
get:
tags: [data]
summary: 导出指定实体为 CSV
parameters:
- name: entity
in: query
required: true
schema:
type: string
enum: [questions, wrong-questions, mock-exams, shenlun, tasks]
responses:
'200':
description: CSV 文本
content:
text/csv:
schema:
type: string
/api/v1/data/backup:
post:
tags: [data]
summary: 创建备份副本
responses:
'200':
description: 备份结果
content:
application/json:
schema:
$ref: '#/components/schemas/BackupResult'
/api/v1/data/restore:
post:
tags: [data]
summary: 从备份还原
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/BackupPayload'
responses:
'200':
description: 还原成功
content:
application/json:
schema:
$ref: '#/components/schemas/RestoreResult'
'400':
$ref: '#/components/responses/BadRequest'
'422':
$ref: '#/components/responses/ValidationError'
components:
parameters:
Id:
name: id
in: path
required: true
description: 实体 idUUID
schema:
type: string
format: uuid
Page:
name: page
in: query
schema:
type: integer
minimum: 1
default: 1
Limit:
name: limit
in: query
schema:
type: integer
minimum: 1
maximum: 200
default: 20
schemas:
# ---------- 枚举 ----------
SubjectKey:
type: string
enum: [xingce, shenlun]
ModuleKey:
type: string
enum:
- xingce-shuli
- xingce-panduan
- xingce-yanyu
- xingce-changshi
- xingce-ziliao
- shenlun-zhuizong
- shenlun-zonghe
- shenlun-shenlun
ShenLunModuleKey:
type: string
enum: [shenlun-zhuizong, shenlun-zonghe, shenlun-shenlun]
QuestionType:
type: string
enum: [single, multiple, judge, blank, essay]
Correctness:
type: string
enum: [correct, wrong, partial, blank]
WrongReason:
type: string
enum:
- knowledge-gap
- concept-confusion
- careless
- time-pressure
- method-unfamiliar
- calculation-error
- reading-error
WrongQuestionStatus:
type: string
enum: [open, resolved, mastered]
ExamType:
type: string
enum: [national, province, self]
TaskStatus:
type: string
enum: [todo, doing, done, skipped]
TaskRecurrence:
type: string
enum: [once, daily, weekly]
DayOfWeek:
type: string
enum: [mon, tue, wed, thu, fri, sat, sun]
# ---------- Question ----------
Question:
type: object
required: [id, subject, module, type, stem, answer, tags, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
subject:
$ref: '#/components/schemas/SubjectKey'
module:
$ref: '#/components/schemas/ModuleKey'
type:
$ref: '#/components/schemas/QuestionType'
stem:
type: string
minLength: 1
options:
type: array
items:
type: string
answer:
oneOf:
- type: string
- type: array
items:
type: string
analysis:
type: string
source:
type: string
difficulty:
type: integer
minimum: 1
maximum: 5
tags:
type: array
items:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
aiExplanation:
type: string
aiConfidence:
type: number
minimum: 0
maximum: 1
QuestionCreate:
allOf:
- $ref: '#/components/schemas/Question'
- type: object
properties:
id:
type: string
format: uuid
description: 可省略,服务端生成
QuestionUpdate:
type: object
minProperties: 1
properties:
stem:
type: string
minLength: 1
options:
type: array
items:
type: string
answer:
oneOf:
- type: string
- type: array
items:
type: string
analysis:
type: string
source:
type: string
difficulty:
type: integer
minimum: 1
maximum: 5
tags:
type: array
items:
type: string
module:
$ref: '#/components/schemas/ModuleKey'
QuestionResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/Question'
QuestionListResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/PageData-Question'
# ---------- Practice ----------
DrawRequest:
type: object
properties:
subject:
$ref: '#/components/schemas/SubjectKey'
module:
$ref: '#/components/schemas/ModuleKey'
count:
type: integer
minimum: 1
maximum: 50
default: 10
strategy:
type: string
enum: [random, module, wrong-first]
default: module
DrawResponse:
type: object
properties:
questions:
type: array
items:
$ref: '#/components/schemas/Question'
SubmitAnswerRequest:
type: object
required: [questionId, userAnswer, source]
properties:
questionId:
type: string
format: uuid
userAnswer:
oneOf:
- type: string
- type: array
items:
type: string
source:
type: string
enum: [practice, mock-exam]
tookMs:
type: integer
minimum: 0
wrongReasons:
type: array
items:
$ref: '#/components/schemas/WrongReason'
SubmitAnswerResponse:
type: object
properties:
questionId:
type: string
format: uuid
correctness:
$ref: '#/components/schemas/Correctness'
isWrong:
type: boolean
correctAnswer:
oneOf:
- type: string
- type: array
items:
type: string
enteredWrongBook:
type: boolean
wrongQuestionId:
type: string
format: uuid
nullable: true
# ---------- AnswerRecord作答记录驱动统计----------
AnswerRecord:
type: object
required: [id, questionId, module, correctness, isWrong, userAnswer, source, practiceDate, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
questionId:
type: string
format: uuid
module:
$ref: '#/components/schemas/ModuleKey'
correctness:
$ref: '#/components/schemas/Correctness'
isWrong:
type: boolean
userAnswer:
oneOf:
- type: string
- type: array
items:
type: string
wrongReasons:
type: array
items:
$ref: '#/components/schemas/WrongReason'
tookMs:
type: integer
minimum: 0
source:
type: string
enum: [practice, mock-exam]
practiceDate:
type: string
format: date-time
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
# ---------- WrongQuestion ----------
WrongQuestion:
type: object
required: [id, questionId, module, wrongReasons, wrongCount, lastWrongAt, reviewCount, status, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
questionId:
type: string
format: uuid
module:
$ref: '#/components/schemas/ModuleKey'
wrongReasons:
type: array
items:
$ref: '#/components/schemas/WrongReason'
wrongCount:
type: integer
minimum: 1
lastWrongAt:
type: string
format: date-time
reviewCount:
type: integer
minimum: 0
status:
$ref: '#/components/schemas/WrongQuestionStatus'
note:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
WrongQuestionUpdate:
type: object
minProperties: 1
properties:
wrongReasons:
type: array
items:
$ref: '#/components/schemas/WrongReason'
note:
type: string
status:
$ref: '#/components/schemas/WrongQuestionStatus'
reviewCount:
type: integer
minimum: 0
WrongQuestionResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/WrongQuestion'
WrongQuestionListResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/PageData-WrongQuestion'
# ---------- MockExam ----------
MockExam:
type: object
required: [id, title, examType, fullScore, score, durationMin, examDate, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
title:
type: string
examType:
$ref: '#/components/schemas/ExamType'
fullScore:
type: number
score:
type: number
rank:
type: integer
durationMin:
type: integer
minimum: 0
moduleScores:
type: object
additionalProperties:
type: number
moduleCorrectRate:
type: object
additionalProperties:
type: number
examDate:
type: string
format: date
note:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
MockExamCreate:
type: object
required: [title, examType, fullScore, score, durationMin, examDate]
properties:
title:
type: string
examType:
$ref: '#/components/schemas/ExamType'
fullScore:
type: number
score:
type: number
rank:
type: integer
durationMin:
type: integer
minimum: 0
moduleScores:
type: object
additionalProperties:
type: number
moduleCorrectRate:
type: object
additionalProperties:
type: number
examDate:
type: string
format: date
note:
type: string
MockExamUpdate:
type: object
minProperties: 1
properties:
title:
type: string
score:
type: number
rank:
type: integer
durationMin:
type: integer
minimum: 0
moduleScores:
type: object
additionalProperties:
type: number
moduleCorrectRate:
type: object
additionalProperties:
type: number
note:
type: string
MockExamResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/MockExam'
MockExamListResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/PageData-MockExam'
# ---------- ShenLun ----------
ShenLunEssay:
type: object
required: [id, topic, module, content, wordCount, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
examId:
type: string
format: uuid
topic:
type: string
module:
$ref: '#/components/schemas/ShenLunModuleKey'
content:
type: string
wordCount:
type: integer
minimum: 0
durationMin:
type: integer
minimum: 0
selfRating:
type: integer
minimum: 1
maximum: 5
aiFeedback:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
ShenLunCreate:
type: object
required: [topic, module, content]
properties:
examId:
type: string
format: uuid
topic:
type: string
module:
$ref: '#/components/schemas/ShenLunModuleKey'
content:
type: string
durationMin:
type: integer
minimum: 0
selfRating:
type: integer
minimum: 1
maximum: 5
ShenLunUpdate:
type: object
minProperties: 1
properties:
content:
type: string
durationMin:
type: integer
minimum: 0
selfRating:
type: integer
minimum: 1
maximum: 5
ShenLunResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/ShenLunEssay'
ShenLunListResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/PageData-ShenLunEssay'
# ---------- Task ----------
StudyTask:
type: object
required: [id, title, planDate, status, recurrence, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
title:
type: string
module:
$ref: '#/components/schemas/ModuleKey'
planDate:
type: string
format: date
status:
$ref: '#/components/schemas/TaskStatus'
recurrence:
$ref: '#/components/schemas/TaskRecurrence'
targetCount:
type: integer
minimum: 0
completedCount:
type: integer
minimum: 0
note:
type: string
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
TaskCreate:
type: object
required: [title, planDate, recurrence]
properties:
title:
type: string
module:
$ref: '#/components/schemas/ModuleKey'
planDate:
type: string
format: date
recurrence:
$ref: '#/components/schemas/TaskRecurrence'
targetCount:
type: integer
minimum: 0
note:
type: string
TaskUpdate:
type: object
minProperties: 1
properties:
title:
type: string
status:
$ref: '#/components/schemas/TaskStatus'
targetCount:
type: integer
minimum: 0
completedCount:
type: integer
minimum: 0
note:
type: string
TaskResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/StudyTask'
TaskListResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/PageData-StudyTask'
# ---------- Stats ----------
ModuleStat:
type: object
required: [module, total, correct, correctRate, wrong]
properties:
module:
$ref: '#/components/schemas/ModuleKey'
total:
type: integer
correct:
type: integer
correctRate:
type: number
wrong:
type: integer
StatsOverview:
type: object
properties:
totalAnswered:
type: integer
totalCorrect:
type: integer
totalWrong:
type: integer
overallCorrectRate:
type: number
practiceStreak:
type: integer
moduleStats:
type: array
items:
$ref: '#/components/schemas/ModuleStat'
wrongByReason:
type: object
additionalProperties:
type: integer
StatsDailyPoint:
type: object
properties:
date:
type: string
format: date
answered:
type: integer
correctRate:
type: number
StatsModuleGroup:
type: object
properties:
module:
$ref: '#/components/schemas/ModuleKey'
total:
type: integer
correct:
type: integer
wrong:
type: integer
correctRate:
type: number
wrongByReason:
type: object
additionalProperties:
type: integer
StatsMonthly:
type: object
properties:
month:
type: string
format: yyyy-MM
totalAnswered:
type: integer
totalCorrect:
type: integer
totalWrong:
type: integer
overallCorrectRate:
type: number
moduleStats:
type: array
items:
$ref: '#/components/schemas/ModuleStat'
wrongByReason:
type: object
additionalProperties:
type: integer
streakSummary:
type: object
properties:
maxStreak:
type: integer
currentStreak:
type: integer
StatsOverviewResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/StatsOverview'
StatsDailyResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/StatsDailyPoint'
StatsModuleResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
type: array
items:
$ref: '#/components/schemas/StatsModuleGroup'
StatsMonthlyResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/StatsMonthly'
# ---------- StatsSnapshot统计聚合快照持久化实体----------
StatsSnapshot:
type: object
required: [id, date, totalAnswered, totalCorrect, totalWrong, overallCorrectRate, moduleStats, wrongByReason, createdAt, updatedAt]
properties:
id:
type: string
format: uuid
date:
type: string
format: date
totalAnswered:
type: integer
totalCorrect:
type: integer
totalWrong:
type: integer
overallCorrectRate:
type: number
practiceStreak:
type: integer
moduleStats:
type: array
items:
$ref: '#/components/schemas/ModuleStat'
wrongByReason:
type: object
additionalProperties:
type: integer
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
# ---------- Settings ----------
AppSettings:
type: object
required: [id, uiTheme, aiEnabled, createdAt, updatedAt]
properties:
id:
type: string
enum: ['app']
targetScore:
type: number
dailyQuestionTarget:
type: integer
dailyStudyMinutes:
type: integer
uiTheme:
type: string
enum: [light, dark]
primaryColor:
type: string
aiEnabled:
type: boolean
createdAt:
type: string
format: date-time
updatedAt:
type: string
format: date-time
SettingsUpdate:
type: object
minProperties: 1
properties:
targetScore:
type: number
dailyQuestionTarget:
type: integer
dailyStudyMinutes:
type: integer
uiTheme:
type: string
enum: [light, dark]
aiEnabled:
type: boolean
SettingsResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
$ref: '#/components/schemas/AppSettings'
# ---------- Data 备份 ----------
BackupPayload:
type: object
required: [schemaVersion, exportedAt]
properties:
schemaVersion:
type: integer
exportedAt:
type: string
format: date-time
questions:
type: array
items:
$ref: '#/components/schemas/Question'
answerRecords:
type: array
items:
$ref: '#/components/schemas/AnswerRecord'
wrongQuestions:
type: array
items:
$ref: '#/components/schemas/WrongQuestion'
mockExams:
type: array
items:
$ref: '#/components/schemas/MockExam'
shenlun:
type: array
items:
$ref: '#/components/schemas/ShenLunEssay'
tasks:
type: array
items:
$ref: '#/components/schemas/StudyTask'
stats:
type: array
items:
$ref: '#/components/schemas/StatsSnapshot'
settings:
$ref: '#/components/schemas/AppSettings'
BackupResult:
type: object
properties:
backupId:
type: string
createdAt:
type: string
format: date-time
filePath:
type: string
RestoreResult:
type: object
properties:
restoredAt:
type: string
format: date-time
entities:
type: array
items:
type: string
preBackupId:
type: string
description: 还原前自动生成的一次备份 id
# ---------- 通用 ----------
DeleteResponse:
allOf:
- $ref: '#/components/schemas/ApiSuccess'
- type: object
properties:
data:
type: object
properties:
deleted:
type: boolean
id:
type: string
format: uuid
ImportResponse:
type: object
properties:
imported:
type: integer
skips:
type: array
items:
type: object
properties:
index:
type: integer
reason:
type: string
ApiSuccess:
type: object
required: [code, data]
properties:
code:
type: integer
enum: [0]
data:
description: 业务数据,由各响应的 data 属性具体定义
message:
type: string
ApiFailure:
type: object
required: [code, data, message]
properties:
code:
type: integer
description: 非 0 错误码
data:
type: object
nullable: true
message:
type: string
PageData-Question:
type: object
required: [items, total, page, limit, hasMore]
properties:
items:
type: array
items:
$ref: '#/components/schemas/Question'
total:
type: integer
page:
type: integer
limit:
type: integer
hasMore:
type: boolean
PageData-WrongQuestion:
type: object
required: [items, total, page, limit, hasMore]
properties:
items:
type: array
items:
$ref: '#/components/schemas/WrongQuestion'
total:
type: integer
page:
type: integer
limit:
type: integer
hasMore:
type: boolean
PageData-MockExam:
type: object
required: [items, total, page, limit, hasMore]
properties:
items:
type: array
items:
$ref: '#/components/schemas/MockExam'
total:
type: integer
page:
type: integer
limit:
type: integer
hasMore:
type: boolean
PageData-ShenLunEssay:
type: object
required: [items, total, page, limit, hasMore]
properties:
items:
type: array
items:
$ref: '#/components/schemas/ShenLunEssay'
total:
type: integer
page:
type: integer
limit:
type: integer
hasMore:
type: boolean
PageData-StudyTask:
type: object
required: [items, total, page, limit, hasMore]
properties:
items:
type: array
items:
$ref: '#/components/schemas/StudyTask'
total:
type: integer
page:
type: integer
limit:
type: integer
hasMore:
type: boolean
responses:
BadRequest:
description: 请求参数错误
content:
application/json:
schema:
$ref: '#/components/schemas/ApiFailure'
ValidationError:
description: 校验失败422 不可处理)
content:
application/json:
schema:
$ref: '#/components/schemas/ApiFailure'
NotFound:
description: 资源不存在
content:
application/json:
schema:
$ref: '#/components/schemas/ApiFailure'