openapi: "3.0.0" info: title: "Survey System API" version: "1.1.0" components: securitySchemes: AdminBearerAuth: type: http scheme: bearer bearerFormat: JWT schemas: User: type: object required: ["id", "name", "phone", "createdAt"] properties: id: type: string name: type: string phone: type: string createdAt: type: string format: date-time AdminUserView: type: object required: ["id", "name", "phone", "createdAt", "password"] properties: id: type: string name: type: string phone: type: string createdAt: type: string format: date-time password: type: string description: "密码 (敏感字段;前端掩码显示)" groupIds: type: array items: type: string description: "所属用户组ID列表" UserGroup: type: object required: ["id", "name", "createdAt"] properties: id: type: string name: type: string description: type: string isSystem: type: boolean createdAt: type: string format: date-time memberCount: type: integer description: "成员数量" QuestionCategory: type: object required: ["id", "name", "createdAt"] properties: id: type: string name: type: string createdAt: type: string format: date-time Question: type: object required: ["content", "type", "answer", "score"] properties: content: type: string type: type: string enum: ["single", "multiple", "judgment", "text"] category: type: string description: "题目类别名称,缺省为通用" default: "通用" options: type: array items: type: string answer: oneOf: - type: string - type: array items: type: string score: type: number ExamSubject: type: object required: ["id", "name", "totalScore", "timeLimitMinutes", "typeRatios", "categoryRatios"] properties: id: type: string name: type: string totalScore: type: integer timeLimitMinutes: type: integer default: 60 typeRatios: type: object additionalProperties: false properties: single: type: number multiple: type: number judgment: type: number text: type: number categoryRatios: type: object additionalProperties: type: number ExamTask: type: object required: ["id", "name", "subjectId", "startAt", "endAt"] properties: id: type: string name: type: string subjectId: type: string startAt: type: string format: date-time endAt: type: string format: date-time selectionConfig: type: string description: "JSON string storing original selection of userIds and groupIds" Pagination: type: object required: ["page", "limit", "total", "pages"] properties: page: type: integer limit: type: integer total: type: integer pages: type: integer paths: /api/users: post: summary: "创建用户或登录" requestBody: required: true content: application/json: schema: type: object required: ["name", "phone", "password"] properties: name: type: string description: "用户姓名,2-20位中英文" phone: type: string description: "手机号" password: type: string description: "登录密码" responses: "200": description: "User created" /api/users/{id}: get: summary: "获取用户信息" parameters: - name: "id" in: "path" required: true schema: type: string responses: "200": description: "User details" /api/questions/import: post: summary: "Excel导入题目" requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary responses: "200": description: "Import result" /api/questions: get: summary: "获取题目列表" parameters: - name: "type" in: query schema: type: string enum: ["single", "multiple", "judgment", "text"] - name: "category" in: query schema: type: string - name: "page" in: query schema: type: integer - name: "limit" in: query schema: type: integer responses: "200": description: "List of questions" post: summary: "添加单题" requestBody: content: application/json: schema: $ref: "#/components/schemas/Question" responses: "200": description: "Question created" /api/questions/{id}: put: summary: "更新题目" parameters: - name: "id" in: "path" required: true schema: type: string requestBody: content: application/json: schema: $ref: "#/components/schemas/Question" responses: "200": description: "Question updated" delete: summary: "删除题目" parameters: - name: "id" in: "path" required: true schema: type: string responses: "200": description: "Question deleted" /api/quiz/generate: post: summary: "生成随机试卷" requestBody: content: application/json: schema: type: object required: ["userId", "subjectId"] properties: userId: type: string subjectId: type: string description: "考试科目ID" responses: "200": description: "Generated quiz" /api/quiz/submit: post: summary: "提交答题" requestBody: content: application/json: schema: type: object required: ["userId", "answers"] properties: userId: type: string answers: type: array items: type: object responses: "200": description: "Submission result" /api/quiz/records/{userId}: get: summary: "获取用户答题记录" parameters: - name: "userId" in: "path" required: true schema: type: string responses: "200": description: "User quiz records" /api/quiz/records/detail/{recordId}: get: summary: "获取答题记录详情" parameters: - name: "recordId" in: path required: true schema: type: string responses: "200": description: "Record detail" /api/admin/login: post: summary: "管理员登录" requestBody: content: application/json: schema: type: object required: ["username", "password"] properties: username: type: string password: type: string responses: "200": description: "Login success" /api/admin/statistics: get: summary: "获取统计数据" responses: "200": description: "Statistics data" /api/admin/users: get: summary: "获取用户列表 (管理员)" security: - AdminBearerAuth: [] parameters: - name: "page" in: query schema: type: integer - name: "limit" in: query schema: type: integer - name: "keyword" in: query schema: type: string description: "搜索关键词(姓名/手机)" responses: "200": description: "User list" post: summary: "创建用户 (管理员)" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: ["name", "phone", "password"] properties: name: type: string phone: type: string password: type: string groupIds: type: array items: type: string responses: "200": description: "User created" delete: summary: "删除用户 (管理员)" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: ["userId"] properties: userId: type: string responses: "200": description: "Deleted" /api/admin/users/{id}: put: summary: "更新用户 (管理员)" security: - AdminBearerAuth: [] parameters: - name: "id" in: "path" required: true schema: type: string requestBody: required: true content: application/json: schema: type: object properties: name: type: string phone: type: string password: type: string groupIds: type: array items: type: string responses: "200": description: "User updated" /api/admin/user-groups: get: summary: "获取用户组列表" security: - AdminBearerAuth: [] responses: "200": description: "Group list" post: summary: "创建用户组" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: ["name"] properties: name: type: string description: type: string responses: "200": description: "Group created" /api/admin/user-groups/{id}: put: summary: "更新用户组" security: - AdminBearerAuth: [] parameters: - name: "id" in: "path" required: true schema: type: string requestBody: required: true content: application/json: schema: type: object properties: name: type: string description: type: string responses: "200": description: "Group updated" delete: summary: "删除用户组" security: - AdminBearerAuth: [] parameters: - name: "id" in: "path" required: true schema: type: string responses: "200": description: "Group deleted" /api/admin/user-groups/{id}/members: get: summary: "获取用户组成员" security: - AdminBearerAuth: [] parameters: - name: "id" in: "path" required: true schema: type: string responses: "200": description: "Group members" /api/admin/users/export: get: summary: "导出用户 (管理员)" security: - AdminBearerAuth: [] responses: "200": description: "Export users" /api/admin/users/import: post: summary: "导入用户 (管理员)" security: - AdminBearerAuth: [] requestBody: content: multipart/form-data: schema: type: object properties: file: type: string format: binary responses: "200": description: "Import users" /api/admin/users/{userId}/records: get: summary: "获取用户历史答题记录 (管理员)" security: - AdminBearerAuth: [] parameters: - name: userId in: path required: true schema: type: string responses: "200": description: "User records" /api/admin/question-categories: get: summary: "获取题目类别列表 (管理员)" security: - AdminBearerAuth: [] responses: "200": description: "Category list" post: summary: "新增题目类别 (管理员)" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: ["name"] properties: name: type: string responses: "200": description: "Created" /api/admin/question-categories/{id}: put: summary: "更新题目类别 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string requestBody: required: true content: application/json: schema: type: object required: ["name"] properties: name: type: string responses: "200": description: "Updated" delete: summary: "删除题目类别 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string responses: "200": description: "Deleted" /api/admin/subjects: get: summary: "获取考试科目列表 (管理员)" security: - AdminBearerAuth: [] responses: "200": description: "Subjects" post: summary: "新增考试科目 (管理员)" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExamSubject" responses: "200": description: "Created" /api/admin/subjects/{id}: put: summary: "更新考试科目 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string requestBody: required: true content: application/json: schema: $ref: "#/components/schemas/ExamSubject" responses: "200": description: "Updated" delete: summary: "删除考试科目 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string responses: "200": description: "Deleted" /api/subjects: get: summary: "获取考试科目列表 (用户)" responses: "200": description: "Subjects" /api/admin/tasks: get: summary: "获取考试任务列表 (管理员)" security: - AdminBearerAuth: [] responses: "200": description: "Tasks" post: summary: "新增考试任务并分派用户 (管理员)" security: - AdminBearerAuth: [] requestBody: required: true description: "Create task with mixed selection of users and groups (system handles de-duplication)" content: application/json: schema: type: object required: ["name", "subjectId", "startAt", "endAt"] properties: name: type: string subjectId: type: string startAt: type: string format: date-time endAt: type: string format: date-time userIds: type: array items: type: string groupIds: type: array items: type: string responses: "200": description: "Created" /api/admin/tasks/{id}: put: summary: "更新考试任务 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string requestBody: required: true description: "Update task with mixed selection (system handles de-duplication)" content: application/json: schema: type: object properties: name: type: string subjectId: type: string startAt: type: string format: date-time endAt: type: string format: date-time userIds: type: array items: type: string groupIds: type: array items: type: string responses: "200": description: "Updated" delete: summary: "删除考试任务 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string responses: "200": description: "Deleted" /api/admin/tasks/{id}/report: get: summary: "导出任务报表 (管理员)" security: - AdminBearerAuth: [] parameters: - name: id in: path required: true schema: type: string responses: "200": description: "Task report" /api/admin/config: get: summary: "获取抽题配置" responses: "200": description: "Quiz config" put: summary: "更新抽题配置" requestBody: content: application/json: schema: type: object responses: "200": description: "Config updated" /api/admin/configs: get: summary: "获取所有系统配置" security: - AdminBearerAuth: [] responses: "200": description: "All configs" /api/admin/password: put: summary: "修改管理员密码" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object required: ["oldPassword", "newPassword"] properties: oldPassword: type: string newPassword: type: string responses: "200": description: "Password updated" /api/admin/export/{type}: get: summary: "通用数据导出" description: "type: users, questions, records, answers" security: - AdminBearerAuth: [] parameters: - name: "type" in: "path" required: true schema: type: string enum: ["users", "questions", "records", "answers"] responses: "200": description: "JSON export data" /api/admin/restore: post: summary: "数据恢复" security: - AdminBearerAuth: [] requestBody: required: true content: application/json: schema: type: object properties: users: type: array questions: type: array records: type: array answers: type: array responses: "200": description: "Data restored" /api/exam-tasks/user/{userId}: get: summary: "获取指定用户的考试任务" parameters: - name: "userId" in: "path" required: true schema: type: string responses: "200": description: "User tasks" /api/admin/tasks/{id}/users: get: summary: "获取任务分派的用户" security: - AdminBearerAuth: [] parameters: - name: "id" in: "path" required: true schema: type: string responses: "200": description: "Task users" /api/admin/active-tasks: get: summary: "获取当前活跃任务统计" security: - AdminBearerAuth: [] responses: "200": description: "Active tasks stats" /api/users/validate: post: summary: "验证用户信息(用于导入校验)" requestBody: content: application/json: schema: type: object required: ["phone"] properties: phone: type: string name: type: string responses: "200": description: "Validation result" /api/users/name/{name}: get: summary: "根据姓名查找用户" security: - AdminBearerAuth: [] parameters: - name: "name" in: "path" required: true schema: type: string responses: "200": description: "Users found"