From 32f7660dc04723d2ed9621804240d7ba9bfd21a7 Mon Sep 17 00:00:00 2001 From: Jerry Yan <792602257@qq.com> Date: Sat, 6 Sep 2025 01:09:17 +0800 Subject: [PATCH] =?UTF-8?q?feat(questionnaire):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=97=AE=E5=8D=B7=E7=AE=A1=E7=90=86=20V2=20=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加了新的 QuestionnaireV2Controller 类,实现了问卷管理的 CRUD操作 - 新增了问卷答案查看和统计功能相关接口 - 重构了 ResponseDetailResponse 类,将 AnswerDetailResponse 类独立出来- 简化了 CreateQuestionOptionRequest 类的结构 --- .../pc/QuestionnaireV2Controller.java | 264 ++++++++++++++++++ .../dto/answer/AnswerDetailResponse.java | 20 ++ .../dto/answer/ResponseDetailResponse.java | 16 -- .../question/CreateQuestionOptionRequest.java | 6 - 4 files changed, 284 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/ycwl/basic/controller/pc/QuestionnaireV2Controller.java create mode 100644 src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/AnswerDetailResponse.java diff --git a/src/main/java/com/ycwl/basic/controller/pc/QuestionnaireV2Controller.java b/src/main/java/com/ycwl/basic/controller/pc/QuestionnaireV2Controller.java new file mode 100644 index 00000000..691dc357 --- /dev/null +++ b/src/main/java/com/ycwl/basic/controller/pc/QuestionnaireV2Controller.java @@ -0,0 +1,264 @@ +package com.ycwl.basic.controller.pc; + +import com.ycwl.basic.integration.questionnaire.dto.answer.ResponseDetailResponse; +import com.ycwl.basic.integration.questionnaire.dto.questionnaire.CreateQuestionnaireRequest; +import com.ycwl.basic.integration.questionnaire.dto.questionnaire.QuestionnaireResponse; +import com.ycwl.basic.integration.questionnaire.dto.statistics.QuestionnaireStatistics; +import com.ycwl.basic.integration.questionnaire.service.QuestionnaireIntegrationService; +import com.ycwl.basic.integration.common.response.PageResponse; +import com.ycwl.basic.utils.ApiResponse; +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.springframework.web.bind.annotation.*; + +import java.util.Map; + +/** + * 问卷管理 V2 版本控制器 - 基于 zt-questionnaire 集成服务 + * + * @author Claude Code + * @date 2025-09-05 + */ +@Slf4j +@RestController +@RequestMapping("/api/questionnaire/v2") +@RequiredArgsConstructor +public class QuestionnaireV2Controller { + + private final QuestionnaireIntegrationService questionnaireIntegrationService; + + // ========== 问卷管理 CRUD 操作 ========== + + /** + * 分页查询问卷列表 + */ + @GetMapping("/") + public ApiResponse> listQuestionnaires( + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Integer status, + @RequestParam(required = false) String name) { + log.info("分页查询问卷列表, page: {}, pageSize: {}, status: {}, name: {}", + page, pageSize, status, name); + + // 参数验证:限制pageSize最大值为100 + if (pageSize > 100) { + pageSize = 100; + } + + try { + PageResponse response = + questionnaireIntegrationService.getQuestionnaireList(page, pageSize, name, status, null); + return ApiResponse.success(response); + } catch (Exception e) { + log.error("分页查询问卷列表失败", e); + return ApiResponse.fail("分页查询问卷列表失败: " + e.getMessage()); + } + } + + /** + * 获取问卷详情 + */ + @GetMapping("/{id}") + public ApiResponse getQuestionnaire(@PathVariable Long id) { + log.info("获取问卷详情, id: {}", id); + try { + QuestionnaireResponse questionnaire = questionnaireIntegrationService.getQuestionnaire(id); + return ApiResponse.success(questionnaire); + } catch (Exception e) { + log.error("获取问卷详情失败, id: {}", id, e); + return ApiResponse.fail("获取问卷详情失败: " + e.getMessage()); + } + } + + /** + * 创建问卷 + */ + @PostMapping("/") + public ApiResponse createQuestionnaire(@Valid @RequestBody CreateQuestionnaireRequest request) { + log.info("创建问卷, name: {}, questions count: {}", + request.getName(), request.getQuestions() != null ? request.getQuestions().size() : 0); + try { + QuestionnaireResponse questionnaire = questionnaireIntegrationService.createQuestionnaire(request, "admin"); + return ApiResponse.success(questionnaire); + } catch (Exception e) { + log.error("创建问卷失败", e); + return ApiResponse.fail("创建问卷失败: " + e.getMessage()); + } + } + + /** + * 更新问卷 + */ + @PutMapping("/{id}") + public ApiResponse updateQuestionnaire( + @PathVariable Long id, + @Valid @RequestBody CreateQuestionnaireRequest request) { + log.info("更新问卷, id: {}", id); + try { + QuestionnaireResponse questionnaire = questionnaireIntegrationService.updateQuestionnaire(id, request, "admin"); + return ApiResponse.success(questionnaire); + } catch (Exception e) { + log.error("更新问卷失败, id: {}", id, e); + return ApiResponse.fail("更新问卷失败: " + e.getMessage()); + } + } + + /** + * 更新问卷状态 + */ + @PutMapping("/{id}/status") + public ApiResponse updateQuestionnaireStatus(@PathVariable Long id, @RequestBody Map request) { + Integer status = request.get("status"); + log.info("更新问卷状态, id: {}, status: {}", id, status); + try { + // 根据状态调用不同的方法 + if (status == 2) { + questionnaireIntegrationService.publishQuestionnaire(id, "admin"); + } else if (status == 3) { + questionnaireIntegrationService.stopQuestionnaire(id, "admin"); + } + return ApiResponse.success("问卷状态更新成功"); + } catch (Exception e) { + log.error("更新问卷状态失败, id: {}, status: {}", id, status, e); + return ApiResponse.fail("更新问卷状态失败: " + e.getMessage()); + } + } + + /** + * 发布问卷 + */ + @PutMapping("/{id}/publish") + public ApiResponse publishQuestionnaire(@PathVariable Long id) { + log.info("发布问卷, id: {}", id); + try { + questionnaireIntegrationService.publishQuestionnaire(id, "admin"); + return ApiResponse.success("问卷发布成功"); + } catch (Exception e) { + log.error("发布问卷失败, id: {}", id, e); + return ApiResponse.fail("发布问卷失败: " + e.getMessage()); + } + } + + /** + * 停止问卷 + */ + @PutMapping("/{id}/stop") + public ApiResponse stopQuestionnaire(@PathVariable Long id) { + log.info("停止问卷, id: {}", id); + try { + questionnaireIntegrationService.stopQuestionnaire(id, "admin"); + return ApiResponse.success("问卷停止成功"); + } catch (Exception e) { + log.error("停止问卷失败, id: {}", id, e); + return ApiResponse.fail("停止问卷失败: " + e.getMessage()); + } + } + + /** + * 删除问卷 + */ + @DeleteMapping("/{id}") + public ApiResponse deleteQuestionnaire(@PathVariable Long id) { + log.info("删除问卷, id: {}", id); + try { + questionnaireIntegrationService.deleteQuestionnaire(id, "admin"); + return ApiResponse.success("问卷删除成功"); + } catch (Exception e) { + log.error("删除问卷失败, id: {}", id, e); + return ApiResponse.fail("删除问卷失败: " + e.getMessage()); + } + } + + // ========== 问卷答案查看操作 ========== + + /** + * 分页查询问卷答案 + */ + @GetMapping("/{id}/answers") + public ApiResponse> getQuestionnaireAnswers( + @PathVariable Long id, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) String userId, + @RequestParam(required = false) String startTime, + @RequestParam(required = false) String endTime) { + log.info("分页查询问卷答案, questionnaireId: {}, page: {}, pageSize: {}, userId: {}", + id, page, pageSize, userId); + + // 参数验证:限制pageSize最大值为100 + if (pageSize > 100) { + pageSize = 100; + } + + try { + PageResponse response = + questionnaireIntegrationService.getResponseList(page, pageSize, id, userId, startTime, endTime); + return ApiResponse.success(response); + } catch (Exception e) { + log.error("分页查询问卷答案失败, questionnaireId: {}", id, e); + return ApiResponse.fail("分页查询问卷答案失败: " + e.getMessage()); + } + } + + /** + * 获取特定答案详情 + */ + @GetMapping("/{id}/answers/{answerId}") + public ApiResponse getQuestionnaireAnswer(@PathVariable Long id, @PathVariable Long answerId) { + log.info("获取问卷答案详情, questionnaireId: {}, answerId: {}", id, answerId); + try { + ResponseDetailResponse answer = questionnaireIntegrationService.getResponseDetail(answerId); + return ApiResponse.success(answer); + } catch (Exception e) { + log.error("获取问卷答案详情失败, questionnaireId: {}, answerId: {}", id, answerId, e); + return ApiResponse.fail("获取问卷答案详情失败: " + e.getMessage()); + } + } + + /** + * 查询用户答题记录 + */ + @GetMapping("/answers/user/{userId}") + public ApiResponse> getUserAnswers( + @PathVariable String userId, + @RequestParam(defaultValue = "1") Integer page, + @RequestParam(defaultValue = "10") Integer pageSize, + @RequestParam(required = false) Long questionnaireId) { + log.info("查询用户答题记录, userId: {}, page: {}, pageSize: {}, questionnaireId: {}", + userId, page, pageSize, questionnaireId); + + // 参数验证:限制pageSize最大值为100 + if (pageSize > 100) { + pageSize = 100; + } + + try { + PageResponse response = + questionnaireIntegrationService.getResponseList(page, pageSize, questionnaireId, userId, null, null); + return ApiResponse.success(response); + } catch (Exception e) { + log.error("查询用户答题记录失败, userId: {}", userId, e); + return ApiResponse.fail("查询用户答题记录失败: " + e.getMessage()); + } + } + + // ========== 统计功能 ========== + + /** + * 获取问卷统计信息 + */ + @GetMapping("/{id}/statistics") + public ApiResponse getQuestionnaireStatistics(@PathVariable Long id) { + log.info("获取问卷统计信息, id: {}", id); + try { + QuestionnaireStatistics statistics = questionnaireIntegrationService.getStatistics(id); + return ApiResponse.success(statistics); + } catch (Exception e) { + log.error("获取问卷统计信息失败, id: {}", id, e); + return ApiResponse.fail("获取问卷统计信息失败: " + e.getMessage()); + } + } + +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/AnswerDetailResponse.java b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/AnswerDetailResponse.java new file mode 100644 index 00000000..5768fea4 --- /dev/null +++ b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/AnswerDetailResponse.java @@ -0,0 +1,20 @@ +package com.ycwl.basic.integration.questionnaire.dto.answer; + +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; + +@Data +public class AnswerDetailResponse { + + @JsonProperty("questionId") + private Long questionId; + + @JsonProperty("questionTitle") + private String questionTitle; + + @JsonProperty("questionType") + private Integer questionType; + + @JsonProperty("answer") + private String answer; +} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/ResponseDetailResponse.java b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/ResponseDetailResponse.java index 12f68dce..151d5fa8 100644 --- a/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/ResponseDetailResponse.java +++ b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/answer/ResponseDetailResponse.java @@ -26,19 +26,3 @@ public class ResponseDetailResponse { @JsonProperty("answers") private List answers; } - -@Data -class AnswerDetailResponse { - - @JsonProperty("questionId") - private Long questionId; - - @JsonProperty("questionTitle") - private String questionTitle; - - @JsonProperty("questionType") - private Integer questionType; - - @JsonProperty("answer") - private String answer; -} \ No newline at end of file diff --git a/src/main/java/com/ycwl/basic/integration/questionnaire/dto/question/CreateQuestionOptionRequest.java b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/question/CreateQuestionOptionRequest.java index 4425cfa3..c2db8824 100644 --- a/src/main/java/com/ycwl/basic/integration/questionnaire/dto/question/CreateQuestionOptionRequest.java +++ b/src/main/java/com/ycwl/basic/integration/questionnaire/dto/question/CreateQuestionOptionRequest.java @@ -25,10 +25,4 @@ public class CreateQuestionOptionRequest { @JsonProperty("sort") private Integer sort = 0; - - public CreateQuestionOptionRequest(String text, String value, Integer sort) { - this.text = text; - this.value = value; - this.sort = sort; - } } \ No newline at end of file