You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

166 lines
11 KiB

package com.mydreamjob.assessment;
import com.mydreamjob.assessment.dto.AssessmentAttemptResponse;
import com.mydreamjob.assessment.dto.AssessmentHistoryItem;
import com.mydreamjob.assessment.dto.AssessmentQuestionResponse;
import com.mydreamjob.assessment.dto.AssessmentResultResponse;
import com.mydreamjob.assessment.dto.AssessmentTypeResponse;
import com.mydreamjob.assessment.dto.CreateAssessmentAttemptRequest;
import com.mydreamjob.assessment.dto.SaveAssessmentAnswersRequest;
import com.mydreamjob.audit.AuditContext;
import com.mydreamjob.common.api.ApiResponse;
import com.mydreamjob.common.api.PageResponse;
import com.mydreamjob.common.logging.RequestIdAccessor;
import com.mydreamjob.security.CurrentUserAccessor;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponses;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.validation.Valid;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* RIASEC 职业兴趣测评接口(V34/V35)。
*
* <p>身份仅取自 JWT,不接受 userId 参数。类型与题目对任意已登录用户开放;
* 答卷创建/详情/保存/提交/结果/历史仅 STUDENT 且仅限本人。COMPANY/ADMIN 操作答卷返回 403。</p>
*/
@Tag(name = "RIASEC 职业兴趣测评", description = "测评类型、题目、答卷、保存答案、提交与结果查询")
@RestController
@RequiredArgsConstructor
public class AssessmentController {
private final AssessmentCatalogService catalogService;
private final AssessmentAttemptService attemptService;
private final AssessmentResultService resultService;
private final CurrentUserAccessor currentUserAccessor;
private final RequestIdAccessor requestIdAccessor;
@Operation(summary = "测评类型列表",
description = "返回全部 ACTIVE 测评定义。任意已登录用户可访问;未登录 401。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录")
})
@GetMapping("/assessments/types")
public ApiResponse<List<AssessmentTypeResponse>> listTypes(HttpServletRequest request) {
return ApiResponse.ok(catalogService.listTypes(), requestIdAccessor.get(request));
}
@Operation(summary = "题目列表",
description = "返回指定测评的 ACTIVE 题目,隐藏维度/reverseScored/source/版本等内部字段。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "测评类型不存在(9701)")
})
@GetMapping("/assessments/{type}/questions")
public ApiResponse<List<AssessmentQuestionResponse>> listQuestions(
@PathVariable String type, HttpServletRequest request) {
return ApiResponse.ok(catalogService.listQuestions(type), requestIdAccessor.get(request));
}
@Operation(summary = "创建答卷",
description = "照六维各抽 5 题共 30 道并持久化,刷新不重抽。幂等键重放返回原答卷;"
+ "同键不同定义 409/9709;已有活跃答卷 409/9708。仅 STUDENT。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非 STUDENT(2002)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "测评类型不存在(9701)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "活跃答卷/幂等冲突(9708/9709)")
})
@PostMapping("/assessments/attempts")
public ApiResponse<AssessmentAttemptResponse> createAttempt(
@Valid @RequestBody CreateAssessmentAttemptRequest req, HttpServletRequest request) {
return ApiResponse.ok(attemptService.create(currentUserAccessor.requireUserId(), req, AuditContext.from(request)),
requestIdAccessor.get(request));
}
@Operation(summary = "答卷详情",
description = "返回本次抽中的 30 道题(固定顺序)、已保存答案、进度与当前状态。仅本人可访问;非 STUDENT 403。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非本人或非 STUDENT(2002)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "答卷不存在(9702)")
})
@GetMapping("/assessments/attempts/{attemptId}")
public ApiResponse<AssessmentAttemptResponse> getAttempt(
@PathVariable Long attemptId, HttpServletRequest request) {
return ApiResponse.ok(attemptService.get(currentUserAccessor.requireUserId(), attemptId), requestIdAccessor.get(request));
}
@Operation(summary = "保存答案",
description = "单题或批量保存,重复保存 upsert;value 1-5;题目必须属于本答卷;"
+ "版本冲突 409/9707;首次保存后状态置为 IN_PROGRESS。仅本人。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非本人或非 STUDENT(2002)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "答卷不存在(9702)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "非法状态/并发(9703/9707)")
})
@PatchMapping("/assessments/attempts/{attemptId}/answers")
public ApiResponse<AssessmentAttemptResponse> saveAnswers(
@PathVariable Long attemptId,
@Valid @RequestBody SaveAssessmentAnswersRequest req, HttpServletRequest request) {
return ApiResponse.ok(attemptService.saveAnswers(currentUserAccessor.requireUserId(), attemptId, req,
AuditContext.from(request)), requestIdAccessor.get(request));
}
@Operation(summary = "提交答卷",
description = "30 题全答且每维各 5 题后方可提交(否则 400/9706);提交后生成结果并写审计;"
+ "重复提交返回原结果,不重复生成与审计。仅本人。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非本人或非 STUDENT(2002)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "答卷不存在(9702)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "非法状态(9703)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "400", description = "未完成(9706)")
})
@PostMapping("/assessments/attempts/{attemptId}/submit")
public ApiResponse<AssessmentResultResponse> submitAttempt(
@PathVariable Long attemptId, HttpServletRequest request) {
return ApiResponse.ok(attemptService.submit(currentUserAccessor.requireUserId(), attemptId,
AuditContext.from(request)), requestIdAccessor.get(request));
}
@Operation(summary = "查看结果",
description = "答卷 COMPLETED 后返回聚合分、类型排名、探索方向。仅本人可访问。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非本人或非 STUDENT(2002)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "404", description = "答卷不存在(9702)"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "409", description = "答卷未完成(9703)")
})
@GetMapping("/assessments/attempts/{attemptId}/result")
public ApiResponse<AssessmentResultResponse> getResult(
@PathVariable Long attemptId, HttpServletRequest request) {
return ApiResponse.ok(resultService.get(currentUserAccessor.requireUserId(), attemptId), requestIdAccessor.get(request));
}
@Operation(summary = "我的测评历史",
description = "分页返回当前学生的全部答卷与结果概要。仅 STUDENT 本人可访问。")
@ApiResponses({
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "200", description = "OK"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "401", description = "未登录"),
@io.swagger.v3.oas.annotations.responses.ApiResponse(responseCode = "403", description = "非 STUDENT(2002)")
})
@GetMapping("/assessments/me")
public ApiResponse<PageResponse<AssessmentHistoryItem>> listMine(
@RequestParam(defaultValue = "0") int page,
@RequestParam(defaultValue = "20") int size,
HttpServletRequest request) {
Page<AssessmentHistoryItem> result = attemptService.listMine(currentUserAccessor.requireUserId(), page, size);
return ApiResponse.ok(PageResponse.of(
result.getContent(),
result.getTotalElements(), result.getNumber(), result.getSize()), requestIdAccessor.get(request));
}
}