Skip to content

Latest commit

 

History

History
990 lines (808 loc) · 20.2 KB

File metadata and controls

990 lines (808 loc) · 20.2 KB

报名申请闭环 API 示例

本文档提供当前“报名申请最小闭环”的请求与响应示例,便于本地联调、接口测试和前后端对接。

相关流程说明见:

  • docs/enrollment-application-flow.md

1. 通用说明

基础路径

当前接口统一挂载在:

/api

Content-Type

请求体统一使用:

Content-Type: application/json

当前安全策略

当前阶段接口默认放行,用于本地联调:

  • 不要求登录
  • 不要求令牌
  • 不要求 CSRF Token

后续接入正式权限模型后,接口访问方式可能调整。

2. 创建学员

请求

POST /api/students
Content-Type: application/json
{
  "name": "张三",
  "gender": "MALE",
  "idCardNo": "110101199001010011",
  "phone": "13800000001",
  "email": "zhangsan@example.com",
  "birthday": "1990-01-01",
  "address": "北京市朝阳区建国路 88 号",
  "emergencyContactName": "李四",
  "emergencyContactPhone": "13900000001",
  "desiredLicenseType": "C1",
  "sourceChannel": "ONLINE",
  "remarks": "首次咨询后直接建档"
}

成功响应

{
  "id": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "studentNo": "STU20260520191001",
  "name": "张三",
  "gender": "MALE",
  "idCardNo": "110101199001010011",
  "phone": "13800000001",
  "email": "zhangsan@example.com",
  "birthday": "1990-01-01",
  "address": "北京市朝阳区建国路 88 号",
  "emergencyContactName": "李四",
  "emergencyContactPhone": "13900000001",
  "desiredLicenseType": "C1",
  "status": "REGISTERED",
  "sourceChannel": "ONLINE",
  "remarks": "首次咨询后直接建档"
}

说明

  • 若身份证号或手机号已存在,服务会复用现有学员档案。
  • 当前返回值中会直接返回复用后的学员信息。

3. 创建报名申请

请求

POST /api/enrollment-applications
Content-Type: application/json
{
  "student": {
    "name": "张三",
    "gender": "MALE",
    "idCardNo": "110101199001010011",
    "phone": "13800000001",
    "email": "zhangsan@example.com",
    "birthday": "1990-01-01",
    "address": "北京市朝阳区建国路 88 号",
    "emergencyContactName": "李四",
    "emergencyContactPhone": "13900000001",
    "desiredLicenseType": "C1",
    "sourceChannel": "ONLINE",
    "remarks": "线上自主报名"
  },
  "licenseType": "C1",
  "trainingType": "周末班",
  "intendedStartDate": "2026-06-01",
  "preferredCoachGender": "FEMALE",
  "medicalDeclaration": true,
  "notes": "希望安排周末训练"
}

成功响应

{
  "id": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "applicationNo": "APP20260520191230",
  "status": "SUBMITTED",
  "submitTime": "2026-05-20T19:12:30",
  "licenseType": "C1",
  "trainingType": "周末班",
  "intendedStartDate": "2026-06-01",
  "preferredCoachGender": "FEMALE",
  "medicalDeclaration": true,
  "notes": "希望安排周末训练",
  "student": {
    "id": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
    "studentNo": "STU20260520191001",
    "name": "张三",
    "gender": "MALE",
    "idCardNo": "110101199001010011",
    "phone": "13800000001",
    "email": "zhangsan@example.com",
    "birthday": "1990-01-01",
    "address": "北京市朝阳区建国路 88 号",
    "emergencyContactName": "李四",
    "emergencyContactPhone": "13900000001",
    "desiredLicenseType": "C1",
    "status": "UNDER_REVIEW",
    "sourceChannel": "ONLINE",
    "remarks": "线上自主报名"
  }
}

说明

  • 创建申请后,学员状态会同步变为 UNDER_REVIEW
  • 一个学员允许存在多次报名申请。

4. 查询报名申请列表

请求

GET /api/enrollment-applications

成功响应

[
  {
    "id": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
    "applicationNo": "APP20260520191230",
    "status": "SUBMITTED",
    "submitTime": "2026-05-20T19:12:30",
    "licenseType": "C1",
    "trainingType": "周末班",
    "intendedStartDate": "2026-06-01",
    "preferredCoachGender": "FEMALE",
    "medicalDeclaration": true,
    "notes": "希望安排周末训练",
    "student": {
      "id": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
      "studentNo": "STU20260520191001",
      "name": "张三",
      "gender": "MALE",
      "idCardNo": "110101199001010011",
      "phone": "13800000001",
      "email": "zhangsan@example.com",
      "birthday": "1990-01-01",
      "address": "北京市朝阳区建国路 88 号",
      "emergencyContactName": "李四",
      "emergencyContactPhone": "13900000001",
      "desiredLicenseType": "C1",
      "status": "UNDER_REVIEW",
      "sourceChannel": "ONLINE",
      "remarks": "线上自主报名"
    }
  }
]

5. 查询报名申请详情

请求

GET /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d

成功响应

{
  "id": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "applicationNo": "APP20260520191230",
  "status": "SUBMITTED",
  "submitTime": "2026-05-20T19:12:30",
  "licenseType": "C1",
  "trainingType": "周末班",
  "intendedStartDate": "2026-06-01",
  "preferredCoachGender": "FEMALE",
  "medicalDeclaration": true,
  "notes": "希望安排周末训练",
  "student": {
    "id": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
    "studentNo": "STU20260520191001",
    "name": "张三",
    "gender": "MALE",
    "idCardNo": "110101199001010011",
    "phone": "13800000001",
    "email": "zhangsan@example.com",
    "birthday": "1990-01-01",
    "address": "北京市朝阳区建国路 88 号",
    "emergencyContactName": "李四",
    "emergencyContactPhone": "13900000001",
    "desiredLicenseType": "C1",
    "status": "UNDER_REVIEW",
    "sourceChannel": "ONLINE",
    "remarks": "线上自主报名"
  }
}

6. 新增审核记录

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/reviews
Content-Type: application/json
{
  "reviewStage": "INITIAL",
  "result": "APPROVED",
  "reviewerName": "审核员A",
  "comments": "资料完整,符合报名条件",
  "missingItemsSummary": null
}

成功响应

{
  "id": "7189bfe6-5e9f-4720-a53f-e3a25fd4d54f",
  "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "reviewStage": "INITIAL",
  "result": "APPROVED",
  "reviewerName": "审核员A",
  "reviewTime": "2026-05-20T19:15:45",
  "comments": "资料完整,符合报名条件",
  "missingItemsSummary": null,
  "applicationStatus": "APPROVED"
}

审核结果示例

审核通过

{
  "reviewStage": "INITIAL",
  "result": "APPROVED",
  "reviewerName": "审核员A",
  "comments": "资料完整,符合报名条件",
  "missingItemsSummary": null
}

对应申请状态:APPROVED

审核拒绝

{
  "reviewStage": "INITIAL",
  "result": "REJECTED",
  "reviewerName": "审核员B",
  "comments": "身份证信息与提交资料不一致",
  "missingItemsSummary": null
}

对应申请状态:REJECTED

要求补件

{
  "reviewStage": "INITIAL",
  "result": "REQUIRES_SUPPLEMENT",
  "reviewerName": "审核员C",
  "comments": "请补充居住证明",
  "missingItemsSummary": "缺少居住证明扫描件"
}

对应申请状态:MATERIAL_PENDING

6. 新增材料元数据

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/materials
Content-Type: application/json
{
  "materialType": "PHOTO",
  "fileName": "photo.jpg",
  "storagePath": "/files/photo.jpg",
  "contentType": "image/jpeg",
  "fileSize": 1024
}

成功响应

{
  "id": "c184652c-fdd7-476f-a1a8-b4a1d75e8ef0",
  "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "materialType": "PHOTO",
  "fileName": "photo.jpg",
  "storagePath": "/files/photo.jpg",
  "contentType": "image/jpeg",
  "fileSize": 1024,
  "status": "UPLOADED",
  "uploadedAt": "2026-05-20T20:10:00",
  "rejectionReason": null
}

7. 查询材料列表

请求

GET /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/materials

成功响应

[
  {
    "id": "c184652c-fdd7-476f-a1a8-b4a1d75e8ef0",
    "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
    "materialType": "PHOTO",
    "fileName": "photo.jpg",
    "storagePath": "/files/photo.jpg",
    "contentType": "image/jpeg",
    "fileSize": 1024,
    "status": "UPLOADED",
    "uploadedAt": "2026-05-20T20:10:00",
    "rejectionReason": null
  }
]

8. 审核单份材料

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/materials/c184652c-fdd7-476f-a1a8-b4a1d75e8ef0/review
Content-Type: application/json
{
  "result": "REJECTED",
  "rejectionReason": "照片不清晰,请重新上传"
}

成功响应

{
  "id": "c184652c-fdd7-476f-a1a8-b4a1d75e8ef0",
  "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "materialType": "PHOTO",
  "fileName": "photo.jpg",
  "storagePath": "/files/photo.jpg",
  "contentType": "image/jpeg",
  "fileSize": 1024,
  "status": "REJECTED",
  "uploadedAt": "2026-05-20T20:10:00",
  "rejectionReason": "照片不清晰,请重新上传"
}

9. 查询材料完整性

请求

GET /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/materials/validation

成功响应

{
  "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "applicationStatus": "MATERIAL_PENDING",
  "readyForReview": false,
  "missingMaterialTypes": [
    "ID_CARD_BACK",
    "MEDICAL_CERTIFICATE"
  ],
  "rejectedMaterialTypes": [
    "PHOTO"
  ],
  "message": "缺少必需材料: [ID_CARD_BACK, MEDICAL_CERTIFICATE]"
}

10. 审核通过前材料不完整

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/reviews
Content-Type: application/json
{
  "reviewStage": "INITIAL",
  "result": "APPROVED",
  "reviewerName": "审核员A",
  "comments": "尝试通过"
}

响应

{
  "message": "缺少必需材料: [ID_CARD_BACK, MEDICAL_CERTIFICATE]"
}

12. 生成系统文档

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/documents
Content-Type: application/json
{
  "documentType": "ENROLLMENT_FORM",
  "filePath": "/docs/enrollment-form.pdf",
  "templateVersion": "v1",
  "remarks": "报名表生成成功"
}

成功响应

{
  "id": "bd58f527-7c37-4952-a46d-11ab21ae5797",
  "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "documentType": "ENROLLMENT_FORM",
  "documentNo": "DOC20260520203030",
  "filePath": "/docs/enrollment-form.pdf",
  "templateVersion": "v1",
  "generationStatus": "GENERATED",
  "generatedAt": "2026-05-20T20:30:30",
  "remarks": "报名表生成成功"
}

13. 查询申请下文档列表

请求

GET /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/documents

成功响应

[
  {
    "id": "bd58f527-7c37-4952-a46d-11ab21ae5797",
    "applicationId": "85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d",
    "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
    "documentType": "ENROLLMENT_FORM",
    "documentNo": "DOC20260520203030",
    "filePath": "/docs/enrollment-form.pdf",
    "templateVersion": "v1",
    "generationStatus": "GENERATED",
    "generatedAt": "2026-05-20T20:30:30",
    "remarks": "报名表生成成功"
  }
]

14. 审核未通过时生成文档失败

请求

POST /api/enrollment-applications/85d14bc5-b4fb-46dc-ae37-c1cf7dc7940d/documents
Content-Type: application/json
{
  "documentType": "ENROLLMENT_FORM",
  "filePath": "/docs/enrollment-form.pdf"
}

响应

{
  "message": "只有审核通过的申请才能生成文档"
}

16. 分配教练

请求

POST /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/coach-assignments
Content-Type: application/json
{
  "coachId": "a8b4d8dd-3d8e-48f0-8e39-17877d6e2783",
  "assignmentType": "MANUAL",
  "reason": "人工分配就近教练",
  "operatorName": "管理员A"
}

成功响应

{
  "id": "bc4061f7-85dc-4507-8d7b-aa4ed40a9362",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "coachId": "a8b4d8dd-3d8e-48f0-8e39-17877d6e2783",
  "coachName": "王教练",
  "assignmentType": "MANUAL",
  "status": "ACTIVE",
  "assignedAt": "2026-05-20T21:10:00",
  "endedAt": null,
  "reason": "人工分配就近教练",
  "operatorName": "管理员A"
}

17. 查询当前有效教练分配

请求

GET /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/coach-assignments/current

成功响应

{
  "id": "bc4061f7-85dc-4507-8d7b-aa4ed40a9362",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "coachId": "a8b4d8dd-3d8e-48f0-8e39-17877d6e2783",
  "coachName": "王教练",
  "assignmentType": "MANUAL",
  "status": "ACTIVE",
  "assignedAt": "2026-05-20T21:10:00",
  "endedAt": null,
  "reason": "人工分配就近教练",
  "operatorName": "管理员A"
}

18. 结束教练分配

请求

POST /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/coach-assignments/bc4061f7-85dc-4507-8d7b-aa4ed40a9362/end

成功响应

{
  "id": "bc4061f7-85dc-4507-8d7b-aa4ed40a9362",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "coachId": "a8b4d8dd-3d8e-48f0-8e39-17877d6e2783",
  "coachName": "王教练",
  "assignmentType": "MANUAL",
  "status": "ENDED",
  "assignedAt": "2026-05-20T21:10:00",
  "endedAt": "2026-05-20T21:30:00",
  "reason": "人工分配就近教练",
  "operatorName": "管理员A"
}

19. 教练准教车型不匹配

响应

{
  "message": "教练准教车型与学员目标驾照类型不匹配"
}

21. 初始化学习进度

请求

POST /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/training-progress
Content-Type: application/json
{
  "currentStage": "SUBJECT_ONE",
  "subjectOneStatus": "IN_PROGRESS",
  "subjectTwoStatus": "NOT_STARTED",
  "subjectThreeStatus": "NOT_STARTED",
  "subjectFourStatus": "NOT_STARTED",
  "completedHours": 12,
  "lastTrainingDate": "2026-05-20",
  "remarks": "完成初始进度建档"
}

成功响应

{
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "currentStage": "SUBJECT_ONE",
  "subjectOneStatus": "IN_PROGRESS",
  "subjectTwoStatus": "NOT_STARTED",
  "subjectThreeStatus": "NOT_STARTED",
  "subjectFourStatus": "NOT_STARTED",
  "completedHours": 12,
  "lastTrainingDate": "2026-05-20",
  "remarks": "完成初始进度建档"
}

22. 查询学习进度

请求

GET /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/training-progress

成功响应

{
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "currentStage": "SUBJECT_ONE",
  "subjectOneStatus": "IN_PROGRESS",
  "subjectTwoStatus": "NOT_STARTED",
  "subjectThreeStatus": "NOT_STARTED",
  "subjectFourStatus": "NOT_STARTED",
  "completedHours": 12,
  "lastTrainingDate": "2026-05-20",
  "remarks": "完成初始进度建档"
}

23. 更新学习进度

请求

POST /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/training-progress/update
Content-Type: application/json
{
  "currentStage": "SUBJECT_TWO",
  "subjectOneStatus": "COMPLETED",
  "subjectTwoStatus": "IN_PROGRESS",
  "subjectThreeStatus": "NOT_STARTED",
  "subjectFourStatus": "NOT_STARTED",
  "completedHours": 24,
  "lastTrainingDate": "2026-05-21",
  "remarks": "推进到科目二"
}

成功响应

{
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "currentStage": "SUBJECT_TWO",
  "subjectOneStatus": "COMPLETED",
  "subjectTwoStatus": "IN_PROGRESS",
  "subjectThreeStatus": "NOT_STARTED",
  "subjectFourStatus": "NOT_STARTED",
  "completedHours": 24,
  "lastTrainingDate": "2026-05-21",
  "remarks": "推进到科目二"
}

24. 学员状态不允许维护进度

响应

{
  "message": "当前学员状态不允许维护学习进度"
}

25. 创建考试报名

请求

POST /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/exam-registrations
Content-Type: application/json
{
  "subjectType": "SUBJECT_ONE",
  "examDate": "2026-06-01T09:00:00",
  "examLocation": "第一考场",
  "remarks": "预约科目一考试"
}

成功响应

{
  "id": "e5594438-d6d1-4d15-bbf3-9c02e6380846",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "subjectType": "SUBJECT_ONE",
  "examDate": "2026-06-01T09:00:00",
  "examLocation": "第一考场",
  "attemptNo": 1,
  "status": "REGISTERED",
  "registeredAt": "2026-05-20T21:40:00",
  "remarks": "预约科目一考试"
}

26. 查询考试报名历史

请求

GET /api/students/0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25/exam-registrations

成功响应

[
  {
    "id": "e5594438-d6d1-4d15-bbf3-9c02e6380846",
    "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
    "subjectType": "SUBJECT_ONE",
    "examDate": "2026-06-01T09:00:00",
    "examLocation": "第一考场",
    "attemptNo": 1,
    "status": "REGISTERED",
    "registeredAt": "2026-05-20T21:40:00",
    "remarks": "预约科目一考试"
  }
]

27. 取消考试报名

请求

POST /api/exam-registrations/e5594438-d6d1-4d15-bbf3-9c02e6380846/cancel

成功响应

{
  "id": "e5594438-d6d1-4d15-bbf3-9c02e6380846",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "subjectType": "SUBJECT_ONE",
  "examDate": "2026-06-01T09:00:00",
  "examLocation": "第一考场",
  "attemptNo": 1,
  "status": "CANCELLED",
  "registeredAt": "2026-05-20T21:40:00",
  "remarks": "预约科目一考试"
}

28. 学习进度未完成时报名失败

响应

{
  "message": "当前科目学习进度未完成,不能报名考试"
}

29. 录入考试成绩

请求

POST /api/exam-registrations/e5594438-d6d1-4d15-bbf3-9c02e6380846/result
Content-Type: application/json
{
  "subjectType": "SUBJECT_ONE",
  "score": 92,
  "resultStatus": "PASSED",
  "examTime": "2026-06-01T10:00:00",
  "evaluatorName": "考官A",
  "failureReason": null
}

成功响应

{
  "id": "b9f7e8db-d2d1-4cd1-8c31-e6ef687920a8",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "examRegistrationId": "e5594438-d6d1-4d15-bbf3-9c02e6380846",
  "subjectType": "SUBJECT_ONE",
  "score": 92,
  "passed": true,
  "resultStatus": "PASSED",
  "examTime": "2026-06-01T10:00:00",
  "evaluatorName": "考官A",
  "failureReason": null
}

30. 查询考试成绩

请求

GET /api/exam-registrations/e5594438-d6d1-4d15-bbf3-9c02e6380846/result

成功响应

{
  "id": "b9f7e8db-d2d1-4cd1-8c31-e6ef687920a8",
  "studentId": "0d7e7c5c-66f8-4cf5-a6e7-4f34c7308f25",
  "examRegistrationId": "e5594438-d6d1-4d15-bbf3-9c02e6380846",
  "subjectType": "SUBJECT_ONE",
  "score": 92,
  "passed": true,
  "resultStatus": "PASSED",
  "examTime": "2026-06-01T10:00:00",
  "evaluatorName": "考官A",
  "failureReason": null
}

31. 重复录入成绩失败

响应

{
  "message": "当前考试报名已存在成绩"
}

建议按以下顺序联调:

  1. POST /api/students
  2. POST /api/enrollment-applications
  3. GET /api/enrollment-applications
  4. GET /api/enrollment-applications/{id}
  5. POST /api/enrollment-applications/{id}/reviews
  6. 再次调用 GET /api/enrollment-applications/{id} 检查状态变化

9. cURL 示例

创建学员

curl -X POST "http://localhost:8080/api/students" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "张三",
    "gender": "MALE",
    "idCardNo": "110101199001010011",
    "phone": "13800000001",
    "desiredLicenseType": "C1",
    "sourceChannel": "ONLINE"
  }'

创建报名申请

curl -X POST "http://localhost:8080/api/enrollment-applications" \
  -H "Content-Type: application/json" \
  -d '{
    "student": {
      "name": "张三",
      "gender": "MALE",
      "idCardNo": "110101199001010011",
      "phone": "13800000001",
      "desiredLicenseType": "C1",
      "sourceChannel": "ONLINE"
    },
    "licenseType": "C1",
    "trainingType": "周末班",
    "medicalDeclaration": true
  }'

审核报名申请

curl -X POST "http://localhost:8080/api/enrollment-applications/{id}/reviews" \
  -H "Content-Type: application/json" \
  -d '{
    "reviewStage": "INITIAL",
    "result": "APPROVED",
    "reviewerName": "审核员A",
    "comments": "资料完整,符合报名条件"
  }'