Browse Source

1、代码同步

liyanbo 9 months ago
parent
commit
46b6907972
49 changed files with 1357 additions and 100 deletions
  1. 3 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionPageReqVO.java
  2. 3 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionRespVO.java
  3. 3 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionSaveReqVO.java
  4. 4 1
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaire/vo/ConfigQuestionRespVO.java
  5. 104 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/QuestionnaireResultController.java
  6. 44 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultPageReqVO.java
  7. 54 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultRespVO.java
  8. 39 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultSaveReqVO.java
  9. 104 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/QuestionnaireResultDetailsController.java
  10. 41 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsPageReqVO.java
  11. 54 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsRespVO.java
  12. 36 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsSaveReqVO.java
  13. 5 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/coursequestion/CourseQuestionDO.java
  14. 65 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/questionnaireresult/QuestionnaireResultDO.java
  15. 66 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/questionnaireresultdetails/QuestionnaireResultDetailsDO.java
  16. 1 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/coursequestion/CourseQuestionMapper.java
  17. 33 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/questionnaireresult/QuestionnaireResultMapper.java
  18. 33 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/questionnaireresultdetails/QuestionnaireResultDetailsMapper.java
  19. 6 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/enums/ErrorCodeConstants.java
  20. 62 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresult/QuestionnaireResultService.java
  21. 89 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresult/QuestionnaireResultServiceImpl.java
  22. 62 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresultdetails/QuestionnaireResultDetailsService.java
  23. 92 0
      byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresultdetails/QuestionnaireResultDetailsServiceImpl.java
  24. 1 1
      byzs-course/src/main/resources/mapper/course/CourseMapper.xml
  25. 2 1
      byzs-course/src/main/resources/mapper/questionnaire/QuestionnaireMapper.xml
  26. 7 0
      byzs-course/src/main/resources/mapper/questionnaireresult/QuestionnaireResultMapper.xml
  27. 7 0
      byzs-course/src/main/resources/mapper/questionnaireresultdetails/QuestionnaireResultDetailsMapper.xml
  28. 5 0
      byzs-module-infra/pom.xml
  29. 10 2
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/controller/admin/file/FileController.java
  30. 6 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/FileClient.java
  31. 5 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/db/DBFileClient.java
  32. 5 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/ftp/FtpFileClient.java
  33. 53 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/local/LocalFileClient.java
  34. 5 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/s3/S3FileClient.java
  35. 5 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/sftp/SftpFileClient.java
  36. 7 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/utils/FileTypeUtils.java
  37. 18 0
      byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/service/file/FileServiceImpl.java
  38. 5 3
      byzs-server/src/main/resources/application.yaml
  39. 15 7
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/WebQuestionnaireController.java
  40. 12 41
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/vo/WebQuestionnaireResultVo.java
  41. 18 0
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/vo/WebQuestionnaireShowVo.java
  42. 2 2
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/reportprogress/vo/WebReportProgressVO.java
  43. 21 0
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/dal/mysql/course/WebCourseMapper.java
  44. 7 0
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/course/WebCourseServiceImpl.java
  45. 96 8
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/questionnaire/WebQuestionnaireServiceImpl.java
  46. 28 33
      byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/reportprogress/WebReportProgressServiceImpl.java
  47. 0 0
      byzs-web/src/main/java/cn/iocoder/byzs/web/service/VideoProcessingService.java
  48. 5 0
      byzs-web/src/main/resources/mapper/course/WebCourseMapper.xml
  49. 9 1
      byzs-web/src/main/resources/mapper/reportprogress/ReportProgressMapper.xml

+ 3 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionPageReqVO.java

@@ -20,4 +20,7 @@ public class CourseQuestionPageReqVO extends PageParam {
     @Schema(description = "试题答案id")
     private Integer cqQuestAnswerId;
 
+    @Schema(description = "试题分数")
+    private Double cqQuestScore;
+
 }

+ 3 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionRespVO.java

@@ -31,6 +31,9 @@ public class CourseQuestionRespVO {
     @ExcelProperty("试题答案id")
     private Integer cqQuestAnswerId;
 
+    @Schema(description = "试题分数")
+    private Double cqQuestScore;
+
     @Schema(description = "选项列表")
     @ExcelProperty("选项列表")
     private List<CourseQuestOptionDO> courseQuestOptionList;

+ 3 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/coursequestion/vo/CourseQuestionSaveReqVO.java

@@ -24,4 +24,7 @@ public class CourseQuestionSaveReqVO {
     @Schema(description = "试题答案id")
     private Integer cqQuestAnswerId;
 
+    @Schema(description = "试题分数")
+    private Double cqQuestScore;
+
 }

+ 4 - 1
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaire/vo/ConfigQuestionRespVO.java

@@ -32,7 +32,10 @@ public class ConfigQuestionRespVO {
     private String cqQuestType;
 
     @Schema(description = "试题答案id")
-    private Integer cqQuestAnswerId;
+    private Long cqQuestAnswerId;
+
+    @Schema(description = "试题分数")
+    private Double cqQuestScore;
 
     @Schema(description = "试题排序")
     private Integer bqOrder;

+ 104 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/QuestionnaireResultController.java

@@ -0,0 +1,104 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.constraints.*;
+import jakarta.validation.*;
+import jakarta.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.pojo.CommonResult;
+import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
+import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.byzs.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.byzs.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.byzs.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult.QuestionnaireResultDO;
+import cn.iocoder.byzs.module.bjdx.service.questionnaireresult.QuestionnaireResultService;
+
+@Tag(name = "管理后台 - 北京大学-问卷结果")
+@RestController
+@RequestMapping("/bjdxResult/questionnaire-result")
+@Validated
+public class QuestionnaireResultController {
+
+    @Resource
+    private QuestionnaireResultService questionnaireResultService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建北京大学-问卷结果")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:create')")
+    public CommonResult<Long> createQuestionnaireResult(@Valid @RequestBody QuestionnaireResultSaveReqVO createReqVO) {
+        return success(questionnaireResultService.createQuestionnaireResult(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新北京大学-问卷结果")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:update')")
+    public CommonResult<Boolean> updateQuestionnaireResult(@Valid @RequestBody QuestionnaireResultSaveReqVO updateReqVO) {
+        questionnaireResultService.updateQuestionnaireResult(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除北京大学-问卷结果")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:delete')")
+    public CommonResult<Boolean> deleteQuestionnaireResult(@RequestParam("id") Long id) {
+        questionnaireResultService.deleteQuestionnaireResult(id);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete-list")
+    @Parameter(name = "ids", description = "编号", required = true)
+    @Operation(summary = "批量删除北京大学-问卷结果")
+                @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:delete')")
+    public CommonResult<Boolean> deleteQuestionnaireResultList(@RequestParam("ids") List<Long> ids) {
+        questionnaireResultService.deleteQuestionnaireResultListByIds(ids);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得北京大学-问卷结果")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:query')")
+    public CommonResult<QuestionnaireResultRespVO> getQuestionnaireResult(@RequestParam("id") Long id) {
+        QuestionnaireResultDO questionnaireResult = questionnaireResultService.getQuestionnaireResult(id);
+        return success(BeanUtils.toBean(questionnaireResult, QuestionnaireResultRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得北京大学-问卷结果分页")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:query')")
+    public CommonResult<PageResult<QuestionnaireResultRespVO>> getQuestionnaireResultPage(@Valid QuestionnaireResultPageReqVO pageReqVO) {
+        PageResult<QuestionnaireResultDO> pageResult = questionnaireResultService.getQuestionnaireResultPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, QuestionnaireResultRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出北京大学-问卷结果 Excel")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportQuestionnaireResultExcel(@Valid QuestionnaireResultPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<QuestionnaireResultDO> list = questionnaireResultService.getQuestionnaireResultPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "北京大学-问卷结果.xls", "数据", QuestionnaireResultRespVO.class,
+                        BeanUtils.toBean(list, QuestionnaireResultRespVO.class));
+    }
+
+}

+ 44 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultPageReqVO.java

@@ -0,0 +1,44 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.byzs.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 北京大学-问卷结果分页 Request VO")
+@Data
+public class QuestionnaireResultPageReqVO extends PageParam {
+
+    @Schema(description = "用户id")
+    private Long bqrUserId;
+
+    @Schema(description = "问卷id")
+    private Long bqrQuestionnaireId;
+
+    @Schema(description = "答卷状态")
+    private String bqrStatus;
+
+    @Schema(description = "试卷得分")
+    private Double bqrScore;
+
+    @Schema(description = "答题开始时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] bqrStartTime;
+
+    @Schema(description = "答题结束时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] bqrEndTime;
+
+    @Schema(description = "答题耗时")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private Integer[] bqrQuestTime;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 54 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultRespVO.java

@@ -0,0 +1,54 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+import cn.iocoder.byzs.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.byzs.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "管理后台 - 北京大学-问卷结果 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class QuestionnaireResultRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("id")
+    private Long id;
+
+    @Schema(description = "用户id")
+    @ExcelProperty("用户id")
+    private Long bqrUserId;
+
+    @Schema(description = "问卷id")
+    @ExcelProperty("问卷id")
+    private Long bqrQuestionnaireId;
+
+    @Schema(description = "答卷状态")
+    @ExcelProperty(value = "答卷状态", converter = DictConvert.class)
+    @DictFormat("bjdx_questionnaire_status") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+    private String bqrStatus;
+
+    @Schema(description = "试卷得分")
+    @ExcelProperty("试卷得分")
+    private Double bqrScore;
+
+    @Schema(description = "答题开始时间")
+    @ExcelProperty("答题开始时间")
+    private LocalDateTime bqrStartTime;
+
+    @Schema(description = "答题结束时间")
+    @ExcelProperty("答题结束时间")
+    private LocalDateTime bqrEndTime;
+
+    @Schema(description = "答题耗时")
+    @ExcelProperty("答题耗时")
+    private Integer bqrQuestTime;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 39 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresult/vo/QuestionnaireResultSaveReqVO.java

@@ -0,0 +1,39 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+import org.aspectj.lang.annotation.Aspect;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+@Schema(description = "管理后台 - 北京大学-问卷结果新增/修改 Request VO")
+@Data
+public class QuestionnaireResultSaveReqVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
+    private Long id;
+
+    @Schema(description = "用户id")
+    private Long bqrUserId;
+
+    @Schema(description = "问卷id")
+    private Long bqrQuestionnaireId;
+
+    @Schema(description = "答卷状态")
+    private String bqrStatus;
+
+    @Schema(description = "试卷得分")
+    private Double bqrScore;
+
+    @Schema(description = "答题开始时间")
+    private LocalDateTime bqrStartTime;
+
+    @Schema(description = "答题结束时间")
+    private LocalDateTime bqrEndTime;
+
+    @Schema(description = "答题耗时")
+    private Integer bqrQuestTime;
+
+}

+ 104 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/QuestionnaireResultDetailsController.java

@@ -0,0 +1,104 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails;
+
+import org.springframework.web.bind.annotation.*;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.security.access.prepost.PreAuthorize;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.Operation;
+
+import jakarta.validation.constraints.*;
+import jakarta.validation.*;
+import jakarta.servlet.http.*;
+import java.util.*;
+import java.io.IOException;
+
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.pojo.CommonResult;
+import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
+import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
+
+import cn.iocoder.byzs.framework.excel.core.util.ExcelUtils;
+
+import cn.iocoder.byzs.framework.apilog.core.annotation.ApiAccessLog;
+import static cn.iocoder.byzs.framework.apilog.core.enums.OperateTypeEnum.*;
+
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails.QuestionnaireResultDetailsDO;
+import cn.iocoder.byzs.module.bjdx.service.questionnaireresultdetails.QuestionnaireResultDetailsService;
+
+@Tag(name = "管理后台 - 北京大学-问卷结果-详情")
+@RestController
+@RequestMapping("/bjdxResult/questionnaire-result-details")
+@Validated
+public class QuestionnaireResultDetailsController {
+
+    @Resource
+    private QuestionnaireResultDetailsService questionnaireResultDetailsService;
+
+    @PostMapping("/create")
+    @Operation(summary = "创建北京大学-问卷结果-详情")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:create')")
+    public CommonResult<Long> createQuestionnaireResultDetails(@Valid @RequestBody QuestionnaireResultDetailsSaveReqVO createReqVO) {
+        return success(questionnaireResultDetailsService.createQuestionnaireResultDetails(createReqVO));
+    }
+
+    @PutMapping("/update")
+    @Operation(summary = "更新北京大学-问卷结果-详情")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:update')")
+    public CommonResult<Boolean> updateQuestionnaireResultDetails(@Valid @RequestBody QuestionnaireResultDetailsSaveReqVO updateReqVO) {
+        questionnaireResultDetailsService.updateQuestionnaireResultDetails(updateReqVO);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete")
+    @Operation(summary = "删除北京大学-问卷结果-详情")
+    @Parameter(name = "id", description = "编号", required = true)
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:delete')")
+    public CommonResult<Boolean> deleteQuestionnaireResultDetails(@RequestParam("id") Long id) {
+        questionnaireResultDetailsService.deleteQuestionnaireResultDetails(id);
+        return success(true);
+    }
+
+    @DeleteMapping("/delete-list")
+    @Parameter(name = "ids", description = "编号", required = true)
+    @Operation(summary = "批量删除北京大学-问卷结果-详情")
+                @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:delete')")
+    public CommonResult<Boolean> deleteQuestionnaireResultDetailsList(@RequestParam("ids") List<Long> ids) {
+        questionnaireResultDetailsService.deleteQuestionnaireResultDetailsListByIds(ids);
+        return success(true);
+    }
+
+    @GetMapping("/get")
+    @Operation(summary = "获得北京大学-问卷结果-详情")
+    @Parameter(name = "id", description = "编号", required = true, example = "1024")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:query')")
+    public CommonResult<QuestionnaireResultDetailsRespVO> getQuestionnaireResultDetails(@RequestParam("id") Long id) {
+        QuestionnaireResultDetailsDO questionnaireResultDetails = questionnaireResultDetailsService.getQuestionnaireResultDetails(id);
+        return success(BeanUtils.toBean(questionnaireResultDetails, QuestionnaireResultDetailsRespVO.class));
+    }
+
+    @GetMapping("/page")
+    @Operation(summary = "获得北京大学-问卷结果-详情分页")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:query')")
+    public CommonResult<PageResult<QuestionnaireResultDetailsRespVO>> getQuestionnaireResultDetailsPage(@Valid QuestionnaireResultDetailsPageReqVO pageReqVO) {
+        PageResult<QuestionnaireResultDetailsDO> pageResult = questionnaireResultDetailsService.getQuestionnaireResultDetailsPage(pageReqVO);
+        return success(BeanUtils.toBean(pageResult, QuestionnaireResultDetailsRespVO.class));
+    }
+
+    @GetMapping("/export-excel")
+    @Operation(summary = "导出北京大学-问卷结果-详情 Excel")
+    @PreAuthorize("@ss.hasPermission('bjdxResult:questionnaire-result-details:export')")
+    @ApiAccessLog(operateType = EXPORT)
+    public void exportQuestionnaireResultDetailsExcel(@Valid QuestionnaireResultDetailsPageReqVO pageReqVO,
+              HttpServletResponse response) throws IOException {
+        pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
+        List<QuestionnaireResultDetailsDO> list = questionnaireResultDetailsService.getQuestionnaireResultDetailsPage(pageReqVO).getList();
+        // 导出 Excel
+        ExcelUtils.write(response, "北京大学-问卷结果-详情.xls", "数据", QuestionnaireResultDetailsRespVO.class,
+                        BeanUtils.toBean(list, QuestionnaireResultDetailsRespVO.class));
+    }
+
+}

+ 41 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsPageReqVO.java

@@ -0,0 +1,41 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo;
+
+import lombok.*;
+import java.util.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+
+import static cn.iocoder.byzs.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
+
+@Schema(description = "管理后台 - 问卷结果-详情分页 Request VO")
+@Data
+public class QuestionnaireResultDetailsPageReqVO extends PageParam {
+
+    @Schema(description = "用户id")
+    private Long bqrdUserId;
+
+    @Schema(description = "答卷结果id")
+    private Long bqrdQuestionnaireResultId;
+
+    @Schema(description = "问卷id")
+    private Long bqrdQuestionnaireId;
+
+    @Schema(description = "试题id")
+    private Long bqrdQuestionId;
+
+    @Schema(description = "选择")
+    private Long bqrdQuestOptionId;
+
+    @Schema(description = "是否答对")
+    private String bqrdIsCorrect;
+
+    @Schema(description = "试题得分")
+    private Double bqrdQuestScore;
+
+    @Schema(description = "创建时间")
+    @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
+    private LocalDateTime[] createTime;
+
+}

+ 54 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsRespVO.java

@@ -0,0 +1,54 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import org.springframework.format.annotation.DateTimeFormat;
+import java.time.LocalDateTime;
+import com.alibaba.excel.annotation.*;
+import cn.iocoder.byzs.framework.excel.core.annotations.DictFormat;
+import cn.iocoder.byzs.framework.excel.core.convert.DictConvert;
+
+@Schema(description = "管理后台 - 问卷结果-详情 Response VO")
+@Data
+@ExcelIgnoreUnannotated
+public class QuestionnaireResultDetailsRespVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("id")
+    private Long id;
+
+    @Schema(description = "用户id")
+    @ExcelProperty("用户id")
+    private Long bqrdUserId;
+
+    @Schema(description = "答卷结果id")
+    @ExcelProperty("答卷结果id")
+    private Long bqrdQuestionnaireResultId;
+
+    @Schema(description = "问卷id")
+    @ExcelProperty("问卷id")
+    private Long bqrdQuestionnaireId;
+
+    @Schema(description = "试题id")
+    @ExcelProperty("试题id")
+    private Long bqrdQuestionId;
+
+    @Schema(description = "选择")
+    @ExcelProperty("选择")
+    private Long bqrdQuestOptionId;
+
+    @Schema(description = "是否答对")
+    @ExcelProperty(value = "是否答对", converter = DictConvert.class)
+    @DictFormat("bjdx_quest_is_correct") // TODO 代码优化:建议设置到对应的 DictTypeConstants 枚举类中
+    private String bqrdIsCorrect;
+
+    @Schema(description = "试题得分")
+    @ExcelProperty("试题得分")
+    private Double bqrdQuestSorce;
+
+    @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
+    @ExcelProperty("创建时间")
+    private LocalDateTime createTime;
+
+}

+ 36 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/controller/admin/questionnaireresultdetails/vo/QuestionnaireResultDetailsSaveReqVO.java

@@ -0,0 +1,36 @@
+package cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.*;
+import java.util.*;
+import jakarta.validation.constraints.*;
+
+@Schema(description = "管理后台 - 问卷结果-详情新增/修改 Request VO")
+@Data
+public class QuestionnaireResultDetailsSaveReqVO {
+
+    @Schema(description = "id", requiredMode = Schema.RequiredMode.REQUIRED)
+    private Long id;
+
+    @Schema(description = "用户id")
+    private Long bqrdUserId;
+
+    @Schema(description = "答卷结果id")
+    private Long bqrdQuestionnaireResultId;
+
+    @Schema(description = "问卷id")
+    private Long bqrdQuestionnaireId;
+
+    @Schema(description = "试题id")
+    private Long bqrdQuestionId;
+
+    @Schema(description = "选择")
+    private Long bqrdQuestOptionId;
+
+    @Schema(description = "是否答对")
+    private String bqrdIsCorrect;
+
+    @Schema(description = "试题得分")
+    private Double bqrdQuestSorce;
+
+}

+ 5 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/coursequestion/CourseQuestionDO.java

@@ -1,5 +1,6 @@
 package cn.iocoder.byzs.module.bjdx.dal.dataobject.coursequestion;
 
+import io.swagger.v3.oas.annotations.media.Schema;
 import lombok.*;
 import com.baomidou.mybatisplus.annotation.*;
 import cn.iocoder.byzs.framework.mybatis.core.dataobject.BaseDO;
@@ -40,6 +41,10 @@ public class CourseQuestionDO extends BaseDO {
      * 试题答案id
      */
     private Integer cqQuestAnswerId;
+    /**
+     * 试题分数
+     */
+    private Double cqQuestScore;
 
 
 }

+ 65 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/questionnaireresult/QuestionnaireResultDO.java

@@ -0,0 +1,65 @@
+package cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult;
+
+import cn.hutool.core.date.DateTime;
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.byzs.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 北京大学-问卷结果 DO
+ *
+ * @author lyb
+ */
+@TableName("bjdx_questionnaire_result")
+@KeySequence("bjdx_questionnaire_result_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QuestionnaireResultDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 用户id
+     */
+    private Long bqrUserId;
+    /**
+     * 问卷id
+     */
+    private Long bqrQuestionnaireId;
+    /**
+     * 答卷状态
+     *
+     * 枚举 {@link TODO bjdx_questionnaire_status 对应的类}
+     */
+    private String bqrStatus;
+    /**
+     * 试卷得分
+     */
+    private Double bqrScore;
+    /**
+     * 答题开始时间
+     */
+    private LocalDateTime bqrStartTime;
+    /**
+     * 答题结束时间
+     */
+    private LocalDateTime bqrEndTime;
+    /**
+     * 答题耗时
+     */
+    private Long bqrQuestTime;
+
+
+}

+ 66 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/dataobject/questionnaireresultdetails/QuestionnaireResultDetailsDO.java

@@ -0,0 +1,66 @@
+package cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails;
+
+import lombok.*;
+import java.util.*;
+import java.time.LocalDateTime;
+import java.time.LocalDateTime;
+import com.baomidou.mybatisplus.annotation.*;
+import cn.iocoder.byzs.framework.mybatis.core.dataobject.BaseDO;
+
+/**
+ * 问卷结果-详情 DO
+ *
+ * @author lyb
+ */
+@TableName("bjdx_questionnaire_result_details")
+@KeySequence("bjdx_questionnaire_result_details_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
+@Data
+@EqualsAndHashCode(callSuper = true)
+@ToString(callSuper = true)
+@Builder
+@NoArgsConstructor
+@AllArgsConstructor
+public class QuestionnaireResultDetailsDO extends BaseDO {
+
+    /**
+     * id
+     */
+    @TableId
+    private Long id;
+    /**
+     * 用户id
+     */
+    private Long bqrdUserId;
+    /**
+     * 答卷结果id
+     */
+    private Long bqrdQuestionnaireResultId;
+    /**
+     * 问卷id
+     */
+    private Long bqrdQuestionnaireId;
+    /**
+     * 试题id
+     */
+    private Long bqrdQuestionId;
+    /**
+     * 选择选项id
+     */
+    private Long bqrdQuestOptionId;
+    /**
+     * 选择选项
+     */
+    private Long bqrdQuestOptionVId;
+    /**
+     * 是否答对
+     *
+     * 枚举
+     */
+    private String bqrdIsCorrect;
+    /**
+     * 试题得分
+     */
+    private Double bqrdQuestScore = 0.0;
+
+
+}

+ 1 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/coursequestion/CourseQuestionMapper.java

@@ -21,6 +21,7 @@ public interface CourseQuestionMapper extends BaseMapperX<CourseQuestionDO> {
                 .likeIfPresent(CourseQuestionDO::getCqQuestion, reqVO.getCqQuestion())
                 .likeIfPresent(CourseQuestionDO::getCqQuestAnalysis, reqVO.getCqQuestAnalysis())
                 .eqIfPresent(CourseQuestionDO::getCqQuestType, reqVO.getCqQuestType())
+                .eqIfPresent(CourseQuestionDO::getCqQuestScore, reqVO.getCqQuestScore())
                 .eqIfPresent(CourseQuestionDO::getCqQuestAnswerId, reqVO.getCqQuestAnswerId())
                 .orderByDesc(CourseQuestionDO::getId));
     }

+ 33 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/questionnaireresult/QuestionnaireResultMapper.java

@@ -0,0 +1,33 @@
+package cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresult;
+
+import java.util.*;
+
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.byzs.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult.QuestionnaireResultDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo.*;
+
+/**
+ * 北京大学-问卷结果 Mapper
+ *
+ * @author lyb
+ */
+@Mapper
+public interface QuestionnaireResultMapper extends BaseMapperX<QuestionnaireResultDO> {
+
+    default PageResult<QuestionnaireResultDO> selectPage(QuestionnaireResultPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<QuestionnaireResultDO>()
+                .eqIfPresent(QuestionnaireResultDO::getBqrUserId, reqVO.getBqrUserId())
+                .eqIfPresent(QuestionnaireResultDO::getBqrQuestionnaireId, reqVO.getBqrQuestionnaireId())
+                .eqIfPresent(QuestionnaireResultDO::getBqrStatus, reqVO.getBqrStatus())
+                .eqIfPresent(QuestionnaireResultDO::getBqrScore, reqVO.getBqrScore())
+                .betweenIfPresent(QuestionnaireResultDO::getBqrStartTime, reqVO.getBqrStartTime())
+                .betweenIfPresent(QuestionnaireResultDO::getBqrEndTime, reqVO.getBqrEndTime())
+                .betweenIfPresent(QuestionnaireResultDO::getBqrQuestTime, reqVO.getBqrQuestTime())
+                .betweenIfPresent(QuestionnaireResultDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(QuestionnaireResultDO::getId));
+    }
+
+}

+ 33 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/dal/mysql/questionnaireresultdetails/QuestionnaireResultDetailsMapper.java

@@ -0,0 +1,33 @@
+package cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresultdetails;
+
+import java.util.*;
+
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.byzs.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails.QuestionnaireResultDetailsDO;
+import org.apache.ibatis.annotations.Mapper;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo.*;
+
+/**
+ * 北京大学-问卷结果-详情 Mapper
+ *
+ * @author lyb
+ */
+@Mapper
+public interface QuestionnaireResultDetailsMapper extends BaseMapperX<QuestionnaireResultDetailsDO> {
+
+    default PageResult<QuestionnaireResultDetailsDO> selectPage(QuestionnaireResultDetailsPageReqVO reqVO) {
+        return selectPage(reqVO, new LambdaQueryWrapperX<QuestionnaireResultDetailsDO>()
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdUserId, reqVO.getBqrdUserId())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdQuestionnaireResultId, reqVO.getBqrdQuestionnaireResultId())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdQuestionnaireId, reqVO.getBqrdQuestionnaireId())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdQuestionId, reqVO.getBqrdQuestionId())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdQuestOptionId, reqVO.getBqrdQuestOptionId())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdIsCorrect, reqVO.getBqrdIsCorrect())
+                .eqIfPresent(QuestionnaireResultDetailsDO::getBqrdQuestScore, reqVO.getBqrdQuestScore())
+                .betweenIfPresent(QuestionnaireResultDetailsDO::getCreateTime, reqVO.getCreateTime())
+                .orderByDesc(QuestionnaireResultDetailsDO::getId));
+    }
+
+}

+ 6 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/enums/ErrorCodeConstants.java

@@ -40,4 +40,10 @@ public interface ErrorCodeConstants {
     // ========== 进度 1_090_000_000 ==========
     ErrorCode PROGRESS_NOT_EXISTS = new ErrorCode(1_090_010_000, "课程配置id不能为空");
 
+    // ========== 答题 1_100_000_000 ==========
+    ErrorCode QUESTIONNAIRE_RESULT_NOT_EXISTS = new ErrorCode(1_100_010_000, "答题不存在");
+
+    // ========== 答题详情 1_101_000_000 ==========
+    ErrorCode QUESTIONNAIRE_RESULT_DETAILS_NOT_EXISTS = new ErrorCode(1_101_010_000, "答题详情不存在");
+
 }

+ 62 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresult/QuestionnaireResultService.java

@@ -0,0 +1,62 @@
+package cn.iocoder.byzs.module.bjdx.service.questionnaireresult;
+
+import java.util.*;
+import jakarta.validation.*;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult.QuestionnaireResultDO;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+
+/**
+ * 北京大学-问卷结果 Service 接口
+ *
+ * @author lyb
+ */
+public interface QuestionnaireResultService {
+
+    /**
+     * 创建北京大学-问卷结果
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createQuestionnaireResult(@Valid QuestionnaireResultSaveReqVO createReqVO);
+
+    /**
+     * 更新北京大学-问卷结果
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateQuestionnaireResult(@Valid QuestionnaireResultSaveReqVO updateReqVO);
+
+    /**
+     * 删除北京大学-问卷结果
+     *
+     * @param id 编号
+     */
+    void deleteQuestionnaireResult(Long id);
+
+    /**
+    * 批量删除北京大学-问卷结果
+    *
+    * @param ids 编号
+    */
+    void deleteQuestionnaireResultListByIds(List<Long> ids);
+
+    /**
+     * 获得北京大学-问卷结果
+     *
+     * @param id 编号
+     * @return 北京大学-问卷结果
+     */
+    QuestionnaireResultDO getQuestionnaireResult(Long id);
+
+    /**
+     * 获得北京大学-问卷结果分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 北京大学-问卷结果分页
+     */
+    PageResult<QuestionnaireResultDO> getQuestionnaireResultPage(QuestionnaireResultPageReqVO pageReqVO);
+
+}

+ 89 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresult/QuestionnaireResultServiceImpl.java

@@ -0,0 +1,89 @@
+package cn.iocoder.byzs.module.bjdx.service.questionnaireresult;
+
+import cn.hutool.core.collection.CollUtil;
+import org.springframework.stereotype.Service;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+
+import java.util.*;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult.QuestionnaireResultDO;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresult.QuestionnaireResultMapper;
+
+import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.byzs.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.byzs.module.bjdx.enums.ErrorCodeConstants.*;
+
+/**
+ * 北京大学-问卷结果 Service 实现类
+ *
+ * @author lyb
+ */
+@Service
+@Validated
+public class QuestionnaireResultServiceImpl implements QuestionnaireResultService {
+
+    @Resource
+    private QuestionnaireResultMapper questionnaireResultMapper;
+
+    @Override
+    public Long createQuestionnaireResult(QuestionnaireResultSaveReqVO createReqVO) {
+        // 插入
+        QuestionnaireResultDO questionnaireResult = BeanUtils.toBean(createReqVO, QuestionnaireResultDO.class);
+        questionnaireResultMapper.insert(questionnaireResult);
+        // 返回
+        return questionnaireResult.getId();
+    }
+
+    @Override
+    public void updateQuestionnaireResult(QuestionnaireResultSaveReqVO updateReqVO) {
+        // 校验存在
+        validateQuestionnaireResultExists(updateReqVO.getId());
+        // 更新
+        QuestionnaireResultDO updateObj = BeanUtils.toBean(updateReqVO, QuestionnaireResultDO.class);
+        questionnaireResultMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteQuestionnaireResult(Long id) {
+        // 校验存在
+        validateQuestionnaireResultExists(id);
+        // 删除
+        questionnaireResultMapper.deleteById(id);
+    }
+
+    @Override
+        public void deleteQuestionnaireResultListByIds(List<Long> ids) {
+        // 校验存在
+        validateQuestionnaireResultExists(ids);
+        // 删除
+        questionnaireResultMapper.deleteByIds(ids);
+        }
+
+    private void validateQuestionnaireResultExists(List<Long> ids) {
+        List<QuestionnaireResultDO> list = questionnaireResultMapper.selectByIds(ids);
+        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
+            throw exception(QUESTIONNAIRE_RESULT_NOT_EXISTS);
+        }
+    }
+
+    private void validateQuestionnaireResultExists(Long id) {
+        if (questionnaireResultMapper.selectById(id) == null) {
+            throw exception(QUESTIONNAIRE_RESULT_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public QuestionnaireResultDO getQuestionnaireResult(Long id) {
+        return questionnaireResultMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<QuestionnaireResultDO> getQuestionnaireResultPage(QuestionnaireResultPageReqVO pageReqVO) {
+        return questionnaireResultMapper.selectPage(pageReqVO);
+    }
+
+}

+ 62 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresultdetails/QuestionnaireResultDetailsService.java

@@ -0,0 +1,62 @@
+package cn.iocoder.byzs.module.bjdx.service.questionnaireresultdetails;
+
+import java.util.*;
+import jakarta.validation.*;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails.QuestionnaireResultDetailsDO;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+
+/**
+ * 北京大学-问卷结果-详情 Service 接口
+ *
+ * @author lyb
+ */
+public interface QuestionnaireResultDetailsService {
+
+    /**
+     * 创建北京大学-问卷结果-详情
+     *
+     * @param createReqVO 创建信息
+     * @return 编号
+     */
+    Long createQuestionnaireResultDetails(@Valid QuestionnaireResultDetailsSaveReqVO createReqVO);
+
+    /**
+     * 更新北京大学-问卷结果-详情
+     *
+     * @param updateReqVO 更新信息
+     */
+    void updateQuestionnaireResultDetails(@Valid QuestionnaireResultDetailsSaveReqVO updateReqVO);
+
+    /**
+     * 删除北京大学-问卷结果-详情
+     *
+     * @param id 编号
+     */
+    void deleteQuestionnaireResultDetails(Long id);
+
+    /**
+    * 批量删除北京大学-问卷结果-详情
+    *
+    * @param ids 编号
+    */
+    void deleteQuestionnaireResultDetailsListByIds(List<Long> ids);
+
+    /**
+     * 获得北京大学-问卷结果-详情
+     *
+     * @param id 编号
+     * @return 北京大学-问卷结果-详情
+     */
+    QuestionnaireResultDetailsDO getQuestionnaireResultDetails(Long id);
+
+    /**
+     * 获得北京大学-问卷结果-详情分页
+     *
+     * @param pageReqVO 分页查询
+     * @return 北京大学-问卷结果-详情分页
+     */
+    PageResult<QuestionnaireResultDetailsDO> getQuestionnaireResultDetailsPage(QuestionnaireResultDetailsPageReqVO pageReqVO);
+
+}

+ 92 - 0
byzs-course/src/main/java/cn/iocoder/byzs/module/bjdx/service/questionnaireresultdetails/QuestionnaireResultDetailsServiceImpl.java

@@ -0,0 +1,92 @@
+package cn.iocoder.byzs.module.bjdx.service.questionnaireresultdetails;
+
+import cn.hutool.core.collection.CollUtil;
+import org.springframework.stereotype.Service;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo.*;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails.QuestionnaireResultDetailsDO;
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import cn.iocoder.byzs.framework.common.util.object.BeanUtils;
+
+import cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresultdetails.QuestionnaireResultDetailsMapper;
+
+import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
+import static cn.iocoder.byzs.framework.common.util.collection.CollectionUtils.convertList;
+import static cn.iocoder.byzs.framework.common.util.collection.CollectionUtils.diffList;
+import static cn.iocoder.byzs.module.bjdx.enums.ErrorCodeConstants.*;
+
+/**
+ * 北京大学-问卷结果-详情 Service 实现类
+ *
+ * @author lyb
+ */
+@Service
+@Validated
+public class QuestionnaireResultDetailsServiceImpl implements QuestionnaireResultDetailsService {
+
+    @Resource
+    private QuestionnaireResultDetailsMapper questionnaireResultDetailsMapper;
+
+    @Override
+    public Long createQuestionnaireResultDetails(QuestionnaireResultDetailsSaveReqVO createReqVO) {
+        // 插入
+        QuestionnaireResultDetailsDO questionnaireResultDetails = BeanUtils.toBean(createReqVO, QuestionnaireResultDetailsDO.class);
+        questionnaireResultDetailsMapper.insert(questionnaireResultDetails);
+        // 返回
+        return questionnaireResultDetails.getId();
+    }
+
+    @Override
+    public void updateQuestionnaireResultDetails(QuestionnaireResultDetailsSaveReqVO updateReqVO) {
+        // 校验存在
+        validateQuestionnaireResultDetailsExists(updateReqVO.getId());
+        // 更新
+        QuestionnaireResultDetailsDO updateObj = BeanUtils.toBean(updateReqVO, QuestionnaireResultDetailsDO.class);
+        questionnaireResultDetailsMapper.updateById(updateObj);
+    }
+
+    @Override
+    public void deleteQuestionnaireResultDetails(Long id) {
+        // 校验存在
+        validateQuestionnaireResultDetailsExists(id);
+        // 删除
+        questionnaireResultDetailsMapper.deleteById(id);
+    }
+
+    @Override
+        public void deleteQuestionnaireResultDetailsListByIds(List<Long> ids) {
+        // 校验存在
+        validateQuestionnaireResultDetailsExists(ids);
+        // 删除
+        questionnaireResultDetailsMapper.deleteByIds(ids);
+        }
+
+    private void validateQuestionnaireResultDetailsExists(List<Long> ids) {
+        List<QuestionnaireResultDetailsDO> list = questionnaireResultDetailsMapper.selectByIds(ids);
+        if (CollUtil.isEmpty(list) || list.size() != ids.size()) {
+            throw exception(QUESTIONNAIRE_RESULT_DETAILS_NOT_EXISTS);
+        }
+    }
+
+    private void validateQuestionnaireResultDetailsExists(Long id) {
+        if (questionnaireResultDetailsMapper.selectById(id) == null) {
+            throw exception(QUESTIONNAIRE_RESULT_DETAILS_NOT_EXISTS);
+        }
+    }
+
+    @Override
+    public QuestionnaireResultDetailsDO getQuestionnaireResultDetails(Long id) {
+        return questionnaireResultDetailsMapper.selectById(id);
+    }
+
+    @Override
+    public PageResult<QuestionnaireResultDetailsDO> getQuestionnaireResultDetailsPage(QuestionnaireResultDetailsPageReqVO pageReqVO) {
+        return questionnaireResultDetailsMapper.selectPage(pageReqVO);
+    }
+
+}

+ 1 - 1
byzs-course/src/main/resources/mapper/course/CourseMapper.xml

@@ -27,7 +27,7 @@
                 AND c.course_content_type = #{courseContentType}
             </if>
         </where>
-        ORDER BY c.course_label,c.course_order
+        ORDER BY c.course_order
 
     </select>
 </mapper>

+ 2 - 1
byzs-course/src/main/resources/mapper/questionnaire/QuestionnaireMapper.xml

@@ -12,7 +12,8 @@
             cq.cq_question as cqQuestion,
             cq.cq_quest_analysis as cqQuestAnalysis,
             cq.cq_quest_answer_id as cqQuestAnswerId,
-            qc.bq_order as bqOrder
+            qc.bq_order as bqOrder,
+            cq.cq_quest_score as cqQuestScore
         FROM bjdx_questionnaire_config qc
         LEFT JOIN bjdx_questionnaire q ON q.id = qc.bqc_questionnaire_id
         LEFT JOIN bjdx_course_question cq ON qc.bqc_question_id = cq.id

+ 7 - 0
byzs-course/src/main/resources/mapper/questionnaireresult/QuestionnaireResultMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresult.QuestionnaireResultMapper">
+
+
+
+</mapper>

+ 7 - 0
byzs-course/src/main/resources/mapper/questionnaireresultdetails/QuestionnaireResultDetailsMapper.xml

@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresultdetails.QuestionnaireResultDetailsMapper">
+
+
+
+</mapper>

+ 5 - 0
byzs-module-infra/pom.xml

@@ -114,6 +114,11 @@
             <artifactId>tika-core</artifactId> <!-- 文件客户端:文件类型的识别 -->
         </dependency>
 
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-vfs2</artifactId>
+            <version>2.9.0</version>
+        </dependency>
     </dependencies>
 
 </project>

+ 10 - 2
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/controller/admin/file/FileController.java

@@ -26,6 +26,15 @@ import org.springframework.security.access.prepost.PreAuthorize;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import java.io.File;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+  import java.util.Arrays;
+  import java.util.List;
+  import java.util.stream.Collectors;
+  import cn.hutool.core.io.FileUtil;
 
 import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
 import static cn.iocoder.byzs.module.infra.framework.file.core.utils.FileTypeUtils.writeAttachment;
@@ -50,7 +59,6 @@ public class FileController {
 //        if (file.getSize() > maxFileSize) {
 //            throw new IllegalArgumentException("文件大小超过限制,仅支持 200MB 以内的文件(大文件请使用前端直传模式)");
 //        }
-
         byte[] content = IoUtil.readBytes(file.getInputStream());
         return success(fileService.createFile(content, file.getOriginalFilename(),
                 uploadReqVO.getDirectory(), file.getContentType()));
@@ -162,4 +170,4 @@ public class FileController {
         return success(BeanUtils.toBean(pageResult, FileRespVO.class));
     }
 
-}
+}

+ 6 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/FileClient.java

@@ -52,4 +52,10 @@ public interface FileClient {
         throw new UnsupportedOperationException("不支持的操作");
     }
 
+    /**
+     *
+     * @param pathMp4 文件路径
+     * @return URL 访问地址
+     */
+    String ffmpegHts(String pathMp4);
 }

+ 5 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/db/DBFileClient.java

@@ -27,6 +27,11 @@ public class DBFileClient extends AbstractFileClient<DBFileClientConfig> {
         fileContentMapper = SpringUtil.getBean(FileContentMapper.class);
     }
 
+    @Override
+    public String ffmpegHts(String pathMp4) {
+        return "";
+    }
+
     @Override
     public String upload(byte[] content, String path, String type) {
         FileContentDO contentDO = new FileContentDO().setConfigId(getId())

+ 5 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/ftp/FtpFileClient.java

@@ -31,6 +31,11 @@ public class FtpFileClient extends AbstractFileClient<FtpFileClientConfig> {
                 CharsetUtil.CHARSET_UTF_8, null, null, FtpMode.valueOf(config.getMode()));
     }
 
+    @Override
+    public String ffmpegHts(String pathMp4) {
+        return "";
+    }
+
     @Override
     public String upload(byte[] content, String path, String type) {
         // 执行写入

+ 53 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/local/LocalFileClient.java

@@ -1,9 +1,14 @@
 package cn.iocoder.byzs.module.infra.framework.file.core.client.local;
 
 import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
 import cn.iocoder.byzs.module.infra.framework.file.core.client.AbstractFileClient;
 
+import java.io.BufferedReader;
 import java.io.File;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.List;
 
 /**
  * 本地文件客户端
@@ -20,11 +25,59 @@ public class LocalFileClient extends AbstractFileClient<LocalFileClientConfig> {
     protected void doInit() {
     }
 
+    @Override
+    public String ffmpegHts(String pathMp4) {
+        pathMp4= getFilePath(pathMp4);
+        String filePathName = pathMp4.substring(0, pathMp4.lastIndexOf("."));
+        String pathM3u8 = filePathName + ".m3u8";
+        try {
+            System.out.println("PATH环境变量: " + System.getenv("PATH"));
+            // 构建FFmpeg命令进行HLS切片
+            ProcessBuilder processBuilder = new ProcessBuilder(
+                    "ffmpeg", "-i", pathMp4,
+                    "-c:v", "h264", "-c:a", "aac",
+                    "-hls_time", "10", "-hls_list_size", "0",
+                    "-hls_segment_filename",  filePathName + "_%03d.ts",
+                    pathM3u8
+            );
+
+            // 重定向错误流到输入流(便于捕获FFmpeg输出信息)
+            processBuilder.redirectErrorStream(true);
+
+            // 启动进程
+            Process process = processBuilder.start();
+
+            // 读取FFmpeg输出日志
+            try (BufferedReader reader = new BufferedReader(
+                    new InputStreamReader(process.getInputStream()))) {
+                String line;
+                while ((line = reader.readLine()) != null) {
+                    System.out.println("FFmpeg输出: " + line);
+                }
+            }
+
+            // 等待进程执行完成
+            int exitCode = process.waitFor();
+            if (exitCode == 0) {
+                pathM3u8 = pathM3u8.substring(pathM3u8.lastIndexOf(File.separator)+1);
+                System.out.println("视频切片成功,m3u8路径: " + pathM3u8);
+                return super.formatFileUrl(config.getDomain(), pathM3u8);
+            } else {
+                System.err.println("FFmpeg执行失败,退出码: " + exitCode);
+                return null;
+            }
+
+        }catch (Exception e) {
+            throw new RuntimeException("视频处理失败,请检查视频格式是否支持:", e);
+        }
+    }
+
     @Override
     public String upload(byte[] content, String path, String type) {
         // 执行写入
         String filePath = getFilePath(path);
         FileUtil.writeBytes(content, filePath);
+
         // 拼接返回路径
         return super.formatFileUrl(config.getDomain(), path);
     }

+ 5 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/s3/S3FileClient.java

@@ -63,6 +63,11 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
                 .build();
     }
 
+    @Override
+    public String ffmpegHts(String pathMp4) {
+        return "";
+    }
+
     @Override
     public String upload(byte[] content, String path, String type) {
         // 构造 PutObjectRequest

+ 5 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/client/sftp/SftpFileClient.java

@@ -26,6 +26,11 @@ public class SftpFileClient extends AbstractFileClient<SftpFileClientConfig> {
         this.sftp = new Sftp(config.getHost(), config.getPort(), config.getUsername(), config.getPassword());
     }
 
+    @Override
+    public String ffmpegHts(String pathMp4) {
+        return "";
+    }
+
     @Override
     public String upload(byte[] content, String path, String type) {
         // 执行写入

+ 7 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/framework/file/core/utils/FileTypeUtils.java

@@ -81,6 +81,13 @@ public class FileTypeUtils {
     public static void writeAttachment(HttpServletResponse response, String filename, byte[] content) throws IOException {
         // 1. 基础头设置
         String contentType = getMineType(content, filename);
+
+        // 2. 设置响应头(根据文件类型)
+//        if (filename.endsWith(".m3u8")) {
+//            contentType = "application/x-mpegURL";
+//        } else if (filename.endsWith(".ts")) {
+//            contentType = "video/MP2T";
+//        }
         response.setContentType(contentType);
         response.setContentLength(content.length);
 

+ 18 - 0
byzs-module-infra/src/main/java/cn/iocoder/byzs/module/infra/service/file/FileServiceImpl.java

@@ -2,6 +2,7 @@ package cn.iocoder.byzs.module.infra.service.file;
 
 import cn.hutool.core.date.LocalDateTimeUtil;
 import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.io.IoUtil;
 import cn.hutool.core.lang.Assert;
 import cn.hutool.core.util.StrUtil;
 import cn.hutool.crypto.digest.DigestUtil;
@@ -20,6 +21,15 @@ import jakarta.annotation.Resource;
 import lombok.SneakyThrows;
 import org.springframework.stereotype.Service;
 
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.util.Arrays;
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
 import static cn.hutool.core.date.DatePattern.PURE_DATE_PATTERN;
 import static cn.iocoder.byzs.framework.common.exception.util.ServiceExceptionUtil.exception;
 import static cn.iocoder.byzs.module.infra.enums.ErrorCodeConstants.FILE_NOT_EXISTS;
@@ -83,6 +93,14 @@ public class FileServiceImpl implements FileService {
         Assert.notNull(client, "客户端(master) 不能为空");
         String url = client.upload(content, path, type);
 
+        // 2.3 处理视频文件
+        if (type.startsWith("video/")) {
+            String m3u8Path = client.ffmpegHts(path);
+            if(StrUtil.isNotEmpty(m3u8Path)){
+                url = m3u8Path;
+            }
+        }
+
         // 3. 保存到数据库
         fileMapper.insert(new FileDO().setConfigId(client.getId())
                 .setName(name).setPath(path).setUrl(url)

+ 5 - 3
byzs-server/src/main/resources/application.yaml

@@ -3,7 +3,9 @@ spring:
     name: byzs-bjdx
 
   profiles:
-    active: prodDev
+    active: local
+#    active: prodDev
+#    active: prod
 
   main:
     allow-circular-references: true # 允许循环依赖,因为项目是三层架构,无法避免这个情况。
@@ -12,8 +14,8 @@ spring:
   servlet:
     # 文件上传相关配置项
     multipart:
-      max-file-size: 100MB # 单个文件大小
-      max-request-size: 200MB # 设置总上传的文件大小
+      max-file-size: 500MB # 单个文件大小
+      max-request-size: 1000MB # 设置总上传的文件大小
 
   # Jackson 配置项
   jackson:

+ 15 - 7
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/WebQuestionnaireController.java

@@ -2,19 +2,25 @@ package cn.iocoder.byzs.module.web.controller.admin.questionnaire;
 
 import cn.iocoder.byzs.framework.common.pojo.CommonResult;
 import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.tenant.core.aop.TenantIgnore;
 import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaire.vo.QuestionnairePageReqVO;
 import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaire.QuestionnaireDO;
 import cn.iocoder.byzs.module.bjdx.service.questionnaire.QuestionnaireService;
+import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireResultVo;
+import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireShowVo;
 import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireVo;
 import cn.iocoder.byzs.module.web.service.questionnaire.WebQuestionnaireServiceImpl;
 import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
 import io.swagger.v3.oas.annotations.tags.Tag;
 import jakarta.annotation.Resource;
+import jakarta.annotation.security.PermitAll;
 import jakarta.validation.Valid;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import static cn.iocoder.byzs.framework.common.pojo.CommonResult.success;
+import static cn.iocoder.byzs.framework.security.core.util.SecurityFrameworkUtils.getLoginUserId;
 
 
 @Tag(name = "Web-前端接口")
@@ -36,17 +42,19 @@ public class WebQuestionnaireController {
     }
 
     @GetMapping("/getQuestionVoList")
-    @Operation(summary = "取问列表")
-    public CommonResult<WebQuestionnaireVo> getQuestionVoList(@RequestParam("qrId") Long qrId) {
-        WebQuestionnaireVo webQuestionnaireVo = webQuestionnaireService.getQuestionVoList(qrId);
-        return success(webQuestionnaireVo);
+    @Operation(summary = "取问列表")
+    public CommonResult<WebQuestionnaireShowVo> getQuestionVoList(@RequestParam("qrId") Long qrId) {
+        WebQuestionnaireShowVo webQuestionnaireShowVo = webQuestionnaireService.getQuestionVoList(qrId, getLoginUserId());
+        return success(webQuestionnaireShowVo);
     }
 
+    @PermitAll
+    @TenantIgnore
     @PostMapping("/saveQuestionResult")
     @Operation(summary = "保存试卷结果")
-    public CommonResult<Boolean> getQuestionnaire(@Valid QuestionnairePageReqVO questionnairePageReqVO) {
-
-        return success(true);
+    public CommonResult<Boolean> saveQuestionResult(@Valid @RequestBody WebQuestionnaireResultVo questionnaireResultVo) {
+        questionnaireResultVo.setUserId(getLoginUserId());
+        return success(webQuestionnaireService.saveQuestionResult(questionnaireResultVo));
     }
 
 }

+ 12 - 41
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/vo/WebQuestionnaireResultVo.java

@@ -8,59 +8,30 @@ import java.util.List;
 
 @Data
 @Accessors(chain = true)
-public class WebQuestionnaireResultVo extends PageParam {
-    //问卷id
-    private Long qrId;
-
-    //问卷名称
-    private String qrName;
-
-    //问卷介绍
-    private String qrDetails;
+public class WebQuestionnaireResultVo {
 
-    //问卷排序
-    private Integer qrOrder;
+    //用户id
+    private Long userId;
 
-    //问卷开始指导语
-    private String qrStartInfo;
-
-    //问卷结束指导语
-    private String qrEndInfo;
+    //问卷id
+    private Long qrId;
 
-    //问题id集(后期改成问题条数)
-    private String qrQuestIds;
+    //答卷id
+    private Long qrResultId;
 
     //问题列表
     private List<WebQuestion> questionList;
 
     @Data
     public static class WebQuestion{
+
         //问题id
         private Long qId;
-        //问题类型
-        private String qType;
-        //问题内容
-        private String qContent;
-        //问题内容
-        private String qAnalysis;
-        //问题内容
-        private Integer qOrder;
 
-        //问题选项
-        private List<WebQuestOption> questionOptionsList;
+        //选项id
+        private Long oId;
 
-        @Data
-        public static class WebQuestOption{
-            //选项
-            private Long oId;
-            //选项
-            private String oValue;
-            //选项内容
-            private String oName;
-            //分值
-            private Double oSorce;
-            //是否答案
-            private String oIsAnswer;
-        }
+        //选项
+        private Long oVId;
     }
 }

+ 18 - 0
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/questionnaire/vo/WebQuestionnaireShowVo.java

@@ -0,0 +1,18 @@
+package cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo;
+
+import cn.iocoder.byzs.framework.common.pojo.PageParam;
+import lombok.Data;
+import lombok.experimental.Accessors;
+
+import java.util.List;
+
+@Data
+@Accessors(chain = true)
+public class WebQuestionnaireShowVo extends PageParam {
+
+    //答卷id
+    private Long qrResultId;
+
+    //问卷
+    private WebQuestionnaireVo questionnaire;
+}

+ 2 - 2
byzs-web/src/main/java/cn/iocoder/byzs/module/web/controller/admin/reportprogress/vo/WebReportProgressVO.java

@@ -35,7 +35,7 @@ public class WebReportProgressVO {
     /**
      * ai问答次数
      */
-    private Integer aiCount;
+    private Integer aiCount = 0;
 
     /**
      * 评语
@@ -64,7 +64,7 @@ public class WebReportProgressVO {
         /**
          * 进度(课程开课率、课程互动率、ai问答次数)
          */
-        private Double progress;
+        private Double progress = 0d;
     }
 
 }

+ 21 - 0
byzs-web/src/main/java/cn/iocoder/byzs/module/web/dal/mysql/course/WebCourseMapper.java

@@ -0,0 +1,21 @@
+package cn.iocoder.byzs.module.web.dal.mysql.course;
+
+import cn.iocoder.byzs.framework.common.pojo.PageResult;
+import cn.iocoder.byzs.framework.mybatis.core.mapper.BaseMapperX;
+import cn.iocoder.byzs.framework.mybatis.core.query.LambdaQueryWrapperX;
+import cn.iocoder.byzs.module.bjdx.controller.admin.course.vo.CoursePageReqVO;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.course.CourseDO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * web课程 Mapper
+ *
+ * @author lyb
+ */
+@Mapper
+public interface WebCourseMapper {
+
+    List<CoursePageReqVO> selectCourse(CoursePageReqVO reqVO);
+}

+ 7 - 0
byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/course/WebCourseServiceImpl.java

@@ -7,6 +7,7 @@ import cn.iocoder.byzs.module.bjdx.controller.admin.courseconfig.vo.CourseConfig
 import cn.iocoder.byzs.module.bjdx.service.course.CourseService;
 import cn.iocoder.byzs.module.bjdx.service.courseconfig.CourseConfigService;
 import cn.iocoder.byzs.module.web.controller.admin.course.vo.WebCourseVO;
+import cn.iocoder.byzs.module.web.dal.mysql.course.WebCourseMapper;
 import jakarta.annotation.Resource;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
@@ -14,6 +15,7 @@ import org.springframework.validation.annotation.Validated;
 import java.util.ArrayList;
 import java.util.Comparator;
 import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * web课程 Service 实现类
@@ -28,6 +30,8 @@ public class WebCourseServiceImpl{
     private CourseService courseService;
     @Resource
     private CourseConfigService courseConfigService;
+    @Resource
+    private WebCourseMapper webCourseMapper;
 
 
     public List<WebCourseVO> getCourseVoByTypeId(Long typeId) {
@@ -38,6 +42,9 @@ public class WebCourseServiceImpl{
 //                .map(CoursePageReqVO::getId)
 //                .collect(Collectors.toList());
 
+        //优化需要走web端类
+//        webCourseMapper
+
         List<WebCourseVO> courseVoList = new ArrayList<>();
 
         for (CoursePageReqVO course : courseList) {

+ 96 - 8
byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/questionnaire/WebQuestionnaireServiceImpl.java

@@ -1,18 +1,32 @@
 package cn.iocoder.byzs.module.web.service.questionnaire;
 
 import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.date.DateTime;
+import cn.iocoder.byzs.framework.mybatis.core.query.LambdaQueryWrapperX;
 import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaire.vo.ConfigQuestionRespVO;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresult.vo.QuestionnaireResultSaveReqVO;
+import cn.iocoder.byzs.module.bjdx.controller.admin.questionnaireresultdetails.vo.QuestionnaireResultDetailsSaveReqVO;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.coursequestion.CourseQuestionDO;
 import cn.iocoder.byzs.module.bjdx.dal.dataobject.coursequestoption.CourseQuestOptionDO;
 import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaire.QuestionnaireDO;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresult.QuestionnaireResultDO;
+import cn.iocoder.byzs.module.bjdx.dal.dataobject.questionnaireresultdetails.QuestionnaireResultDetailsDO;
 import cn.iocoder.byzs.module.bjdx.dal.mysql.coursequestion.CourseQuestionMapper;
 import cn.iocoder.byzs.module.bjdx.dal.mysql.coursequestoption.CourseQuestOptionMapper;
 import cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaire.QuestionnaireMapper;
+import cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresult.QuestionnaireResultMapper;
+import cn.iocoder.byzs.module.bjdx.dal.mysql.questionnaireresultdetails.QuestionnaireResultDetailsMapper;
 import cn.iocoder.byzs.module.bjdx.service.questionnaire.QuestionnaireService;
+import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireResultVo;
+import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireShowVo;
 import cn.iocoder.byzs.module.web.controller.admin.questionnaire.vo.WebQuestionnaireVo;
 import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.validation.annotation.Validated;
 
+import java.time.Duration;
+import java.time.LocalDateTime;
 import java.util.*;
 import java.util.stream.Collectors;
 
@@ -33,9 +47,25 @@ public class WebQuestionnaireServiceImpl {
     private CourseQuestionMapper courseQuestionMapper;
     @Resource
     private CourseQuestOptionMapper courseQuestOptionMapper;
+    @Resource
+    private QuestionnaireResultMapper questionnaireResultMapper;
+    @Resource
+    private QuestionnaireResultDetailsMapper questionnaireResultDetailsMapper;
 
-    public WebQuestionnaireVo getQuestionVoList(Long qrId) {
-        // 问卷信息填充(未修改部分)
+    public WebQuestionnaireShowVo getQuestionVoList(Long qrId, Long userId) {
+        // 结果主表插入(关键修改:时间类型转换)
+        LocalDateTime startTime = LocalDateTime.now(); // 直接使用 LocalDateTime
+        QuestionnaireResultDO questionnaireResult = new QuestionnaireResultDO()
+            .setBqrUserId(userId)
+            .setBqrQuestionnaireId(qrId)
+            .setBqrStartTime(startTime) // 改为 LocalDateTime 类型
+            .setBqrStatus("1");
+        questionnaireResultMapper.insert(questionnaireResult);
+        // 问卷信息填充
+        WebQuestionnaireShowVo webQuestionnaireShowVo = new WebQuestionnaireShowVo();
+        webQuestionnaireShowVo.setQrResultId(questionnaireResult.getId());
+
+        //问卷信息
         QuestionnaireDO questionnaire = questionnaireService.getQuestionnaire(qrId);
         WebQuestionnaireVo questionnaireVo = new WebQuestionnaireVo();
         questionnaireVo.setQrId(questionnaire.getId());
@@ -59,11 +89,11 @@ public class WebQuestionnaireServiceImpl {
                 List<WebQuestionnaireVo.WebQuestion> questionList = new ArrayList<>();
                 configQuestionRespVOList.forEach(configQuestionRespVO -> {
                     WebQuestionnaireVo.WebQuestion webQuestion = new WebQuestionnaireVo.WebQuestion();
-                    webQuestion.setQId(configQuestionRespVO.getId());
-                    webQuestion.setQType(configQuestionRespVO.getCqQuestType());
-                    webQuestion.setQContent(configQuestionRespVO.getCqQuestion());
-                    webQuestion.setQAnalysis(configQuestionRespVO.getCqQuestAnalysis());
-                    webQuestion.setQOrder(configQuestionRespVO.getBqOrder());
+                    webQuestion.setQId(configQuestionRespVO.getId())
+                        .setQType(configQuestionRespVO.getCqQuestType())
+                        .setQContent(configQuestionRespVO.getCqQuestion())
+                        .setQAnalysis(configQuestionRespVO.getCqQuestAnalysis())
+                        .setQOrder(configQuestionRespVO.getBqOrder());
 
                     List<CourseQuestOptionDO> questOptionDOMapList = questionOptionMap.get(webQuestion.getQId());
                     if (CollUtil.isNotEmpty(questOptionDOMapList)) {
@@ -88,6 +118,64 @@ public class WebQuestionnaireServiceImpl {
                 questionnaireVo.setQuestionList(questionList);
             }
         }
-        return questionnaireVo;
+        webQuestionnaireShowVo.setQuestionnaire(questionnaireVo);
+        return webQuestionnaireShowVo;
     }
+
+    public Boolean saveQuestionResult(WebQuestionnaireResultVo questionnaireResultVo) {
+        // 问卷结果更新状态(关键修改:时间类型统一)
+        LocalDateTime endDateTime = LocalDateTime.now(); // 直接使用 LocalDateTime
+        QuestionnaireResultDO questionnaireResult = questionnaireResultMapper.selectById(questionnaireResultVo.getQrResultId());
+
+        LocalDateTime startTime = questionnaireResult.getBqrStartTime(); // 直接获取 LocalDateTime 类型
+        Long questTime = Duration.between(startTime, endDateTime).getSeconds(); // 无需额外转换
+
+        QuestionnaireResultDO updateResultDO = new QuestionnaireResultDO()
+            .setId(questionnaireResultVo.getQrResultId())
+            .setBqrEndTime(endDateTime) // 改为 LocalDateTime 类型
+            .setBqrQuestTime(questTime)
+            .setBqrStatus("2");
+        questionnaireResultMapper.updateById(updateResultDO);
+
+        // 问题列表答案
+        List<WebQuestionnaireResultVo.WebQuestion> questionList = questionnaireResultVo.getQuestionList();
+
+        List<ConfigQuestionRespVO> configQuestionRespVOList = questionnaireMapper.selectConfigQuestionList(new ConfigQuestionRespVO().setQuestionnaireId(questionnaireResultVo.getQrId()));
+        // 关键修改:将问题列表转换为ID到问题的映射(方便快速查找)
+        Map<Long, ConfigQuestionRespVO> questionIdMap = configQuestionRespVOList.stream()
+            .collect(Collectors.toMap(ConfigQuestionRespVO::getId, q -> q, (k1, k2) -> k1));
+
+        // 试题答案(新增:获取正确答案逻辑)
+        List<QuestionnaireResultDetailsDO> saveDetailsVOList = new ArrayList<>();
+        questionList.forEach(webQuestion -> {
+            QuestionnaireResultDetailsDO saveDetailsVO = new QuestionnaireResultDetailsDO();
+            saveDetailsVO.setBqrdUserId(questionnaireResult.getBqrUserId())
+                .setBqrdQuestionnaireId(questionnaireResultVo.getQrId())
+                .setBqrdQuestionnaireResultId(questionnaireResultVo.getQrId())
+                .setBqrdQuestionId(webQuestion.getQId())
+                .setBqrdQuestOptionId(webQuestion.getOId())
+                .setBqrdQuestOptionVId(webQuestion.getOVId());
+
+            // 从configQuestionRespVOList中匹配当前试题的答案
+            ConfigQuestionRespVO currentQuestion = questionIdMap.get(webQuestion.getQId());
+            if (currentQuestion != null && currentQuestion.getCqQuestAnswerId() != null) {
+                boolean isCorrect = Objects.equals(currentQuestion.getCqQuestAnswerId(), webQuestion.getOId());
+                saveDetailsVO.setBqrdIsCorrect(isCorrect ? "1" : "2");
+                saveDetailsVO.setBqrdQuestScore(isCorrect ? currentQuestion.getCqQuestScore() : 0);
+            }
+            saveDetailsVOList.add(saveDetailsVO);
+        });
+
+        //答题详情保存
+        questionnaireResultDetailsMapper.insertBatch(saveDetailsVOList);
+
+        // 问卷结果更新状态
+        Double score = saveDetailsVOList.stream().mapToDouble(QuestionnaireResultDetailsDO::getBqrdQuestScore).sum();
+        questionnaireResultMapper.updateById(new QuestionnaireResultDO()
+                .setId(questionnaireResultVo.getQrResultId())
+                .setBqrStatus("3")
+                .setBqrScore(score));
+        return true;
+    }
+
 }

+ 28 - 33
byzs-web/src/main/java/cn/iocoder/byzs/module/web/service/reportprogress/WebReportProgressServiceImpl.java

@@ -111,54 +111,53 @@ public class WebReportProgressServiceImpl {
         Map<String, List<WebReportProgressDTO>> progressTypeMap = webReportProgressDOList.stream().collect(Collectors.groupingBy(WebReportProgressDTO::getProgressType));
 
         courseAllMap.forEach((kcflName, courseMap)->{
+            //课程开课率
+            WebReportProgressVO.ReportProgressVo courseProgressVo = new WebReportProgressVO.ReportProgressVo();
+            courseProgressVo.setKcflName(kcflName);
+
+            //课程互动率
+            WebReportProgressVO.ReportProgressVo courseConfigProgressVoConfig = new WebReportProgressVO.ReportProgressVo();
+            courseConfigProgressVoConfig.setKcflName(kcflName);
 
             //解析数据进度
             progressTypeMap.keySet().forEach(progressType -> {
                 List<WebReportProgressDTO> progressDOList = progressTypeMap.get(progressType);
-                Map<String, List<WebReportProgressDTO>> progressKcflMap = progressDOList.stream().collect(Collectors.groupingBy(WebReportProgressDTO::getKcflName));
+
                 switch (progressType) {
                     case "course":
 
                         //计算课程大纲进度
-                        progressKcflMap.forEach((kcflNameData, progressDTOList) -> {
-                            //课程开课率
-                            WebReportProgressVO.ReportProgressVo courseProgressVo = new WebReportProgressVO.ReportProgressVo();
-                            courseProgressVo.setKcflName(kcflName);
-                            double sum = progressDTOList.stream().collect(Collectors.summarizingDouble(WebReportProgressDTO::getProgress)).getSum();
-                            courseProgressVo.setProgress(delTwo(sum / courseAllMap.get(kcflName).size()));
-                            courseProgressVoList.add(courseProgressVo);
-                        });
+                        Map<String, List<WebReportProgressDTO>> progressKcflMap = progressDOList.stream().collect(Collectors.groupingBy(WebReportProgressDTO::getKcflName));
+                            double courseSum = progressKcflMap.containsKey(kcflName) ? progressKcflMap.get(kcflName).stream().collect(Collectors.summarizingDouble(WebReportProgressDTO::getProgress)).getSum() : 0;
+                        courseProgressVo.setProgress(delTwo(courseSum / courseAllMap.get(kcflName).size()));
+
                         break;
 
                     case "courseQuest":
 
                         //计算课程大纲进度
-                        progressKcflMap.forEach((kcflNameData, progressDTOList) -> {
-                            //课程互动率
-                            WebReportProgressVO.ReportProgressVo courseConfigProgressVoConfig = new WebReportProgressVO.ReportProgressVo();
-                            courseConfigProgressVoConfig.setKcflName(kcflName);
-
-                            // 新增:计算courseMap所有value的总和(每个Map的value是课程配置数量)
-                            int totalConfigCount = courseMap.stream()
+                        // 新增:计算courseMap所有value的总和(每个Map的value是课程配置数量)
+                        int totalConfigCount = courseMap.stream()
                                 .flatMap(map -> map.values().stream())  // 展开所有Map的value值
                                 .mapToInt(Integer::intValue)            // 转换为int流
                                 .sum();                                 // 求和
-
-                            double sum = progressDTOList.size();
-                            // 注意:这里可能需要根据实际业务调整分母(示例保持原逻辑)
-                            courseConfigProgressVoConfig.setProgress(delTwo(sum / totalConfigCount * 100));  // 调整为使用总和计算进度
-                            courseConfigProgressVoList.add(courseConfigProgressVoConfig);  // 修正集合添加对象
-                        });
+                        Map<String, List<WebReportProgressDTO>> progressKcflQuestMap = progressDOList.stream().collect(Collectors.groupingBy(WebReportProgressDTO::getKcflName));
+                        double courseConfigSum = progressKcflQuestMap.containsKey(kcflName) ? progressKcflQuestMap.get(kcflName).size() : 0;
+                        // 注意:这里可能需要根据实际业务调整分母(示例保持原逻辑)
+                        courseConfigProgressVoConfig.setProgress(delTwo(courseConfigSum / totalConfigCount * 100));  // 调整为使用总和计算进度
                         break;
 
                     case "aiCount":
                         if (!progressDOList.isEmpty()) {
-                            Double sum = progressDOList.stream().collect(Collectors.summarizingDouble(WebReportProgressDTO::getProgress)).getSum();
-                            webReportProgressVO.setAiCount(sum.intValue());
+                            double aiCount = progressDOList.stream().collect(Collectors.summarizingDouble(WebReportProgressDTO::getProgress)).getSum();
+                            webReportProgressVO.setAiCount((int) aiCount);
                         }
                         break;
                 }
             });
+
+            courseProgressVoList.add(courseProgressVo);
+            courseConfigProgressVoList.add(courseConfigProgressVoConfig);  // 修正集合添加对象
         });
 
         // 原有总和计算逻辑(位置不变)
@@ -173,20 +172,16 @@ public class WebReportProgressServiceImpl {
         webReportProgressVO.setReportCourseProgressList(courseProgressVoList);
         webReportProgressVO.setReportCourseConfigProgressList(courseConfigProgressVoList);
 
-        //
+        //评语
         Double njCourseProgress = webReportProgressVO.getNjCourseProgress();
         Double njCourseConfigProgress = webReportProgressVO.getNjCourseConfigProgress();
         Integer aiCount = webReportProgressVO.getAiCount();
         List<ReportManageDO> reportManageDOList = reportManageMapper.selectList();
         StringBuffer comment = new StringBuffer();
         reportManageDOList.forEach(reportManageDO -> {
-            if (reportManageDO.getBrcReportAiCountMin() <= njCourseProgress && reportManageDO.getBrcReportAiCountMax() >= njCourseProgress){
-                comment.append(reportManageDO.getBrcReportComment());
-            }
-            if (reportManageDO.getBrcReportQuestMin() <= njCourseConfigProgress && reportManageDO.getBrcReportQuestMax() >= njCourseConfigProgress){
-                comment.append(reportManageDO.getBrcReportComment());
-            }
-            if (reportManageDO.getBrcReportAiCountMin() <= aiCount && reportManageDO.getBrcReportAiCountMax() >= aiCount){
+            if ((reportManageDO.getBrcReportCourseMin() <= njCourseProgress && reportManageDO.getBrcReportCourseMax() >= njCourseProgress) ||
+                    (reportManageDO.getBrcReportQuestMin() <= njCourseConfigProgress && reportManageDO.getBrcReportQuestMax() >= njCourseConfigProgress) ||
+                    (reportManageDO.getBrcReportAiCountMin() <= aiCount && reportManageDO.getBrcReportAiCountMax() >= aiCount)){
                 comment.append(reportManageDO.getBrcReportComment());
             }
         });
@@ -195,7 +190,7 @@ public class WebReportProgressServiceImpl {
     }
 
     public double delTwo(Double num){
-        if (Double.isInfinite(num))return 0;
+        if (Double.isInfinite(num) || Double.isNaN(num))return 0;
         BigDecimal two = new BigDecimal(num);
         double newNum = two.setScale(0, RoundingMode.HALF_UP).doubleValue();
         newNum = newNum > 100 ? 100 : newNum;

+ 0 - 0
byzs-web/src/main/java/cn/iocoder/byzs/web/service/VideoProcessingService.java


+ 5 - 0
byzs-web/src/main/resources/mapper/course/WebCourseMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="cn.iocoder.byzs.module.bjdx.dal.mysql.course.CourseMapper">
+
+</mapper>

+ 9 - 1
byzs-web/src/main/resources/mapper/reportprogress/ReportProgressMapper.xml

@@ -6,7 +6,7 @@
             resultType="cn.iocoder.byzs.module.web.controller.admin.reportprogress.vo.WebReportProgressDTO">
         SELECT
             u.nickname as userName,
-            fl.ct_type as kcflName,
+            CONCAT(LPAD(fl.ct_type_sort, 2, '0'), ' ', fl.ct_type) as kcflName,
             c.course_name as courseName,
             rp.brp_progress as progress,
             rp.brp_type as progressType
@@ -14,5 +14,13 @@
         LEFT JOIN bjdx_course_type fl ON rp.brp_ct_id =fl.id
         LEFT JOIN bjdx_course c ON rp.brp_course_id = c.id
         LEFT JOIN system_users u ON rp.brp_user_id = u.id
+        <where>
+            <if test="brpUserId != null">
+                and rp.brp_user_id = #{brpUserId}
+            </if>
+            <if test="brpNjId != null">
+                AND rp.brp_nj_id = #{brpNjId}
+            </if>
+        </where>
     </select>
 </mapper>