Explorar el Código

Merge branch 'dev' of http://192.168.1.245:11111/jinjilong/onlineEducation-fwd into dev

honorfire hace 7 meses
padre
commit
1c9250ad28
Se han modificado 69 ficheros con 2493 adiciones y 127 borrados
  1. 2 6
      snowy-modules/snowy-web-app/src/main/java/vip/xiaonuo/web/core/config/GlobalConfigure.java
  2. 6 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/pom.xml
  3. 54 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/FFmpegConfig.java
  4. 33 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/FilePath.java
  5. 128 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/M3u8Component.java
  6. 32 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/SpringAsyncConfig.java
  7. 12 1
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/FileController.java
  8. 2 1
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/MinioController.java
  9. 159 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/QuestionAnswerController.java
  10. 132 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/QuestionAnswerGiveController.java
  11. 95 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/QuestionAnswer.java
  12. 71 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/QuestionAnswerGive.java
  13. 2 3
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/ResourceUserFile.java
  14. 34 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/enums/QuestionAnswerEnum.java
  15. 34 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/enums/QuestionAnswerGiveEnum.java
  16. 27 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/QuestionAnswerGiveMapper.java
  17. 34 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/QuestionAnswerMapper.java
  18. 4 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/ResourceUserFileMapper.java
  19. 10 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/QuestionAnswerGiveMapper.xml
  20. 40 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/QuestionAnswerMapper.xml
  21. 54 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/ResourceUserFileMapper.xml
  22. 63 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerAddParam.java
  23. 71 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerEditParam.java
  24. 42 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveAddParam.java
  25. 44 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveEditParam.java
  26. 35 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveIdParam.java
  27. 51 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGivePageParam.java
  28. 35 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerIdParam.java
  29. 53 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerPageParam.java
  30. 7 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/M3u8UploadService.java
  31. 81 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/QuestionAnswerGiveService.java
  32. 87 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/QuestionAnswerService.java
  33. 128 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/M3u8UploadServiceImpl.java
  34. 96 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/QuestionAnswerGiveServiceImpl.java
  35. 156 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/QuestionAnswerServiceImpl.java
  36. 61 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/FileUtil.java
  37. 64 13
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/MinioUtil.java
  38. 52 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/m3u8Util.java
  39. 81 0
      snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/vo/questionanswer/QuestionAnswerVo.java
  40. 12 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-api/src/main/java/vip/xiaonuo/exam/api/CourseChapterPaperApi.java
  41. 6 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/pom.xml
  42. 13 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/admin/QuestionController.java
  43. 5 4
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/EducationController.java
  44. 20 20
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/ExamPaperAnswerController.java
  45. 7 11
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/ExamPaperController.java
  46. 18 16
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/QuestionAnswerController.java
  47. 10 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/CourseChapterPaper.java
  48. 1 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaper.java
  49. 4 3
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaperAnswer.java
  50. 30 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaperQuestionCustomerAnswer.java
  51. 29 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/Question.java
  52. 3 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/enums/ExamPaperTypeEnum.java
  53. 1 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperAnswerMapper.java
  54. 3 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperMapper.java
  55. 2 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperQuestionCustomerAnswerMapper.java
  56. 10 3
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/CourseChapterPaperMapper.xml
  57. 4 3
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperAnswerMapper.xml
  58. 15 6
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperMapper.xml
  59. 2 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperQuestionCustomerAnswerMapper.xml
  60. 1 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperAnswerService.java
  61. 2 2
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperQuestionCustomerAnswerService.java
  62. 1 1
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperService.java
  63. 4 3
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperAnswerServiceImpl.java
  64. 6 4
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperQuestionCustomerAnswerServiceImpl.java
  65. 52 12
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperServiceImpl.java
  66. 19 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/exam/ExamPaperPageVM.java
  67. 20 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/exampaper/ExamPaperAnswerPageVM.java
  68. 19 0
      snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/question/answer/QuestionPageStudentRequestVM.java
  69. 2 6
      snowy-server/snowy-gateway-app/src/main/java/vip/xiaonuo/gateway/config/GatewayConfigure.java

+ 2 - 6
snowy-modules/snowy-web-app/src/main/java/vip/xiaonuo/web/core/config/GlobalConfigure.java

@@ -184,13 +184,9 @@ public class GlobalConfigure implements WebMvcConfigurer {
             /* 资源中心 */
             "/disk/resourcecentre/page",
             "/disk/resourcecentre/detail",
-            "/disk/courseauditrecord/addViewCount",
+            "/disk/courseauditrecord/addViewCount"
+
 
-            "/disk/minio/upload",
-            "/disk/minio/checkExits",
-            "/disk/minio/merge",
-            "/disk/minio/delete",
-            "/disk/minio/checkMd5List"
     };
 
     /**

+ 6 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/pom.xml

@@ -324,6 +324,12 @@
             <scope>system</scope>
             <systemPath>${project.basedir}/src/main/resources/lib/aspose-pdf-22.4.jar</systemPath>
         </dependency>
+
+        <dependency>
+            <groupId>net.bramp.ffmpeg</groupId>
+            <artifactId>ffmpeg</artifactId>
+            <version>0.6.2</version>
+        </dependency>
     </dependencies>
 
     <repositories>

+ 54 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/FFmpegConfig.java

@@ -0,0 +1,54 @@
+package vip.xiaonuo.disk.config.m3u8;
+
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import net.bramp.ffmpeg.FFmpeg;
+import net.bramp.ffmpeg.FFprobe;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+import java.io.File;
+
+//@Configuration
+@Slf4j
+public class FFmpegConfig {
+
+    //@Resource
+    private FilePath filePath;
+
+    @SneakyThrows
+    //@Bean
+    public FFmpeg fFmpeg() {
+        String path = "";
+        if (isLinux()){
+            path+=filePath.getFfmpegPathLinux() + File.separator + "ffmpeg";
+        }else if (isWindows()){
+            path+=filePath.getFfmpegPathWin() + File.separator + "ffmpeg.exe";
+        }
+        log.info("ffmpeg 路径为{}",path);
+        return new FFmpeg(path);
+    }
+
+    @SneakyThrows
+    //@Bean
+    public FFprobe fFprobe() {
+        String path = "";
+        if (isLinux()){
+            path+=filePath.getFfmpegPathLinux() + File.separator + "ffprobe";
+        }else if (isWindows()){
+            path+=filePath.getFfmpegPathWin() + File.separator + "ffprobe.exe";
+        }
+        log.info("ffprobe 路径为{}",path);
+        return new FFprobe(path);
+    }
+    public static boolean isLinux() {
+        return System.getProperty("os.name").toLowerCase().contains("linux");
+    }
+
+    public static boolean isWindows() {
+        return System.getProperty("os.name").toLowerCase().contains("windows");
+    }
+
+
+}

+ 33 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/FilePath.java

@@ -0,0 +1,33 @@
+package vip.xiaonuo.disk.config.m3u8;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+@Data
+//@Component
+//@ConfigurationProperties(prefix = "m3u8.convertor")
+public class FilePath {
+    /**
+    * 文件上传临时路径 (本地文件转换不需要)
+    */
+    private String tempPath = "D:\\file\\tmp\\";
+
+    /**
+     * m3u8文件转换后,储存的根路径
+     */
+    private String basePath = "D:\\file\\m3u8\\";
+
+    /**
+     * m3u8文件转换后,储存的根路径
+     */
+    private String bigPath = "D:\\file\\big\\";
+
+    private String proxy = "m3u8/";
+
+    private String proxyURL= "http://127.0.0.1:8080/";
+
+    private String ffmpegPathWin = "C:\\Program Files\\ffmpeg\\bin";
+
+    private String ffmpegPathLinux = "ffmpeg";
+}

+ 128 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/M3u8Component.java

@@ -0,0 +1,128 @@
+package vip.xiaonuo.disk.config.m3u8;
+
+import cn.hutool.core.io.FileUtil;
+import lombok.SneakyThrows;
+import lombok.extern.slf4j.Slf4j;
+import net.bramp.ffmpeg.FFmpeg;
+import net.bramp.ffmpeg.FFmpegExecutor;
+import net.bramp.ffmpeg.FFprobe;
+import net.bramp.ffmpeg.builder.FFmpegBuilder;
+import net.bramp.ffmpeg.probe.FFmpegProbeResult;
+import net.bramp.ffmpeg.probe.FFmpegStream;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+import vip.xiaonuo.disk.util.m3u8Util;
+import javax.annotation.Resource;
+import java.io.File;
+import java.util.List;
+import java.util.Optional;
+import java.util.stream.Collectors;
+
+
+@Slf4j
+//@Component
+public class M3u8Component {
+
+    //@Resource
+    private FFmpeg ffmpeg;
+
+    //@Resource
+    private FFprobe ffprobe;
+
+    //@Resource
+    private FilePath filePath;
+
+
+
+    /**
+     * 视频文件转 m3u8
+     * 支持: .mp4 | .flv | .avi | .mov | .wmv | .wav
+     * @param file 视频文件
+     * @return 路径
+     */
+    public String mediaFileToM3u8(MultipartFile file){
+        if (file.isEmpty()) {
+            throw new RuntimeException("未发现文件");
+        }
+        log.info("开始解析视频");
+        long start = System.currentTimeMillis();
+        //临时目录创建
+        String tempFilePath = filePath.getTempPath();
+        if (!FileUtil.exist(tempFilePath)) {
+            FileUtil.mkdir(tempFilePath);
+        }
+        String filePathName = tempFilePath + file.getOriginalFilename();
+        File dest = new File(filePathName);
+        try {
+            file.transferTo(dest);
+        }catch (Exception e){
+            log.error("视频转m3u8格式存在异常,异常原因e:{}",e.getMessage());
+        }
+        long end = System.currentTimeMillis();
+        log.info("临时文件上传成功......耗时:{} ms", end - start);
+        String m3u8FilePath = localFileToM3u8(filePathName);
+        log.info("视频转换已完成 !");
+        return m3u8FilePath;
+    }
+
+    /**
+     * 本地媒体资源转换
+     * @param filePathName : 文件路径
+     * @return :
+     */
+    @SneakyThrows
+    public String localFileToM3u8(String filePathName) {
+        long startTime = System.currentTimeMillis();
+        final FFmpegProbeResult probe = ffprobe.probe(filePathName);
+        final List<FFmpegStream> streams = probe.getStreams().stream().filter(fFmpegStream -> fFmpegStream.codec_type != null).collect(Collectors.toList());
+        final Optional<FFmpegStream> audioStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.AUDIO.equals(fFmpegStream.codec_type)).findFirst();
+        final Optional<FFmpegStream> videoStream = streams.stream().filter(fFmpegStream -> FFmpegStream.CodecType.VIDEO.equals(fFmpegStream.codec_type)).findFirst();
+
+        if (!audioStream.isPresent()) {
+            log.error("未发现音频流");
+        }
+        if (!videoStream.isPresent()) {
+            log.error("未发现视频流");
+        }
+        //m3u8文件 存储路径
+        String filePath = m3u8Util.generateFilePath(this.filePath.getBasePath());
+        if (!FileUtil.exist(filePath)) {
+            FileUtil.mkdir(filePath);
+        }
+        String mainName = m3u8Util.getFileMainName(filePathName);
+        String m3u8FileName = filePath + mainName + ".m3u8";
+
+        //下面这一串参数别乱动,经过调优的,1G视频大概需要10秒左右,如果是大佬随意改
+        //"-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_wrap", "0", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12"
+        FFmpegBuilder builder = new FFmpegBuilder()
+                .setInput(filePathName)
+                .overrideOutputFiles(true)
+                .addOutput(m3u8FileName)//输出文件
+                .setFormat(probe.getFormat().format_name) //"mp4"
+                .setAudioBitRate(audioStream.map(fFmpegStream -> fFmpegStream.bit_rate).orElse(0L))
+                .setAudioChannels(1)
+                .setAudioCodec("aac")        // using the aac codec
+                .setAudioSampleRate(audioStream.get().sample_rate)
+                .setAudioBitRate(audioStream.get().bit_rate)
+                .setStrict(FFmpegBuilder.Strict.STRICT)
+                .setFormat("hls")
+                .setPreset("ultrafast")
+                .addExtraArgs("-vsync", "2", "-c:v", "copy", "-c:a", "copy", "-tune", "fastdecode", "-hls_time", "10", "-hls_list_size", "0", "-threads", "12")
+                .done();
+
+        FFmpegExecutor executor = new FFmpegExecutor(ffmpeg, ffprobe);
+        // Run a one-pass encode
+        executor.createJob(builder).run();
+
+        File dest = new File(filePathName);
+        if (dest.isFile() && dest.exists()) {
+            dest.delete();
+            System.gc();
+            log.warn("临时文件 {}已删除", dest.getName());
+        }
+        long endTime = System.currentTimeMillis();
+        log.info("文件:{} 转换完成!共耗时{} ms", dest.getName(), (endTime - startTime));
+        return m3u8FileName;
+    }
+
+}

+ 32 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/config/m3u8/SpringAsyncConfig.java

@@ -0,0 +1,32 @@
+package vip.xiaonuo.disk.config.m3u8;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+@Configuration
+@EnableAsync
+public class SpringAsyncConfig {
+    /**
+     * 线程池参数根据minIO设置,如果开启线程太多会被MinIO拒绝
+     * @return :
+     */
+    @Bean("minIOUploadTreadPool")
+    public ThreadPoolTaskExecutor  asyncServiceExecutorForMinIo() {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        // 设置核心线程数,采用IO密集 h/(1-拥塞)
+        executor.setCorePoolSize(6);
+        // 设置最大线程数,由于minIO连接数量有限,此处尽力设计大点
+        executor.setMaxPoolSize(500);
+        // 设置线程活跃时间(秒)
+        executor.setKeepAliveSeconds(30);
+        // 设置默认线程名称
+        executor.setThreadNamePrefix("minio-upload-task-");
+        // 等待所有任务结束后再关闭线程池
+        executor.setWaitForTasksToCompleteOnShutdown(true);
+        //执行初始化
+        executor.initialize();
+        return executor;
+    }
+}

+ 12 - 1
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/FileController.java

@@ -26,6 +26,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.util.ClassUtils;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
 import vip.xiaonuo.disk.component.AsyncTaskComp;
 import vip.xiaonuo.disk.component.FileDealComp;
@@ -36,6 +37,7 @@ import vip.xiaonuo.disk.dto.file.*;
 import vip.xiaonuo.disk.io.QiwenFile;
 import vip.xiaonuo.disk.service.IFileService;
 import vip.xiaonuo.disk.service.IUserFileService;
+import vip.xiaonuo.disk.service.M3u8UploadService;
 import vip.xiaonuo.disk.util.OperationLogUtil;
 import vip.xiaonuo.disk.util.QiwenFileUtil;
 import vip.xiaonuo.disk.util.TreeNode;
@@ -82,7 +84,8 @@ public class FileController {
     @Value("${common.account}")
     private String commonUserId;
 
-
+    @Resource
+    private M3u8UploadService m3u8UploadService;
 
 
     public static Executor executor = Executors.newFixedThreadPool(20);
@@ -1077,4 +1080,12 @@ public class FileController {
         return RestResult.success().data(vo);
     }
 
+
+    @Operation(summary = "m3u8格式转换测试", description = "m3u8格式转换测试", tags = {"file"})
+    @RequestMapping(value = "/m3u8Upload", method = RequestMethod.GET)
+    @ResponseBody
+    public RestResult<FileDetailVO> m3u8Upload(
+            @Parameter(description = "视频文件", required = true) MultipartFile file){
+        return RestResult.success().data(m3u8UploadService.m3u8Upload(file));
+    }
 }

+ 2 - 1
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/MinioController.java

@@ -7,6 +7,7 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.ResponseEntity;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
+import vip.xiaonuo.disk.domain.ResourceUserFile;
 import vip.xiaonuo.disk.domain.UploadFile;
 import vip.xiaonuo.disk.service.MinioService;
 import vip.xiaonuo.disk.util.MinioUtil;
@@ -57,7 +58,7 @@ public class MinioController {
     }
 
     @PostMapping("/checkMd5List")
-    public ResponseEntity<List<String>> checkFilesExits(@RequestBody List<UploadFile> genericItems){
+    public ResponseEntity<List<ResourceUserFile>> checkFilesExits(@RequestBody List<UploadFile> genericItems){
         return ResponseEntity.ok(minioUtil.checkFilesExits(genericItems));
     }
 }

+ 159 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/QuestionAnswerController.java

@@ -0,0 +1,159 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.controller;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.common.pojo.CommonValidList;
+import vip.xiaonuo.disk.domain.QuestionAnswer;
+import vip.xiaonuo.disk.param.QuestionAnswerAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerPageParam;
+import vip.xiaonuo.disk.service.QuestionAnswerService;
+import vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+import javax.validation.constraints.NotNull;
+
+/**
+ * question_answer控制器
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ */
+@Api(tags = "question_answer控制器")
+@ApiSupport(author = "SNOWY_TEAM", order = 1)
+@RestController
+@Validated
+public class QuestionAnswerController {
+
+    @Resource
+    private QuestionAnswerService questionAnswerService;
+
+    /**
+     * 获取question_answer分页
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("获取question_answer分页")
+    @GetMapping("/disk/answer/page")
+    public CommonResult<Page<QuestionAnswerVo>> page(QuestionAnswerPageParam questionAnswerPageParam) {
+        return CommonResult.data(questionAnswerService.page(questionAnswerPageParam));
+    }
+
+    /**
+     * 添加question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("添加question_answer")
+    @CommonLog("添加question_answer")
+    @PostMapping("/disk/answer/add")
+    public CommonResult<String> add(@RequestBody @Valid QuestionAnswerAddParam questionAnswerAddParam) {
+        questionAnswerService.add(questionAnswerAddParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 编辑question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("编辑question_answer")
+    @CommonLog("编辑question_answer")
+    @PostMapping("/disk/answer/edit")
+    public CommonResult<String> edit(@RequestBody @Valid QuestionAnswerEditParam questionAnswerEditParam) {
+        questionAnswerService.edit(questionAnswerEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("删除question_answer")
+    @CommonLog("删除question_answer")
+    @PostMapping("/disk/answer/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                                   CommonValidList<QuestionAnswerIdParam> questionAnswerIdParamList) {
+        questionAnswerService.delete(questionAnswerIdParamList);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取question_answer详情
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("获取question_answer详情")
+    @GetMapping("/disk/answer/detail")
+    public CommonResult<QuestionAnswer> detail(@Valid QuestionAnswerIdParam questionAnswerIdParam) {
+        return CommonResult.data(questionAnswerService.detail(questionAnswerIdParam));
+    }
+
+
+    /**
+     * 点赞
+     *
+     * @author pans
+     * @date  2025/06/27 11:07
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("点赞")
+    @CommonLog("点赞")
+    @GetMapping("/disk/answer/give")
+    public CommonResult<String> edit(@Valid @NotNull(message="主键id不能为空") Integer id) {
+        questionAnswerService.give(id);
+        return CommonResult.ok();
+    }
+
+
+    /**
+     * 取消点赞
+     *
+     * @author pans
+     * @date  2025/06/27 11:07
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("点赞")
+    @CommonLog("点赞")
+    @GetMapping("/disk/answer/giveCancel")
+    public CommonResult<String> giveCancel(@Valid @NotNull(message="主键id不能为空") Integer id) {
+        return CommonResult.ok(questionAnswerService.giveCancel(id));
+    }
+
+}

+ 132 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/controller/QuestionAnswerGiveController.java

@@ -0,0 +1,132 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
+import com.github.xiaoymin.knife4j.annotations.ApiSupport;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import vip.xiaonuo.common.annotation.CommonLog;
+import vip.xiaonuo.common.pojo.CommonResult;
+import vip.xiaonuo.common.pojo.CommonValidList;
+import vip.xiaonuo.disk.domain.QuestionAnswerGive;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGivePageParam;
+import vip.xiaonuo.disk.service.QuestionAnswerGiveService;
+
+import javax.annotation.Resource;
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
+
+/**
+ * question_answer_give控制器
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ */
+@Api(tags = "question_answer_give控制器")
+@ApiSupport(author = "SNOWY_TEAM", order = 1)
+@RestController
+@Validated
+public class QuestionAnswerGiveController {
+
+    @Resource
+    private QuestionAnswerGiveService questionAnswerGiveService;
+
+    /**
+     * 获取question_answer_give分页
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    @ApiOperationSupport(order = 1)
+    @ApiOperation("获取question_answer_give分页")
+    @SaCheckPermission("/disk/answergive/page")
+    @GetMapping("/disk/answergive/page")
+    public CommonResult<Page<QuestionAnswerGive>> page(QuestionAnswerGivePageParam questionAnswerGivePageParam) {
+        return CommonResult.data(questionAnswerGiveService.page(questionAnswerGivePageParam));
+    }
+
+    /**
+     * 添加question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    @ApiOperationSupport(order = 2)
+    @ApiOperation("添加question_answer_give")
+    @CommonLog("添加question_answer_give")
+    @SaCheckPermission("/disk/answergive/add")
+    @PostMapping("/disk/answergive/add")
+    public CommonResult<String> add(@RequestBody @Valid QuestionAnswerGiveAddParam questionAnswerGiveAddParam) {
+        questionAnswerGiveService.add(questionAnswerGiveAddParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 编辑question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    @ApiOperationSupport(order = 3)
+    @ApiOperation("编辑question_answer_give")
+    @CommonLog("编辑question_answer_give")
+    @SaCheckPermission("/disk/answergive/edit")
+    @PostMapping("/disk/answergive/edit")
+    public CommonResult<String> edit(@RequestBody @Valid QuestionAnswerGiveEditParam questionAnswerGiveEditParam) {
+        questionAnswerGiveService.edit(questionAnswerGiveEditParam);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 删除question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    @ApiOperationSupport(order = 4)
+    @ApiOperation("删除question_answer_give")
+    @CommonLog("删除question_answer_give")
+    @SaCheckPermission("/disk/answergive/delete")
+    @PostMapping("/disk/answergive/delete")
+    public CommonResult<String> delete(@RequestBody @Valid @NotEmpty(message = "集合不能为空")
+                                                   CommonValidList<QuestionAnswerGiveIdParam> questionAnswerGiveIdParamList) {
+        questionAnswerGiveService.delete(questionAnswerGiveIdParamList);
+        return CommonResult.ok();
+    }
+
+    /**
+     * 获取question_answer_give详情
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    @ApiOperationSupport(order = 5)
+    @ApiOperation("获取question_answer_give详情")
+    @SaCheckPermission("/disk/answergive/detail")
+    @GetMapping("/disk/answergive/detail")
+    public CommonResult<QuestionAnswerGive> detail(@Valid QuestionAnswerGiveIdParam questionAnswerGiveIdParam) {
+        return CommonResult.data(questionAnswerGiveService.detail(questionAnswerGiveIdParam));
+    }
+
+}

+ 95 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/QuestionAnswer.java

@@ -0,0 +1,95 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * question_answer实体
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+@Setter
+@TableName("question_answer")
+public class QuestionAnswer {
+
+    /** ID */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "ID", position = 1)
+    private Integer id;
+
+    /** PID */
+    @ApiModelProperty(value = "PID", position = 2)
+    private Integer pid;
+
+    /** NAME */
+    @ApiModelProperty(value = "NAME", position = 3)
+    private String name;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 4)
+    @TableField(value="user_id")
+    private String userId;
+
+    /** TIME */
+    @ApiModelProperty(value = "TIME", position = 5)
+    private Date time;
+
+    /** DESC */
+    @ApiModelProperty(value = "REMARK", position = 6)
+    private String remark;
+
+    /** DELETE_FLAG */
+    @ApiModelProperty(value = "DELETE_FLAG", position = 7)
+    @TableLogic
+    @TableField(fill = FieldFill.INSERT)
+    private String deleteFlag;
+
+    /** CREATE_TIME */
+    @ApiModelProperty(value = "CREATE_TIME", position = 8)
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /** CREATE_USER */
+    @ApiModelProperty(value = "CREATE_USER", position = 9)
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    /** UPDATE_TIME */
+    @ApiModelProperty(value = "UPDATE_TIME", position = 10)
+    @TableField(fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    /** UPDATE_USER */
+    @ApiModelProperty(value = "UPDATE_USER", position = 11)
+    @TableField(fill = FieldFill.UPDATE)
+    private String updateUser;
+
+
+
+    /** GIVE_NUM */
+    @ApiModelProperty(value = "GIVE_NUM", position = 13)
+    private Integer giveNum;
+
+
+    private  String courseId;
+
+    private  String chapterId;
+}

+ 71 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/QuestionAnswerGive.java

@@ -0,0 +1,71 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * question_answer_give实体
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+@Setter
+@TableName("question_answer_give")
+public class QuestionAnswerGive {
+
+    /** ID */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "ID", position = 1)
+    private Integer id;
+
+    /** QUESTION_ANSWERID */
+    @ApiModelProperty(value = "QUESTION_ANSWERID", position = 2)
+    private Integer questionAnswerid;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 3)
+    private String userId;
+
+    /** DELETE_FLAG */
+    @ApiModelProperty(value = "DELETE_FLAG", position = 4)
+    @TableLogic
+    @TableField(fill = FieldFill.INSERT)
+    private String deleteFlag;
+
+    /** CREATE_TIME */
+    @ApiModelProperty(value = "CREATE_TIME", position = 5)
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /** CREATE_USER */
+    @ApiModelProperty(value = "CREATE_USER", position = 6)
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    /** UPDATE_TIME */
+    @ApiModelProperty(value = "UPDATE_TIME", position = 7)
+    @TableField(fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    /** UPDATE_USER */
+    @ApiModelProperty(value = "UPDATE_USER", position = 8)
+    @TableField(fill = FieldFill.UPDATE)
+    private String updateUser;
+}

+ 2 - 3
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/domain/ResourceUserFile.java

@@ -21,9 +21,6 @@ import lombok.Setter;
 import vip.xiaonuo.common.util.PinyinUtils;
 import vip.xiaonuo.disk.io.QiwenFile;
 
-import java.math.BigDecimal;
-import java.util.Date;
-
 /**
  * RESOURCE_USERFILE实体
  *
@@ -111,6 +108,8 @@ public class ResourceUserFile {
     @ApiModelProperty(value = "FUNC_TYPE", position = 16)
     private String funcType;
 
+    @TableField(exist = false)
+    private String md5;
 
     public ResourceUserFile() {};
     public ResourceUserFile(QiwenFile qiwenFile, String userId, String fileId) {

+ 34 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/enums/QuestionAnswerEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.enums;
+
+import lombok.Getter;
+
+/**
+ * question_answer枚举
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+public enum QuestionAnswerEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    QuestionAnswerEnum(String value) {
+        this.value = value;
+    }
+}

+ 34 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/enums/QuestionAnswerGiveEnum.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.enums;
+
+import lombok.Getter;
+
+/**
+ * question_answer_give枚举
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+public enum QuestionAnswerGiveEnum {
+
+    /** 测试 */
+    TEST("TEST");
+
+    private final String value;
+
+    QuestionAnswerGiveEnum(String value) {
+        this.value = value;
+    }
+}

+ 27 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/QuestionAnswerGiveMapper.java

@@ -0,0 +1,27 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import vip.xiaonuo.disk.domain.QuestionAnswerGive;
+
+
+/**
+ * question_answer_giveMapper接口
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+public interface QuestionAnswerGiveMapper extends BaseMapper<QuestionAnswerGive> {
+    void updateQuestionAnswerGiveMapper(QuestionAnswerGive userCommentGive);
+}

+ 34 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/QuestionAnswerMapper.java

@@ -0,0 +1,34 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import vip.xiaonuo.disk.domain.QuestionAnswer;
+import vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo;
+
+import java.util.List;
+
+
+/**
+ * question_answerMapper接口
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+public interface QuestionAnswerMapper extends BaseMapper<QuestionAnswer> {
+    Page<QuestionAnswerVo> selectCommentPid(@Param("page") Page<Object> page, @Param("chapterId") String chapterId,@Param("courseId") String courseId, @Param("userId") String userId);
+
+    List<QuestionAnswerVo> selectCommentNoPid(@Param("chapterId") String chapterId, @Param("courseId") String courseId, @Param("userId") String userId);
+}

+ 4 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/ResourceUserFileMapper.java

@@ -29,4 +29,8 @@ public interface ResourceUserFileMapper extends BaseMapper<ResourceUserFile> {
     List<ResourceUserFile> selectUserFileByLikeRightFilePath(@Param("filePath") String filePath, @Param("userId") String userId);
 
     Long selectStorageSizeByUserId(@Param("userId") String userId);
+
+    ResourceUserFile selectUserFileId(String md5);
+
+    Integer selectUserFileIdCount(@Param("md5") String md5,@Param("userId") String userId);
 }

+ 10 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/QuestionAnswerGiveMapper.xml

@@ -0,0 +1,10 @@
+<?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="vip.xiaonuo.disk.mapper.QuestionAnswerGiveMapper">
+    <update id="updateQuestionAnswerGiveMapper">
+        UPDATE question_answer_give
+        SET DELETE_FLAG=#{deleteFlag}
+        WHERE
+            question_answerid = #{questionAnswerid}  AND  user_id = #{userId}
+    </update>
+</mapper>

+ 40 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/QuestionAnswerMapper.xml

@@ -0,0 +1,40 @@
+<?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="vip.xiaonuo.disk.mapper.QuestionAnswerMapper">
+
+       <select id="selectCommentPid" resultType="vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo">
+           SELECT
+               a.id,
+               a.pid,
+               a.name name,
+               a.user_id userId,
+               a.time,
+               ifnull(a.give_num,0) giveNum,
+               (SELECT count(1) FROM  question_answer_give WHERE question_answerid=a.id AND user_id=#{userId} and  delete_flag='NOT_DELETE') giveNumSelf,
+               b.name  userName
+           FROM
+               question_answer a LEFT JOIN  sys_user b ON a. user_id=b.id
+           WHERE
+               COURSE_ID=#{courseId} and CHAPTER_ID=#{chapterId}
+             and pid IS NULL
+           order by a.id desc,giveNum desc
+       </select>
+
+    <select id="selectCommentNoPid" resultType="vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo">
+        SELECT
+            a.id,
+            a.pid,
+            a.name commentName,
+            a.user_id userId,
+            a.time,
+            ifnull(a.give_num,0) giveNum,
+            (SELECT count(1) FROM  question_answer_give WHERE question_answerid=a.id AND user_id=#{userId} and  delete_flag='NOT_DELETE') giveNumSelf,
+            b.name  userName
+        FROM
+            question_answer a LEFT JOIN  sys_user b ON a. user_id=b.id
+        WHERE
+            COURSE_ID=#{courseId} and CHAPTER_ID=#{chapterId}
+          and	pid IS NOT NULL
+    </select>
+
+</mapper>

+ 54 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/mapper/mapping/ResourceUserFileMapper.xml

@@ -13,6 +13,60 @@
                                        LEFT JOIN RESOURCE_FILE ON RESOURCE_FILE.FILE_ID = RESOURCE_USERFILE.FILE_ID
         WHERE RESOURCE_USERFILE.USER_ID = #{userId}
     </select>
+      <select id="selectUserFileId" resultType="vip.xiaonuo.disk.domain.ResourceUserFile">
+          SELECT
+              CREATE_TIME createTime,
+              CREATE_USER_ID createUserId,
+              DELETE_BATCH_NUM deleteBatchNum,
+              DELETE_TIME deleteFlag,
+              EXTEND_NAME extendName,
+              FILE_ID fileId,
+              FILE_NAME fileName,
+              FILE_PATH filePath,
+              IS_DIR isDir,
+              MODIFY_TIME modifyTime,
+              MODIFY_USER_ID modifyUserId,
+              UPLOAD_TIME uploadTime,
+              USER_ID userId,
+              IS_COLLET isCollet,
+              FILE_NAME_PINYIN fileNamePinyin,
+              FUNC_TYPE funcType,
+              DELETE_FLAG deleteFlag,
+              CREATE_USER createUser,
+              UPDATE_TIME uploadTime,
+              UPDATE_USER uploadUser
+          FROM
+              RESOURCE_USERFILE
+          WHERE
+              FILE_ID =(
+                  SELECT
+                      FILE_ID
+                  FROM
+                      RESOURCE_FILE
+                  WHERE
+                      IDENTIFIER = #{md5}
+              )
+          order by  CREATE_TIME desc
+          LIMIT 1
+      </select>
 
 
+    <select id="selectUserFileIdCount" resultType="java.lang.Integer">
+        SELECT
+          count(distinct USER_FILE_ID) num
+        FROM
+            RESOURCE_USERFILE
+        WHERE
+            FILE_ID =(
+                SELECT
+                    FILE_ID
+                FROM
+                    RESOURCE_FILE
+                WHERE
+                    IDENTIFIER = #{md5}
+            ) and USER_ID = #{userId}
+            order by  CREATE_TIME desc
+            LIMIT 1
+    </select>
+
 </mapper>

+ 63 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerAddParam.java

@@ -0,0 +1,63 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * question_answer添加参数
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+@Setter
+public class QuestionAnswerAddParam {
+
+    /** PID */
+    @ApiModelProperty(value = "PID", position = 2)
+    private Integer pid;
+
+    /** NAME */
+    @ApiModelProperty(value = "NAME", position = 3)
+    private String name;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 4)
+    private String userId;
+
+    /** TIME */
+    @ApiModelProperty(value = "TIME", position = 5)
+    private Date time;
+
+    /** DESC */
+    @ApiModelProperty(value = "REMARK", position = 6)
+    private String remark;
+
+    /** RESOURCE_ID */
+    @ApiModelProperty(value = "RESOURCE_ID", position = 12)
+    private String resourceId;
+
+    /** GIVE_NUM */
+    @ApiModelProperty(value = "GIVE_NUM", position = 13)
+    private String giveNum;
+
+    private  String courseId;
+
+    private  String chapterId;
+
+}

+ 71 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerEditParam.java

@@ -0,0 +1,71 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+import java.util.Date;
+
+/**
+ * question_answer编辑参数
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+@Setter
+public class QuestionAnswerEditParam {
+
+    /** ID */
+    @ApiModelProperty(value = "ID", required = true, position = 1)
+    @NotNull(message = "id不能为空")
+    private Integer id;
+
+    /** PID */
+    @ApiModelProperty(value = "PID", position = 2)
+    private Integer pid;
+
+    /** NAME */
+    @ApiModelProperty(value = "NAME", position = 3)
+    private String name;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 4)
+    private String userId;
+
+    /** TIME */
+    @ApiModelProperty(value = "TIME", position = 5)
+    private Date time;
+
+    /** DESC */
+    @ApiModelProperty(value = "REMARK", position = 6)
+    private String remark;
+
+    /** RESOURCE_ID */
+    @ApiModelProperty(value = "RESOURCE_ID", position = 12)
+    private String resourceId;
+
+    /** GIVE_NUM */
+    @ApiModelProperty(value = "GIVE_NUM", position = 13)
+    private String giveNum;
+
+    private  String courseId;
+
+    private  String chapterId;
+
+
+
+}

+ 42 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveAddParam.java

@@ -0,0 +1,42 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * question_answer_give添加参数
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+@Setter
+public class QuestionAnswerGiveAddParam {
+
+    /** QUESTION_ANSWERID */
+    @ApiModelProperty(value = "QUESTION_ANSWERID", position = 2)
+    private Integer questionAnswerid;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 3)
+    private String userId;
+
+}

+ 44 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveEditParam.java

@@ -0,0 +1,44 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * question_answer_give编辑参数
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+@Setter
+public class QuestionAnswerGiveEditParam {
+
+    /** ID */
+    @ApiModelProperty(value = "ID", required = true, position = 1)
+    @NotNull(message = "id不能为空")
+    private Long id;
+
+    /** QUESTION_ANSWERID */
+    @ApiModelProperty(value = "QUESTION_ANSWERID", position = 2)
+    private Integer questionAnswerid;
+
+    /** USER_ID */
+    @ApiModelProperty(value = "USER_ID", position = 3)
+    private String userId;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGiveIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * question_answer_giveId参数
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+@Setter
+public class QuestionAnswerGiveIdParam {
+
+    /** ID */
+    @ApiModelProperty(value = "ID", required = true)
+    @NotBlank(message = "id不能为空")
+    private Long id;
+}

+ 51 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerGivePageParam.java

@@ -0,0 +1,51 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * question_answer_give查询参数
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Getter
+@Setter
+public class QuestionAnswerGivePageParam {
+
+    /** 当前页 */
+    @ApiModelProperty(value = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @ApiModelProperty(value = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @ApiModelProperty(value = "关键词")
+    private String searchKey;
+
+}

+ 35 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerIdParam.java

@@ -0,0 +1,35 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import javax.validation.constraints.NotNull;
+
+/**
+ * question_answerId参数
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+@Setter
+public class QuestionAnswerIdParam {
+
+    /** ID */
+    @ApiModelProperty(value = "ID", required = true)
+    @NotNull(message = "id不能为空")
+    private Integer id;
+}

+ 53 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/param/QuestionAnswerPageParam.java

@@ -0,0 +1,53 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.param;
+
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * question_answer查询参数
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Getter
+@Setter
+public class QuestionAnswerPageParam {
+
+    /** 当前页 */
+    @ApiModelProperty(value = "当前页码")
+    private Integer current;
+
+    /** 每页条数 */
+    @ApiModelProperty(value = "每页条数")
+    private Integer size;
+
+    /** 排序字段 */
+    @ApiModelProperty(value = "排序字段,字段驼峰名称,如:userName")
+    private String sortField;
+
+    /** 排序方式 */
+    @ApiModelProperty(value = "排序方式,升序:ASCEND;降序:DESCEND")
+    private String sortOrder;
+
+    /** 关键词 */
+    @ApiModelProperty(value = "关键词")
+    private String searchKey;
+
+    private String courseId;
+
+    private String chapterId;
+
+}

+ 7 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/M3u8UploadService.java

@@ -0,0 +1,7 @@
+package vip.xiaonuo.disk.service;
+
+import org.springframework.web.multipart.MultipartFile;
+
+public interface M3u8UploadService {
+    String m3u8Upload(MultipartFile file);
+}

+ 81 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/QuestionAnswerGiveService.java

@@ -0,0 +1,81 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.disk.domain.QuestionAnswerGive;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGivePageParam;
+
+import java.util.List;
+
+/**
+ * question_answer_giveService接口
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+public interface QuestionAnswerGiveService extends IService<QuestionAnswerGive> {
+
+    /**
+     * 获取question_answer_give分页
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    Page<QuestionAnswerGive> page(QuestionAnswerGivePageParam questionAnswerGivePageParam);
+
+    /**
+     * 添加question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    void add(QuestionAnswerGiveAddParam questionAnswerGiveAddParam);
+
+    /**
+     * 编辑question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    void edit(QuestionAnswerGiveEditParam questionAnswerGiveEditParam);
+
+    /**
+     * 删除question_answer_give
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    void delete(List<QuestionAnswerGiveIdParam> questionAnswerGiveIdParamList);
+
+    /**
+     * 获取question_answer_give详情
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     */
+    QuestionAnswerGive detail(QuestionAnswerGiveIdParam questionAnswerGiveIdParam);
+
+    /**
+     * 获取question_answer_give详情
+     *
+     * @author pans
+     * @date  2025/07/11 19:32
+     **/
+    QuestionAnswerGive queryEntity(Long id);
+
+}

+ 87 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/QuestionAnswerService.java

@@ -0,0 +1,87 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.service;
+
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.IService;
+import vip.xiaonuo.disk.domain.QuestionAnswer;
+import vip.xiaonuo.disk.param.QuestionAnswerAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerPageParam;
+import vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo;
+
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+/**
+ * question_answerService接口
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+public interface QuestionAnswerService extends IService<QuestionAnswer> {
+
+    /**
+     * 获取question_answer分页
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    Page<QuestionAnswerVo> page(QuestionAnswerPageParam questionAnswerPageParam);
+
+    /**
+     * 添加question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    void add(QuestionAnswerAddParam questionAnswerAddParam);
+
+    /**
+     * 编辑question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    void edit(QuestionAnswerEditParam questionAnswerEditParam);
+
+    /**
+     * 删除question_answer
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    void delete(List<QuestionAnswerIdParam> questionAnswerIdParamList);
+
+    /**
+     * 获取question_answer详情
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     */
+    QuestionAnswer detail(QuestionAnswerIdParam questionAnswerIdParam);
+
+    /**
+     * 获取question_answer详情
+     *
+     * @author pans
+     * @date  2025/07/11 18:52
+     **/
+    QuestionAnswer queryEntity(Integer id);
+
+    void give(@Valid @NotNull(message="主键id不能为空") Integer id);
+
+    String giveCancel(@Valid @NotNull(message="主键id不能为空") Integer id);
+}

+ 128 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/M3u8UploadServiceImpl.java

@@ -0,0 +1,128 @@
+package vip.xiaonuo.disk.service.impl;
+
+import cn.hutool.core.date.DateUtil;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import org.springframework.web.multipart.MultipartFile;
+import vip.xiaonuo.disk.config.m3u8.FilePath;
+import vip.xiaonuo.disk.config.m3u8.M3u8Component;
+import vip.xiaonuo.disk.service.M3u8UploadService;
+import vip.xiaonuo.disk.util.FileUtil;
+import vip.xiaonuo.disk.util.MinioUtil;
+import javax.annotation.Resource;
+import java.io.File;
+import java.io.FileInputStream;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.concurrent.CountDownLatch;
+
+/**
+ * @PackageName:vip.xiaonuo.exam.service.impl
+ * @ClassName:M3u8UploadServiceImpl
+ * @Author ZSS
+ * @Date 2025-07-14 18:33
+ * @Note: m3u8上传服务实现类
+ **/
+@Service
+@Slf4j
+public class M3u8UploadServiceImpl implements M3u8UploadService {
+
+    //@Resource
+    private FilePath filePath;
+
+    //@Autowired
+    private MinioUtil minioUtil;
+
+    @Resource(name = "minIOUploadTreadPool")
+    private ThreadPoolTaskExecutor poolTaskExecutor;
+
+    //@Resource
+    private M3u8Component m3U8ComponentTemplate;
+
+    @Override
+    public String m3u8Upload(MultipartFile file) {
+        return mediaFileToM3u8(file);
+    }
+
+
+    /**
+     * 上传视频转m3u8后上传至minIO
+     */
+    public String mediaFileToM3u8(MultipartFile file){
+        String paths = m3U8ComponentTemplate.mediaFileToM3u8(file);
+        return upload2M3u8(paths);
+    }
+
+    /**
+     * 本地视频转m3u8后上传至minIO
+     */
+    public String localVideo2M3u8(String path){
+        String paths = m3U8ComponentTemplate.localFileToM3u8(path);
+        return upload2M3u8(paths);
+    }
+
+
+
+    /**
+     * 上传转码后得视频至OSS或minIOn
+     * @return 路径
+     */
+    public String upload2M3u8(String path) {
+        try {
+            //存储转码后文件
+            String realPath = path.substring(0, path.lastIndexOf(File.separator));
+            log.info("视频解析后的 realPath {}", realPath);
+            String name = path.substring(path.lastIndexOf(File.separator) + 1);
+            log.info("解析后视频 name {}", name);
+            File allFile = new File(realPath);
+            File[] files = allFile.listFiles();
+            if (null == files || files.length == 0) {
+                return null;
+            }
+            String patch = DateUtil.format(LocalDateTime.now(), "yyyy/MM/") + name.substring(0, name.lastIndexOf(".")) + "/";
+            List<File> errorFile = new ArrayList<>();
+
+            long start = System.currentTimeMillis();
+            //替换m3u8文件中的路径
+            FileUtil.replaceTextContent(path, name.substring(0, name.lastIndexOf(".")),
+                    filePath.getProxyURL() + filePath.getProxy() + patch +
+                            name.substring(0, name.lastIndexOf(".")));
+            //开始上传
+            CountDownLatch countDownLatch = new CountDownLatch(files.length);
+            Arrays.stream(files).forEach(li -> poolTaskExecutor.execute(() -> {
+                try (FileInputStream fileInputStream = new FileInputStream(li)) {
+                    minioUtil.FileUploaderExist("m3u8", patch + li.getName(), fileInputStream);
+                    log.info("文件:{} 正在上传", li.getName());
+                } catch (Exception e) {
+                    errorFile.add(li);
+                    e.printStackTrace();
+                } finally {
+                    countDownLatch.countDown();
+                }
+            }));
+            countDownLatch.await();
+            long end = System.currentTimeMillis();
+            log.info("解析文件上传成功,共计:{} 个文件,失败:{},共耗时: {}ms", files.length, errorFile.size(), end - start);
+
+            //异步移除所有文件
+            poolTaskExecutor.execute(() -> {
+                FileUtil.deleteFolder(realPath);
+            });
+            if (CollectionUtils.isEmpty(errorFile)) {
+                String resultUrl = filePath.getProxyURL() + filePath.getProxy() + patch + name;
+                resultUrl = resultUrl.replaceAll("\\\\", "/");
+                return resultUrl;
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return "";
+    }
+
+
+}

+ 96 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/QuestionAnswerGiveServiceImpl.java

@@ -0,0 +1,96 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.common.enums.CommonSortOrderEnum;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.disk.domain.QuestionAnswerGive;
+import vip.xiaonuo.disk.mapper.QuestionAnswerGiveMapper;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGiveIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerGivePageParam;
+import vip.xiaonuo.disk.service.QuestionAnswerGiveService;
+
+import java.util.List;
+
+/**
+ * question_answer_giveService接口实现类
+ *
+ * @author pans
+ * @date  2025/07/11 19:32
+ **/
+@Service
+public class QuestionAnswerGiveServiceImpl extends ServiceImpl<QuestionAnswerGiveMapper, QuestionAnswerGive> implements QuestionAnswerGiveService {
+
+
+    @Override
+    public Page<QuestionAnswerGive> page(QuestionAnswerGivePageParam questionAnswerGivePageParam) {
+        QueryWrapper<QuestionAnswerGive> queryWrapper = new QueryWrapper<>();
+        if(ObjectUtil.isAllNotEmpty(questionAnswerGivePageParam.getSortField(), questionAnswerGivePageParam.getSortOrder())) {
+            CommonSortOrderEnum.validate(questionAnswerGivePageParam.getSortOrder());
+            queryWrapper.orderBy(true, questionAnswerGivePageParam.getSortOrder().equals(CommonSortOrderEnum.ASC.getValue()),
+                    StrUtil.toUnderlineCase(questionAnswerGivePageParam.getSortField()));
+        } else {
+            queryWrapper.lambda().orderByAsc(QuestionAnswerGive::getId);
+        }
+        return this.page(CommonPageRequest.defaultPage(), queryWrapper);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void add(QuestionAnswerGiveAddParam questionAnswerGiveAddParam) {
+        QuestionAnswerGive questionAnswerGive = BeanUtil.toBean(questionAnswerGiveAddParam, QuestionAnswerGive.class);
+        this.save(questionAnswerGive);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void edit(QuestionAnswerGiveEditParam questionAnswerGiveEditParam) {
+        QuestionAnswerGive questionAnswerGive = this.queryEntity(questionAnswerGiveEditParam.getId());
+        BeanUtil.copyProperties(questionAnswerGiveEditParam, questionAnswerGive);
+        this.updateById(questionAnswerGive);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<QuestionAnswerGiveIdParam> questionAnswerGiveIdParamList) {
+        // 执行删除
+        this.removeByIds(CollStreamUtil.toList(questionAnswerGiveIdParamList, QuestionAnswerGiveIdParam::getId));
+    }
+
+    @Override
+    public QuestionAnswerGive detail(QuestionAnswerGiveIdParam questionAnswerGiveIdParam) {
+        return this.queryEntity(questionAnswerGiveIdParam.getId());
+    }
+
+    @Override
+    public QuestionAnswerGive queryEntity(Long id) {
+        QuestionAnswerGive questionAnswerGive = this.getById(id);
+        if(ObjectUtil.isEmpty(questionAnswerGive)) {
+            throw new CommonException("question_answer_give不存在,id值为:{}", id);
+        }
+        return questionAnswerGive;
+    }
+
+}

+ 156 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/service/impl/QuestionAnswerServiceImpl.java

@@ -0,0 +1,156 @@
+/*
+ * Copyright [2022] [https://www.xiaonuo.vip]
+ *
+ * Snowy采用APACHE LICENSE 2.0开源协议,您在使用过程中,需要注意以下几点:
+ *
+ * 1.请不要删除和修改根目录下的LICENSE文件。
+ * 2.请不要删除和修改Snowy源码头部的版权声明。
+ * 3.本项目代码可免费商业使用,商业使用请保留源码和相关描述文件的项目出处,作者声明等。
+ * 4.分发源码时候,请注明软件出处 https://www.xiaonuo.vip
+ * 5.不可二次分发开源参与同类竞品,如有想法可联系团队xiaonuobase@qq.com商议合作。
+ * 6.若您的项目无法满足以上几点,需要更多功能代码,获取Snowy商业授权许可,请在官网购买授权,地址为 https://www.xiaonuo.vip
+ */
+package vip.xiaonuo.disk.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollStreamUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import vip.xiaonuo.auth.core.util.StpLoginUserUtil;
+import vip.xiaonuo.common.exception.CommonException;
+import vip.xiaonuo.common.page.CommonPageRequest;
+import vip.xiaonuo.disk.domain.QuestionAnswer;
+import vip.xiaonuo.disk.domain.QuestionAnswerGive;
+import vip.xiaonuo.disk.mapper.QuestionAnswerGiveMapper;
+import vip.xiaonuo.disk.mapper.QuestionAnswerMapper;
+import vip.xiaonuo.disk.param.QuestionAnswerAddParam;
+import vip.xiaonuo.disk.param.QuestionAnswerEditParam;
+import vip.xiaonuo.disk.param.QuestionAnswerIdParam;
+import vip.xiaonuo.disk.param.QuestionAnswerPageParam;
+import vip.xiaonuo.disk.service.QuestionAnswerService;
+import vip.xiaonuo.disk.vo.questionanswer.QuestionAnswerVo;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * question_answerService接口实现类
+ *
+ * @author pans
+ * @date  2025/07/11 18:52
+ **/
+@Service
+public class QuestionAnswerServiceImpl extends ServiceImpl<QuestionAnswerMapper, QuestionAnswer> implements QuestionAnswerService {
+
+
+    @Resource
+    private  QuestionAnswerMapper questionAnswerMapper;
+
+    @Resource
+    private QuestionAnswerGiveMapper questionAnswerGiveMapper;
+
+    @Override
+    public Page<QuestionAnswerVo> page(QuestionAnswerPageParam questionAnswerPageParam) {
+        Page<QuestionAnswerVo> page=questionAnswerMapper.selectCommentPid(CommonPageRequest.defaultPage(),questionAnswerPageParam.getChapterId(), questionAnswerPageParam.getCourseId(),StpLoginUserUtil.getLoginUser().getId());
+        List<QuestionAnswerVo> list=questionAnswerMapper.selectCommentNoPid(questionAnswerPageParam.getChapterId(), questionAnswerPageParam.getCourseId(),StpLoginUserUtil.getLoginUser().getId());
+        page.getRecords().stream().forEach(item -> {
+            List<QuestionAnswerVo> child= list.stream().filter(itemchild-> itemchild.getPid().equals(item.getId())).collect(Collectors.toList());
+            item.setChild(child);
+            item.setChildSize(child.size());
+        });
+
+        return page;
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void add(QuestionAnswerAddParam questionAnswerAddParam) {
+        QuestionAnswer questionAnswer = BeanUtil.toBean(questionAnswerAddParam, QuestionAnswer.class);
+        questionAnswer.setUserId(StpLoginUserUtil.getLoginUser().getId());
+        questionAnswer.setTime(new Date());
+        this.save(questionAnswer);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void edit(QuestionAnswerEditParam questionAnswerEditParam) {
+        QuestionAnswer questionAnswer = this.queryEntity(questionAnswerEditParam.getId());
+        BeanUtil.copyProperties(questionAnswerEditParam, questionAnswer);
+        questionAnswer.setUserId(StpLoginUserUtil.getLoginUser().getId());
+        questionAnswer.setTime(new Date());
+        this.updateById(questionAnswer);
+    }
+
+    @Transactional(rollbackFor = Exception.class)
+    @Override
+    public void delete(List<QuestionAnswerIdParam> questionAnswerIdParamList) {
+        // 执行删除
+        this.removeByIds(CollStreamUtil.toList(questionAnswerIdParamList, QuestionAnswerIdParam::getId));
+    }
+
+    @Override
+    public QuestionAnswer detail(QuestionAnswerIdParam questionAnswerIdParam) {
+        return this.queryEntity(questionAnswerIdParam.getId());
+    }
+
+    @Override
+    public QuestionAnswer queryEntity(Integer id) {
+        QuestionAnswer questionAnswer = this.getById(id);
+        if(ObjectUtil.isEmpty(questionAnswer)) {
+            throw new CommonException("question_answer不存在,id值为:{}", id);
+        }
+        return questionAnswer;
+    }
+
+
+
+
+
+    @Override
+    public void give(Integer id) {
+        QuestionAnswer userComment=queryEntity(id);
+        if(ObjectUtil.isEmpty(userComment.getGiveNum())) {
+            userComment.setGiveNum(1);
+        }else{
+            userComment.setGiveNum(userComment.getGiveNum()+1);
+        }
+        this.updateById(userComment);
+        //添加点赞记录表
+        QuestionAnswerGive userCommentGive=new QuestionAnswerGive();
+        userCommentGive.setUserId(StpLoginUserUtil.getLoginUser().getId());
+        userCommentGive.setCreateUser(StpLoginUserUtil.getLoginUser().getId());
+        userCommentGive.setQuestionAnswerid(id);
+        userCommentGive.setCreateTime(new Date());
+        userCommentGive.setDeleteFlag("NOT_DELETE");
+        questionAnswerGiveMapper.insert(userCommentGive);
+    }
+
+    @Override
+    public String giveCancel(Integer id) {
+        QuestionAnswer userComment=queryEntity(id);
+        if(userComment.getGiveNum()>0){
+            userComment.setGiveNum(userComment.getGiveNum()-1);
+            this.updateById(userComment);
+            //删除点赞记录表
+            QuestionAnswerGive userCommentGive=new QuestionAnswerGive();
+            userCommentGive.setQuestionAnswerid(id);
+            userCommentGive.setUserId(StpLoginUserUtil.getLoginUser().getId());
+            userCommentGive.setDeleteFlag("DELETED");
+            questionAnswerGiveMapper.updateQuestionAnswerGiveMapper(userCommentGive);
+            return "取消点赞成功!";
+        }else{
+            return "点赞数量为0,无法取消点赞!";
+        }
+    }
+
+
+
+
+
+
+}

+ 61 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/FileUtil.java

@@ -0,0 +1,61 @@
+package vip.xiaonuo.disk.util;
+
+import java.io.*;
+
+public class FileUtil {
+
+    public static void deleteFiles(String path) {
+        File file = new File(path);
+        if (file.exists()) {
+            if (file.isDirectory()) {
+                File[] temp = file.listFiles(); //获取该文件夹下的所有文件
+                for (File value : temp) {
+                    deleteFile(value.getAbsolutePath());
+                }
+            } else {
+                file.delete(); //删除子文件
+            }
+            file.delete(); //删除文件夹
+        }
+    }
+
+    public static void deleteFile(String path){
+        File dest = new File(path);
+        if (dest.isFile() && dest.exists()) {
+            dest.delete();
+        }
+    }
+
+    public static void deleteFolder(String folderPath){
+        if(cn.hutool.core.io.FileUtil.exist(folderPath)){
+            cn.hutool.core.io.FileUtil.del(folderPath);
+        }
+    }
+
+    public static void replaceTextContent(String path,String srcStr,String replaceStr) throws IOException {
+        // 读
+        File file = new File(path);
+        FileReader in = new FileReader(file);
+        BufferedReader bufIn = new BufferedReader(in);
+        // 内存流, 作为临时流
+        CharArrayWriter tempStream = new CharArrayWriter();
+        // 替换
+        String line = null;
+        while ( (line = bufIn.readLine()) != null) {
+            // 替换每行中, 符合条件的字符串
+            line = line.replaceAll(srcStr, replaceStr);
+            // 将该行写入内存
+            tempStream.write(line);
+            // 添加换行符
+            tempStream.append(System.getProperty("line.separator"));
+        }
+        // 关闭 输入流
+        bufIn.close();
+        // 将内存中的流 写入 文件
+        FileWriter out = new FileWriter(file);
+        tempStream.writeTo(out);
+        out.close();
+        System.out.println("====path:"+path);
+
+    }
+}

+ 64 - 13
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/MinioUtil.java

@@ -1,6 +1,8 @@
 package vip.xiaonuo.disk.util;
 
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollectionUtil;
 import com.alibaba.fastjson2.JSON;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.qiwenshare.common.util.DateUtil;
@@ -102,25 +104,50 @@ public class MinioUtil {
      * @param md5List
      * @return
      */
-    public List<String> checkFilesExits(List<UploadFile> md5List) {
+    public List<ResourceUserFile> checkFilesExits(List<UploadFile> md5List) {
 
-        ArrayList<String> noExitList = new ArrayList<>();
+        List<ResourceUserFile> noExitList = new ArrayList<>();
         md5List.forEach(item -> {
-            try {
                 //根据文件名称查询userFileId
-                String fileSuffix=item.getFileSuffix().substring(1, item.getFileSuffix().length());
-                String fileUrl = UFOPUtils.getUploadFileUrl(item.getMd5(), fileSuffix);
-                logger.info("校验是否存在的文件名是: "+fileUrl);
-                minioClient.statObject(StatObjectArgs.builder().bucket(bucket).object(fileUrl).build());
-            } catch (Exception e) {
-                logger.info("该文件需要上传,md5值是:" + item.getMd5());
-                // 未存在的文件添加到队列中,前端仍需上传
-                noExitList.add(item.getMd5());
-            }
+                Map<String, Object> param = new HashMap<>();
+                //看看该md5批次号有没有对应存在的文件
+                param.put("identifier", item.getMd5());
+                List<ResourceFile> list = resourceFileMapper.selectByMap(param);
+               if(CollectionUtil.isNotEmpty(list)&&list.size()==1){
+                   //根据md5值查询已上传的文件
+                   ResourceUserFile userFile=resourceUserFileMapper.selectUserFileId(item.getMd5());
+                   Integer userFileCount=resourceUserFileMapper.selectUserFileIdCount(item.getMd5(),StpLoginUserUtil.getLoginUser().getId());
+                   if(userFileCount==0){
+                       ResourceUserFile newUserFile=new  ResourceUserFile();
+                       BeanUtil.copyProperties(userFile, newUserFile);
+                       newUserFile.setIsDir(0);
+                       newUserFile.setMd5(item.getMd5());
+                       resourceUserFileMapper.insert(newUserFile);
+                       noExitList.add(newUserFile);
+                   }else{
+                       ResourceUserFile newUserFile=new  ResourceUserFile();
+                       BeanUtil.copyProperties(userFile, newUserFile);
+                       String fileName=item.getFileName().substring(0,item.getFileName().lastIndexOf("."));
+                       newUserFile.setFileName(fileName+"("+userFileCount+")"+item.getFileSuffix());
+                       newUserFile.setMd5(item.getMd5());
+                       newUserFile.setIsDir(0);
+                       resourceUserFileMapper.insert(newUserFile);
+                       noExitList.add(newUserFile);
+                   }
+               }else{
+                   logger.info("该文件需要上传,md5值是:" + item.getMd5());
+                   ResourceUserFile newUserFile=new  ResourceUserFile();
+                   newUserFile.setMd5(item.getMd5());
+                   newUserFile.setIsDir(0);
+                   // 未存在的文件添加到队列中,前端仍需上传
+                   noExitList.add(newUserFile);
+               }
+
         });
         return noExitList;
     }
 
+
     /**
      * 上传文件分块
      *
@@ -352,11 +379,12 @@ public class MinioUtil {
             }
         }
         ExecutorService threadPool = CheckThreadPool.getExecutor();
+        String userId = StpLoginUserUtil.getLoginUser().getId();
         try {
             threadPool.execute(() -> {
                 TranscodingResourceReqDTO transcodingResourceReqDTO = new TranscodingResourceReqDTO();
                 transcodingResourceReqDTO.setUserFileId(resourceUserFile.getUserFileId());
-                transcodingResourceReqDTO.setUserId(StpLoginUserUtil.getLoginUser().getId());
+                transcodingResourceReqDTO.setUserId(userId);
                 kafKaProducerUtil.sendTranscodingResource(producer.getProducer(), JSON.toJSONString(transcodingResourceReqDTO));
             });
         } catch (Exception e) {
@@ -408,6 +436,7 @@ public class MinioUtil {
         }
         resourceFileDealComp.parseMusicFile(qiwenFile.getExtendName(), 3, url, file.getFileId());
         Map<String, Object> map = new HashMap();
+        map.put("md5", resourceUserFile.getMd5());
         map.put("userFileId", resourceUserFile.getUserFileId());
         map.put("rs", true);
         return map;
@@ -504,4 +533,26 @@ public class MinioUtil {
 
     }
 
+    /**
+     * 使用putObject上传一个文件到文件分类
+     *
+     * @param bucket   : bucket名称
+     * @param fileName : 文件名
+     * @param stream   : 文件流
+     * @throws Exception : 异常
+     */
+    public void FileUploaderExist(String bucket, String fileName, InputStream stream) throws Exception {
+        PutObjectArgs.Builder putObjectArgsBuilder = PutObjectArgs.builder()
+                .bucket(bucket.toLowerCase())
+                .object(fileName)
+                .stream(stream, stream.available(), -1);
+        if (fileName.contains(".m3u8")) {
+            putObjectArgsBuilder.contentType("application/vnd.apple.mpegurl");
+        } else if (fileName.contains(".ts")) {
+            putObjectArgsBuilder.contentType("video/MP2T");
+        } else {
+            putObjectArgsBuilder.contentType("application/octet-stream");
+        }
+        minioClient.putObject(putObjectArgsBuilder.build());
+    }
 }

+ 52 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/util/m3u8Util.java

@@ -0,0 +1,52 @@
+package vip.xiaonuo.disk.util;
+
+import cn.hutool.core.date.DateUtil;
+import cn.hutool.core.io.FileUtil;
+import cn.hutool.core.util.StrUtil;
+
+import java.io.File;
+import java.time.LocalDateTime;
+
+/**
+ * @Description 工具类
+ * @Author sirwsl
+ * @Version 1.0
+ */
+public class m3u8Util {
+
+    /**
+    *@Description 根据基础路径,生成文件存储路径
+    *@param basePath 基础路径(根路径)
+    *@Return
+    */
+    public static String generateFilePath(String basePath){
+        String temp = basePath;
+        if(StrUtil.isNotBlank(basePath)){
+            if(basePath.endsWith(File.separator)){
+                temp = basePath.substring(0,basePath.lastIndexOf(File.separator));
+            }
+        }
+        return temp + File.separator + generateDateDir() + File.separator;
+    }
+
+    /**
+     *@Description 根据当前时间,生成下级存储目录
+     *@Return
+     */
+    public static String generateDateDir(){
+        LocalDateTime now = LocalDateTime.now();
+        return DateUtil.format(now, "yyyyMMdd"+File.separator+"HH"+File.separator+"mm"+File.separator+"ss"+File.separator+"SSS");
+    }
+
+    /**
+     *@Description 根据文件全路径,获取文件主名称
+     *@param fullPath 文件全路径(包含文件名)
+     *@Return
+     */
+    public static String getFileMainName(String fullPath){
+        String fileName = FileUtil.getName(fullPath);
+        return fileName.substring(0,fileName.lastIndexOf("."));
+    }
+
+
+}

+ 81 - 0
snowy-plugin/snowy-plugin-disk/snowy-plugin-disk-func/src/main/java/vip/xiaonuo/disk/vo/questionanswer/QuestionAnswerVo.java

@@ -0,0 +1,81 @@
+package vip.xiaonuo.disk.vo.questionanswer;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+import java.util.List;
+
+
+@Getter
+@Setter
+public class QuestionAnswerVo {
+    /** 主键id */
+    @TableId(type = IdType.AUTO)
+    @ApiModelProperty(value = "主键id", position = 1)
+    private Integer id;
+
+    /** 父级id */
+    @ApiModelProperty(value = "父级id", position = 2)
+    private Integer pid;
+
+    /** 评论名称 */
+    @ApiModelProperty(value = "名称", position = 3)
+    private String name;
+
+    /** 用户id */
+    @ApiModelProperty(value = "用户id", position = 4)
+    private String userId;
+
+    /** 用户名称 */
+    @ApiModelProperty(value = "用户名称", position = 4)
+    private String userName;
+
+
+    /** 评论时间 */
+    @ApiModelProperty(value = "评论时间", position = 5)
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date time;
+
+    /** 删除1, 未删除 0 */
+    @ApiModelProperty(value = "删除1, 未删除 0", position = 6)
+    @TableLogic
+    @TableField(fill = FieldFill.INSERT)
+    private String deleteFlag;
+
+    /** 点赞量 */
+    @ApiModelProperty(value = "点赞量", position = 7)
+    private Integer giveNum;
+
+    /** 创建时间 */
+    @ApiModelProperty(value = "创建时间", position = 8)
+    @TableField(fill = FieldFill.INSERT)
+    private Date createTime;
+
+    /** 创建人 */
+    @ApiModelProperty(value = "创建人", position = 9)
+    @TableField(fill = FieldFill.INSERT)
+    private String createUser;
+
+    /** 修改时间 */
+    @ApiModelProperty(value = "修改时间", position = 10)
+    @TableField(fill = FieldFill.UPDATE)
+    private Date updateTime;
+
+    /** 修改人 */
+    @ApiModelProperty(value = "修改人", position = 11)
+    @TableField(fill = FieldFill.UPDATE)
+    private String updateUser;
+
+    /** 查询对这个评论点没点过赞 */
+    private Integer giveNumSelf;
+
+    private Integer childSize;
+
+    /** 孩子评论 */
+    private List<QuestionAnswerVo> child;
+
+}

+ 12 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-api/src/main/java/vip/xiaonuo/exam/api/CourseChapterPaperApi.java

@@ -0,0 +1,12 @@
+package vip.xiaonuo.exam.api;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 章节试卷(作业)接口
+ */
+public interface CourseChapterPaperApi {
+    // 查询章节试卷(作业) 按章节ID chapterId 查询,按用户ID userId 查询个人记录
+    List<Map<String,Object>> queryListByChapterId(String chapterId, String userId, String type);
+}

+ 6 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/pom.xml

@@ -17,6 +17,11 @@
     <description>考试系统插件func实现</description>
 
     <dependencies>
+        <!-- 每个插件都要引入自己的对外接口 -->
+        <dependency>
+            <groupId>vip.xiaonuo</groupId>
+            <artifactId>snowy-plugin-exam-api</artifactId>
+        </dependency>
         <dependency>
             <groupId>vip.xiaonuo</groupId>
             <artifactId>snowy-common</artifactId>
@@ -110,4 +115,4 @@
             <optional>true</optional>
         </dependency>
     </dependencies>
-</project>
+</project>

+ 13 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/admin/QuestionController.java

@@ -39,7 +39,19 @@ public class QuestionController extends BaseApiController {
 
     @RequestMapping(value = "/page", method = RequestMethod.POST)
     public CommonResult<Page<Question>> pageList(@RequestBody QuestionPageRequestVM model) {
-        return CommonResult.data(questionService.page(model));
+        Page<Question> pageInfo = questionService.page(model);
+        pageInfo.getRecords().forEach(question -> {
+            question.setCreateTimeStr(DateTimeUtil.dateFormat(question.getCreateTime()));
+            question.setScoreStr(ExamUtil.scoreToVM(question.getScore()));
+            TextContent textContent = textContentService.selectById(question.getInfoTextContentId());
+            String clearHtml = "";
+            if(textContent != null && textContent.getContent() != null && !textContent.getContent().isEmpty()){
+                QuestionObject questionObject = JsonUtil.toJsonObject(textContent.getContent(), QuestionObject.class);
+                clearHtml = HtmlUtil.clear(questionObject.getTitleContent());
+            }
+            question.setShortTitle(clearHtml);
+        });
+        return CommonResult.data(pageInfo);
     }
 
     @RequestMapping(value = "/edit", method = RequestMethod.POST)

+ 5 - 4
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/EducationController.java

@@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RequestMethod;
 import org.springframework.web.bind.annotation.RestController;
 import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
 import vip.xiaonuo.exam.domain.Subject;
@@ -29,7 +30,7 @@ public class EducationController extends BaseApiController {
     }
 
     @RequestMapping(value = "/subject/list", method = RequestMethod.POST)
-    public RestResponse<List<SubjectVM>> list() {
+    public CommonResult<List<SubjectVM>> list() {
         SaBaseLoginUser user = getCurrentUser();
         List<Subject> subjects = subjectService.getSubjectByLevel(user.getSortCode());
         List<SubjectVM> subjectVMS = subjects.stream().map(d -> {
@@ -37,14 +38,14 @@ public class EducationController extends BaseApiController {
             subjectVM.setId(String.valueOf(d.getId()));
             return subjectVM;
         }).collect(Collectors.toList());
-        return RestResponse.ok(subjectVMS);
+        return CommonResult.data(subjectVMS);
     }
 
     @RequestMapping(value = "/subject/select/{id}", method = RequestMethod.POST)
-    public RestResponse<SubjectEditRequestVM> select(@PathVariable Integer id) {
+    public CommonResult<SubjectEditRequestVM> select(@PathVariable Integer id) {
         Subject subject = subjectService.selectById(id);
         SubjectEditRequestVM vm = modelMapper.map(subject, SubjectEditRequestVM.class);
-        return RestResponse.ok(vm);
+        return CommonResult.data(vm);
     }
 
 }

+ 20 - 20
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/ExamPaperAnswerController.java

@@ -1,6 +1,8 @@
 package vip.xiaonuo.exam.controller.student;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
 
@@ -46,30 +48,28 @@ public class ExamPaperAnswerController extends BaseApiController {
 
 
     @RequestMapping(value = "/pageList", method = RequestMethod.POST)
-    public RestResponse<PageInfo<ExamPaperAnswerPageResponseVM>> pageList(@RequestBody @Valid ExamPaperAnswerPageVM model) {
+    public CommonResult<Page<ExamPaperAnswer>> pageList(@RequestBody @Valid ExamPaperAnswerPageVM model) {
         model.setCreateUser(getCurrentUser().getId());
-        PageInfo<ExamPaperAnswer> pageInfo = examPaperAnswerService.studentPage(model);
-        PageInfo<ExamPaperAnswerPageResponseVM> page = PageInfoHelper.copyMap(pageInfo, e -> {
-            ExamPaperAnswerPageResponseVM vm = modelMapper.map(e, ExamPaperAnswerPageResponseVM.class);
+        Page<ExamPaperAnswer> pageInfo = examPaperAnswerService.studentPage(model);
+        pageInfo.getRecords().forEach(vm -> {
             Subject subject = subjectService.selectById(vm.getSubjectId());
-            vm.setDoTime(ExamUtil.secondToVM(e.getDoTime()));
-            vm.setSystemScore(ExamUtil.scoreToVM(e.getSystemScore()));
-            vm.setUserScore(ExamUtil.scoreToVM(e.getUserScore()));
-            vm.setPaperScore(ExamUtil.scoreToVM(e.getPaperScore()));
+            vm.setDoTimeStr(ExamUtil.secondToVM(vm.getDoTime()));
+            vm.setSystemScoreStr(ExamUtil.scoreToVM(vm.getSystemScore()));
+            vm.setUserScoreStr(ExamUtil.scoreToVM(vm.getUserScore()));
+            vm.setPaperScoreStr(ExamUtil.scoreToVM(vm.getPaperScore()));
             vm.setSubjectName(subject.getName());
-            vm.setCreateTime(DateTimeUtil.dateFormat(e.getCreateTime()));
-            return vm;
+            vm.setCreateTimeStr(DateTimeUtil.dateFormat(vm.getCreateTime()));
         });
-        return RestResponse.ok(page);
+        return CommonResult.data(pageInfo);
     }
 
 
     @RequestMapping(value = "/answerSubmit", method = RequestMethod.POST)
-    public RestResponse answerSubmit(@RequestBody @Valid ExamPaperSubmitVM examPaperSubmitVM) {
+    public CommonResult<String> answerSubmit(@RequestBody @Valid ExamPaperSubmitVM examPaperSubmitVM) {
         SaBaseLoginUser user = getCurrentUser();
         ExamPaperAnswerInfo examPaperAnswerInfo = examPaperAnswerService.calculateExamPaperAnswer(examPaperSubmitVM, user);
         if (null == examPaperAnswerInfo) {
-            return RestResponse.fail(2, "试卷不能重复做");
+            return CommonResult.error( "试卷不能重复做");
         }
         ExamPaperAnswer examPaperAnswer = examPaperAnswerInfo.getExamPaperAnswer();
         Integer userScore = examPaperAnswer.getUserScore();
@@ -81,21 +81,21 @@ public class ExamPaperAnswerController extends BaseApiController {
         userEventLog.setContent(content);
         eventPublisher.publishEvent(new CalculateExamPaperAnswerCompleteEvent(examPaperAnswerInfo));
         eventPublisher.publishEvent(new UserEvent(userEventLog));
-        return RestResponse.ok(scoreVm);
+        return CommonResult.ok(scoreVm);
     }
 
 
     @RequestMapping(value = "/edit", method = RequestMethod.POST)
-    public RestResponse edit(@RequestBody @Valid ExamPaperSubmitVM examPaperSubmitVM) {
+    public CommonResult<String> edit(@RequestBody @Valid ExamPaperSubmitVM examPaperSubmitVM) {
         boolean notJudge = examPaperSubmitVM.getAnswerItems().stream().anyMatch(i -> i.getDoRight() == null && i.getScore() == null);
         if (notJudge) {
-            return RestResponse.fail(2, "有未批改题目");
+            return CommonResult.error("有未批改题目");
         }
 
         ExamPaperAnswer examPaperAnswer = examPaperAnswerService.selectById(examPaperSubmitVM.getId());
         ExamPaperAnswerStatusEnum examPaperAnswerStatusEnum = ExamPaperAnswerStatusEnum.fromCode(examPaperAnswer.getStatus());
         if (examPaperAnswerStatusEnum == ExamPaperAnswerStatusEnum.Complete) {
-            return RestResponse.fail(3, "试卷已完成");
+            return CommonResult.error("试卷已完成");
         }
         String score = examPaperAnswerService.judge(examPaperSubmitVM);
         SaBaseLoginUser user = getCurrentUser();
@@ -103,18 +103,18 @@ public class ExamPaperAnswerController extends BaseApiController {
         String content = user.getName() + " 批改试卷:" + examPaperAnswer.getPaperName() + " 得分:" + score;
         userEventLog.setContent(content);
         eventPublisher.publishEvent(new UserEvent(userEventLog));
-        return RestResponse.ok(score);
+        return CommonResult.ok(score);
     }
 
     @RequestMapping(value = "/read/{id}", method = RequestMethod.POST)
-    public RestResponse<ExamPaperReadVM> read(@PathVariable Integer id) {
+    public CommonResult<ExamPaperReadVM> read(@PathVariable Integer id) {
         ExamPaperAnswer examPaperAnswer = examPaperAnswerService.selectById(id);
         ExamPaperReadVM vm = new ExamPaperReadVM();
         ExamPaperEditRequestVM paper = examPaperService.examPaperToVM(examPaperAnswer.getExamPaperId());
         ExamPaperSubmitVM answer = examPaperAnswerService.examPaperAnswerToVM(examPaperAnswer.getId());
         vm.setPaper(paper);
         vm.setAnswer(answer);
-        return RestResponse.ok(vm);
+        return CommonResult.data(vm);
     }
 
 

+ 7 - 11
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/ExamPaperController.java

@@ -1,5 +1,7 @@
 package vip.xiaonuo.exam.controller.student;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
 import vip.xiaonuo.exam.domain.ExamPaper;
@@ -10,7 +12,7 @@ import vip.xiaonuo.exam.utility.PageInfoHelper;
 import vip.xiaonuo.exam.viewmodel.admin.exam.ExamPaperEditRequestVM;
 import vip.xiaonuo.exam.viewmodel.student.exam.ExamPaperPageResponseVM;
 import vip.xiaonuo.exam.viewmodel.student.exam.ExamPaperPageVM;
-import com.github.pagehelper.PageInfo;
+
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.context.ApplicationEventPublisher;
 import org.springframework.web.bind.annotation.*;
@@ -34,20 +36,14 @@ public class ExamPaperController extends BaseApiController {
 
 
     @RequestMapping(value = "/select/{id}", method = RequestMethod.POST)
-    public RestResponse<ExamPaperEditRequestVM> select(@PathVariable Integer id) {
+    public CommonResult<ExamPaperEditRequestVM> select(@PathVariable Integer id) {
         ExamPaperEditRequestVM vm = examPaperService.examPaperToVM(id);
-        return RestResponse.ok(vm);
+        return CommonResult.data(vm);
     }
 
 
     @RequestMapping(value = "/pageList", method = RequestMethod.POST)
-    public RestResponse<PageInfo<ExamPaperPageResponseVM>> pageList(@RequestBody @Valid ExamPaperPageVM model) {
-        PageInfo<ExamPaper> pageInfo = examPaperService.studentPage(model);
-        PageInfo<ExamPaperPageResponseVM> page = PageInfoHelper.copyMap(pageInfo, e -> {
-            ExamPaperPageResponseVM vm = modelMapper.map(e, ExamPaperPageResponseVM.class);
-            vm.setCreateTime(DateTimeUtil.dateFormat(e.getCreateTime()));
-            return vm;
-        });
-        return RestResponse.ok(page);
+    public CommonResult<Page<ExamPaper>> pageList(@RequestBody @Valid ExamPaperPageVM model) {
+        return CommonResult.data(examPaperService.studentPage(model));
     }
 }

+ 18 - 16
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/controller/student/QuestionAnswerController.java

@@ -1,5 +1,7 @@
 package vip.xiaonuo.exam.controller.student;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import vip.xiaonuo.common.pojo.CommonResult;
 import vip.xiaonuo.exam.base.BaseApiController;
 import vip.xiaonuo.exam.base.RestResponse;
 import vip.xiaonuo.exam.domain.ExamPaperQuestionCustomerAnswer;
@@ -10,10 +12,7 @@ import vip.xiaonuo.exam.service.ExamPaperQuestionCustomerAnswerService;
 import vip.xiaonuo.exam.service.QuestionService;
 import vip.xiaonuo.exam.service.SubjectService;
 import vip.xiaonuo.exam.service.TextContentService;
-import vip.xiaonuo.exam.utility.DateTimeUtil;
-import vip.xiaonuo.exam.utility.HtmlUtil;
-import vip.xiaonuo.exam.utility.JsonUtil;
-import vip.xiaonuo.exam.utility.PageInfoHelper;
+import vip.xiaonuo.exam.utility.*;
 import vip.xiaonuo.exam.viewmodel.admin.question.QuestionEditRequestVM;
 import vip.xiaonuo.exam.viewmodel.student.exam.ExamPaperSubmitItemVM;
 import vip.xiaonuo.exam.viewmodel.student.question.answer.QuestionAnswerVM;
@@ -41,33 +40,36 @@ public class QuestionAnswerController extends BaseApiController {
     }
 
     @RequestMapping(value = "/page", method = RequestMethod.POST)
-    public RestResponse<PageInfo<QuestionPageStudentResponseVM>> pageList(@RequestBody QuestionPageStudentRequestVM model) {
+    public CommonResult<Page<ExamPaperQuestionCustomerAnswer>> pageList(@RequestBody QuestionPageStudentRequestVM model) {
         model.setCreateUser(getCurrentUser().getId());
-        PageInfo<ExamPaperQuestionCustomerAnswer> pageInfo = examPaperQuestionCustomerAnswerService.studentPage(model);
-        PageInfo<QuestionPageStudentResponseVM> page = PageInfoHelper.copyMap(pageInfo, q -> {
-            Subject subject = subjectService.selectById(q.getSubjectId());
-            QuestionPageStudentResponseVM vm = modelMapper.map(q, QuestionPageStudentResponseVM.class);
-            vm.setCreateTime(DateTimeUtil.dateFormat(q.getCreateTime()));
-            TextContent textContent = textContentService.selectById(q.getQuestionTextContentId());
+        Page<ExamPaperQuestionCustomerAnswer> pageInfo = examPaperQuestionCustomerAnswerService.studentPage(model);
+
+        pageInfo.getRecords().forEach(vm -> {
+            Subject subject = subjectService.selectById(vm.getSubjectId());
+
+            vm.setCreateTimeStr(DateTimeUtil.dateFormat(vm.getCreateTime()));
+            TextContent textContent = textContentService.selectById(vm.getQuestionTextContentId());
+            String clearHtml = "";
             QuestionObject questionObject = JsonUtil.toJsonObject(textContent.getContent(), QuestionObject.class);
-            String clearHtml = HtmlUtil.clear(questionObject.getTitleContent());
+            if(questionObject != null && questionObject.getTitleContent() != null && !questionObject.getTitleContent().isEmpty()){
+                clearHtml = HtmlUtil.clear(questionObject.getTitleContent());
+            }
             vm.setShortTitle(clearHtml);
             vm.setSubjectName(subject.getName());
-            return vm;
         });
-        return RestResponse.ok(page);
+        return CommonResult.data(pageInfo);
     }
 
 
     @RequestMapping(value = "/select/{id}", method = RequestMethod.POST)
-    public RestResponse<QuestionAnswerVM> select(@PathVariable Integer id) {
+    public CommonResult<QuestionAnswerVM> select(@PathVariable Integer id) {
         QuestionAnswerVM vm = new QuestionAnswerVM();
         ExamPaperQuestionCustomerAnswer examPaperQuestionCustomerAnswer = examPaperQuestionCustomerAnswerService.selectById(id);
         ExamPaperSubmitItemVM questionAnswerVM = examPaperQuestionCustomerAnswerService.examPaperQuestionCustomerAnswerToVM(examPaperQuestionCustomerAnswer);
         QuestionEditRequestVM questionVM = questionService.getQuestionEditRequestVM(examPaperQuestionCustomerAnswer.getQuestionId());
         vm.setQuestionVM(questionVM);
         vm.setQuestionAnswerVM(questionAnswerVM);
-        return RestResponse.ok(vm);
+        return CommonResult.data(vm);
     }
 
 }

+ 10 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/CourseChapterPaper.java

@@ -10,6 +10,8 @@ package vip.xiaonuo.exam.domain;
 public class CourseChapterPaper {
     String chapterId;
     String paperId;
+    //chapterId的ID type 0 章节 1课时
+    String type;
 
     public String getChapterId() {
         return chapterId;
@@ -26,4 +28,12 @@ public class CourseChapterPaper {
     public void setPaperId(String paperId) {
         this.paperId = paperId;
     }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
 }

+ 1 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaper.java

@@ -20,7 +20,7 @@ public class ExamPaper implements Serializable {
     private Integer subjectId;
 
     /**
-     * 试卷类型( 1.固定试卷 2.调查问卷 4.时段试卷 6.任务试卷 )
+     * 试卷类型( 1.固定试卷 2.章节作业 3.章节测验 4.时段试卷 5.调查问卷 6.任务试卷 )
      */
     private Integer paperType;
 

+ 4 - 3
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaperAnswer.java

@@ -17,7 +17,7 @@ public class ExamPaperAnswer implements Serializable {
     private String paperName;
 
     /**
-     * 试卷类型( 1固定试卷 4.时段试卷 6.任务试卷)
+     * 试卷类型( 1.固定试卷 2.章节作业 3.章节测验 4.时段试卷 5.调查问卷 6.任务试卷 )
      */
     private Integer paperType;
 
@@ -62,6 +62,7 @@ public class ExamPaperAnswer implements Serializable {
      */
     private Integer doTime;
 
+    private String doTimeStr;
     /**
      * 试卷状态(1待判分 2完成)
      */
@@ -81,8 +82,6 @@ public class ExamPaperAnswer implements Serializable {
 
     private Integer taskExamId;
 
-    private String doTimeStr;
-
     public Integer getId() {
         return id;
     }
@@ -250,4 +249,6 @@ public class ExamPaperAnswer implements Serializable {
     public void setCreateTimeStr(String createTimeStr) {
         this.createTimeStr = createTimeStr;
     }
+
+
 }

+ 30 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/ExamPaperQuestionCustomerAnswer.java

@@ -71,8 +71,14 @@ public class ExamPaperQuestionCustomerAnswer implements Serializable {
 
     private Date createTime;
 
+    private String createTimeStr;
+
     private Integer itemOrder;
 
+    private String shortTitle;
+
+    private String subjectName;
+
     public Integer getId() {
         return id;
     }
@@ -192,4 +198,28 @@ public class ExamPaperQuestionCustomerAnswer implements Serializable {
     public void setItemOrder(Integer itemOrder) {
         this.itemOrder = itemOrder;
     }
+
+    public String getCreateTimeStr() {
+        return createTimeStr;
+    }
+
+    public void setCreateTimeStr(String createTimeStr) {
+        this.createTimeStr = createTimeStr;
+    }
+
+    public String getShortTitle() {
+        return shortTitle;
+    }
+
+    public void setShortTitle(String shortTitle) {
+        this.shortTitle = shortTitle;
+    }
+
+    public String getSubjectName() {
+        return subjectName;
+    }
+
+    public void setSubjectName(String subjectName) {
+        this.subjectName = subjectName;
+    }
 }

+ 29 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/Question.java

@@ -28,6 +28,8 @@ public class Question implements Serializable {
      */
     private Integer score;
 
+    private String scoreStr;
+
     /**
      * 级别
      */
@@ -63,8 +65,12 @@ public class Question implements Serializable {
      */
     private Date createTime;
 
+    private String createTimeStr;
+
     private Boolean deleted;
 
+    private String shortTitle;
+
     public Integer getId() {
         return id;
     }
@@ -161,6 +167,29 @@ public class Question implements Serializable {
         this.deleted = deleted;
     }
 
+    public String getShortTitle() {
+        return shortTitle;
+    }
+
+    public void setShortTitle(String shortTitle) {
+        this.shortTitle = shortTitle;
+    }
+
+    public String getCreateTimeStr() {
+        return createTimeStr;
+    }
+
+    public void setCreateTimeStr(String createTimeStr) {
+        this.createTimeStr = createTimeStr;
+    }
+
+    public String getScoreStr() {
+        return scoreStr;
+    }
+
+    public void setScoreStr(String scoreStr) {
+        this.scoreStr = scoreStr;
+    }
 
     public void setCorrectFromVM(String correct, List<String> correctArray) {
         int qType = this.getQuestionType();

+ 3 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/domain/enums/ExamPaperTypeEnum.java

@@ -6,8 +6,10 @@ import java.util.Map;
 public enum ExamPaperTypeEnum {
 
     Fixed(1, "固定试卷"),
-    Survey(2, "调查问卷"),
+    ChapterWork(2, "章节作业"),
+    ChapterTrain(3, "章节测验"),
     TimeLimit(4, "时段试卷"),
+    Survey(5, "调查问卷"),
     Task(6, "任务试卷");
 
     int code;

+ 1 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperAnswerMapper.java

@@ -14,7 +14,7 @@ import java.util.List;
 @Mapper
 public interface ExamPaperAnswerMapper extends BaseMapper<ExamPaperAnswer> {
 
-    List<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM requestVM);
+    Page<ExamPaperAnswer> studentPage(@Param("bo") ExamPaperAnswerPageVM requestVM , @Param("page") Page<ExamPaperAnswer> page);
 
     Integer selectAllCount();
 

+ 3 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperMapper.java

@@ -21,7 +21,7 @@ public interface ExamPaperMapper extends BaseMapper<ExamPaper> {
 
     Page<ExamPaper> taskExamPage(@Param("bo")ExamPaperPageRequestVM requestVM, @Param("page") Page<ExamPaper> page);
 
-    List<ExamPaper> studentPage(ExamPaperPageVM requestVM);
+    Page<ExamPaper> studentPage(@Param("bo")ExamPaperPageVM requestVM, @Param("page") Page<ExamPaper> page);
 
     List<PaperInfo> indexPaper(PaperFilter paperFilter);
 
@@ -32,4 +32,6 @@ public interface ExamPaperMapper extends BaseMapper<ExamPaper> {
     int updateTaskPaper(@Param("taskId") Integer taskId,@Param("paperIds") List<Integer> paperIds);
 
     int clearTaskPaper(@Param("paperIds") List<Integer> paperIds);
+
+    List<ExamPaper> selectByIds(@Param("ids") List<String> ids);
 }

+ 2 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/ExamPaperQuestionCustomerAnswerMapper.java

@@ -1,5 +1,6 @@
 package vip.xiaonuo.exam.mapper;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import vip.xiaonuo.exam.domain.ExamPaperQuestionCustomerAnswer;
 import vip.xiaonuo.exam.domain.other.ExamPaperAnswerUpdate;
 import vip.xiaonuo.exam.domain.other.KeyValue;
@@ -15,7 +16,7 @@ public interface ExamPaperQuestionCustomerAnswerMapper extends BaseMapper<ExamPa
 
     List<ExamPaperQuestionCustomerAnswer> selectListByPaperAnswerId(Integer id);
 
-    List<ExamPaperQuestionCustomerAnswer> studentPage(QuestionPageStudentRequestVM requestVM);
+    Page<ExamPaperQuestionCustomerAnswer> studentPage(@Param("bo") QuestionPageStudentRequestVM requestVM, @Param("page") Page<ExamPaperQuestionCustomerAnswer> page);
 
     int insertList(List<ExamPaperQuestionCustomerAnswer> list);
 

+ 10 - 3
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/CourseChapterPaperMapper.xml

@@ -4,9 +4,10 @@
     <resultMap id="BaseResultMap" type="vip.xiaonuo.exam.domain.CourseChapterPaper">
         <result column="CHAPTER_ID" jdbcType="VARCHAR" property="chapterId" />
         <result column="PAPER_ID" jdbcType="VARCHAR" property="paperId" />
+        <result column="TYPE" jdbcType="VARCHAR" property="type" />
     </resultMap>
     <sql id="Base_Column_List">
-        CHAPTER_ID, PAPER_ID
+        CHAPTER_ID, PAPER_ID, TYPE
     </sql>
     <select id="queryList" resultMap="BaseResultMap" parameterType="vip.xiaonuo.exam.domain.CourseChapterPaper">
         select
@@ -19,10 +20,13 @@
         <if test="paperId != null">
             and PAPER_ID = #{paperId,jdbcType=VARCHAR}
         </if>
+        <if test="type != null">
+            and TYPE = #{type,jdbcType=VARCHAR}
+        </if>
     </select>
     <insert id="add" parameterType="vip.xiaonuo.exam.domain.CourseChapterPaper">
-        insert into COURSE_CHAPTER_PAPER (CHAPTER_ID, PAPER_ID)
-        values (#{chapterId,jdbcType=VARCHAR}, #{paperId,jdbcType=VARCHAR})
+        insert into COURSE_CHAPTER_PAPER (CHAPTER_ID, PAPER_ID, TYPE)
+        values (#{chapterId,jdbcType=VARCHAR}, #{paperId,jdbcType=VARCHAR}, #{type,jdbcType=VARCHAR})
     </insert>
     <delete id="delete" parameterType="vip.xiaonuo.exam.domain.CourseChapterPaper">
         delete from COURSE_CHAPTER_PAPER
@@ -33,5 +37,8 @@
         <if test="paperId != null">
             and PAPER_ID = #{paperId,jdbcType=VARCHAR}
         </if>
+        <if test="type != null">
+            and TYPE = #{type,jdbcType=VARCHAR}
+        </if>
     </delete>
 </mapper>

+ 4 - 3
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperAnswerMapper.xml

@@ -220,11 +220,12 @@
     <include refid="Base_Column_List"/>
     FROM t_exam_paper_answer
     <where>
-        and create_user = #{createUser}
-     <if test="subjectId != null">
-         and subject_id = #{subjectId}
+        and create_user = #{bo.createUser}
+     <if test="bo.subjectId != null">
+         and subject_id = #{bo.subjectId}
      </if>
     </where>
+    ORDER BY create_time DESC
   </select>
 
 

+ 15 - 6
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperMapper.xml

@@ -271,13 +271,13 @@
     FROM t_exam_paper
     <where>
        and deleted=0
-      <if test="subjectId != null ">
-        and subject_id=#{subjectId}
+      <if test="bo.subjectId != null ">
+        and subject_id=#{bo.subjectId}
       </if>
-      <if test="levelId != null ">
-        and grade_level=#{levelId}
+      <if test="bo.levelId != null ">
+        and grade_level=#{bo.levelId}
       </if>
-       and paper_type=#{paperType}
+       and paper_type=#{bo.paperType}
     </where>
   </select>
 
@@ -312,7 +312,6 @@
 		GROUP BY create_time
 	</select>
 
-
   <update id="updateTaskPaper">
     update t_exam_paper set task_exam_id = #{taskId} where id in
     <foreach item="id" collection="paperIds" open="(" separator=","
@@ -330,4 +329,14 @@
     </foreach>
   </update>
 
+  <select id="selectByIds" resultType="vip.xiaonuo.exam.domain.ExamPaper">
+    SELECT
+    <include refid="Base_Column_List"/>
+    FROM t_exam_paper
+    WHERE id in
+    <foreach item="id" collection="paperIds" open="(" separator=","
+             close=")">
+      #{id}
+    </foreach>
+  </select>
 </mapper>

+ 2 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/mapper/mapping/ExamPaperQuestionCustomerAnswerMapper.xml

@@ -234,8 +234,9 @@
     FROM t_exam_paper_question_customer_answer
     <where>
       and do_right=FALSE
-      and create_user=#{createUser}
+      and create_user=#{bo.createUser}
     </where>
+    order by create_time desc
   </select>
 
 

+ 1 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperAnswerService.java

@@ -19,7 +19,7 @@ public interface ExamPaperAnswerService extends BaseService<ExamPaperAnswer> {
      * @param requestVM 过滤条件
      * @return PageInfo<ExamPaperAnswer>
      */
-    PageInfo<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM requestVM);
+    Page<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM requestVM);
 
     /**
      * 计算试卷提交结果(不入库)

+ 2 - 2
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperQuestionCustomerAnswerService.java

@@ -4,13 +4,13 @@ import vip.xiaonuo.exam.domain.ExamPaperQuestionCustomerAnswer;
 import vip.xiaonuo.exam.domain.other.ExamPaperAnswerUpdate;
 import vip.xiaonuo.exam.viewmodel.student.exam.ExamPaperSubmitItemVM;
 import vip.xiaonuo.exam.viewmodel.student.question.answer.QuestionPageStudentRequestVM;
-import com.github.pagehelper.PageInfo;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 
 import java.util.List;
 
 public interface ExamPaperQuestionCustomerAnswerService extends BaseService<ExamPaperQuestionCustomerAnswer> {
 
-    PageInfo<ExamPaperQuestionCustomerAnswer> studentPage(QuestionPageStudentRequestVM requestVM);
+    Page<ExamPaperQuestionCustomerAnswer> studentPage(QuestionPageStudentRequestVM requestVM);
 
     List<ExamPaperQuestionCustomerAnswer> selectListByPaperAnswerId(Integer id);
 

+ 1 - 1
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/ExamPaperService.java

@@ -19,7 +19,7 @@ public interface ExamPaperService extends BaseService<ExamPaper> {
 
     Page<ExamPaper> taskExamPage(ExamPaperPageRequestVM requestVM);
 
-    PageInfo<ExamPaper> studentPage(ExamPaperPageVM requestVM);
+    Page<ExamPaper> studentPage(ExamPaperPageVM requestVM);
 
     ExamPaper savePaperFromVM(ExamPaperEditRequestVM examPaperEditRequestVM, SaBaseLoginUser user);
 

+ 4 - 3
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperAnswerServiceImpl.java

@@ -58,9 +58,10 @@ public class ExamPaperAnswerServiceImpl extends BaseServiceImpl<ExamPaperAnswer>
     }
 
     @Override
-    public PageInfo<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM requestVM) {
-        return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() ->
-                examPaperAnswerMapper.studentPage(requestVM));
+    public Page<ExamPaperAnswer> studentPage(ExamPaperAnswerPageVM requestVM) {
+        Page<ExamPaperAnswer> page = new Page<ExamPaperAnswer>(requestVM.getCurrent(), requestVM.getSize());
+        page.setSearchCount(true); // 设置计算总记录数
+        return examPaperAnswerMapper.studentPage(requestVM,page);
     }
 
 

+ 6 - 4
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperQuestionCustomerAnswerServiceImpl.java

@@ -1,5 +1,7 @@
 package vip.xiaonuo.exam.service.impl;
 
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import vip.xiaonuo.exam.domain.ExamPaperAnswer;
 import vip.xiaonuo.exam.domain.ExamPaperQuestionCustomerAnswer;
 import vip.xiaonuo.exam.domain.other.ExamPaperAnswerUpdate;
 import vip.xiaonuo.exam.domain.other.KeyValue;
@@ -37,10 +39,10 @@ public class ExamPaperQuestionCustomerAnswerServiceImpl extends BaseServiceImpl<
 
 
     @Override
-    public PageInfo<ExamPaperQuestionCustomerAnswer> studentPage(QuestionPageStudentRequestVM requestVM) {
-        return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() ->
-                examPaperQuestionCustomerAnswerMapper.studentPage(requestVM)
-        );
+    public Page<ExamPaperQuestionCustomerAnswer> studentPage(QuestionPageStudentRequestVM requestVM) {
+        Page<ExamPaperQuestionCustomerAnswer> page = new Page<ExamPaperQuestionCustomerAnswer>(requestVM.getCurrent(), requestVM.getSize());
+        page.setSearchCount(true); // 设置计算总记录数
+        return examPaperQuestionCustomerAnswerMapper.studentPage(requestVM,page);
     }
 
     @Override

+ 52 - 12
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/service/impl/ExamPaperServiceImpl.java

@@ -1,13 +1,19 @@
 package vip.xiaonuo.exam.service.impl;
 
 
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.map.MapUtil;
+import com.baomidou.mybatisplus.core.toolkit.StringUtils;
 import com.github.pagehelper.PageHelper;
 import com.github.pagehelper.PageInfo;
+import lombok.extern.slf4j.Slf4j;
 import org.modelmapper.ModelMapper;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 import vip.xiaonuo.auth.core.pojo.SaBaseLoginUser;
+import vip.xiaonuo.exam.api.CourseChapterPaperApi;
+import vip.xiaonuo.exam.domain.CourseChapterPaper;
 import vip.xiaonuo.exam.domain.ExamPaper;
 import vip.xiaonuo.exam.domain.Question;
 import vip.xiaonuo.exam.domain.TextContent;
@@ -17,10 +23,7 @@ import vip.xiaonuo.exam.domain.exam.ExamPaperTitleItemObject;
 import vip.xiaonuo.exam.domain.other.KeyValue;
 import vip.xiaonuo.exam.mapper.ExamPaperMapper;
 import vip.xiaonuo.exam.mapper.QuestionMapper;
-import vip.xiaonuo.exam.service.ExamPaperService;
-import vip.xiaonuo.exam.service.QuestionService;
-import vip.xiaonuo.exam.service.SubjectService;
-import vip.xiaonuo.exam.service.TextContentService;
+import vip.xiaonuo.exam.service.*;
 import vip.xiaonuo.exam.service.enums.ActionEnum;
 import vip.xiaonuo.exam.utility.DateTimeUtil;
 import vip.xiaonuo.exam.utility.ExamUtil;
@@ -35,14 +38,14 @@ import vip.xiaonuo.exam.viewmodel.student.dashboard.PaperFilter;
 import vip.xiaonuo.exam.viewmodel.student.dashboard.PaperInfo;
 import vip.xiaonuo.exam.viewmodel.student.exam.ExamPaperPageVM;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.List;
+
+import javax.annotation.Resource;
+import java.util.*;
 import java.util.concurrent.atomic.AtomicInteger;
 import java.util.stream.Collectors;
-
+@Slf4j
 @Service
-public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements ExamPaperService {
+public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements ExamPaperService, CourseChapterPaperApi {
 
     protected final static ModelMapper modelMapper = ModelMapperSingle.Instance();
     private final ExamPaperMapper examPaperMapper;
@@ -51,6 +54,9 @@ public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements
     private final QuestionService questionService;
     private final SubjectService subjectService;
 
+    @Resource
+    private CourseChapterPaperService courseChapterPaperService;
+
     @Autowired
     public ExamPaperServiceImpl(ExamPaperMapper examPaperMapper, QuestionMapper questionMapper, TextContentService textContentService, QuestionService questionService, SubjectService subjectService) {
         super(examPaperMapper);
@@ -77,9 +83,10 @@ public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements
     }
 
     @Override
-    public PageInfo<ExamPaper> studentPage(ExamPaperPageVM requestVM) {
-        return PageHelper.startPage(requestVM.getPageIndex(), requestVM.getPageSize(), "id desc").doSelectPageInfo(() ->
-                examPaperMapper.studentPage(requestVM));
+    public Page<ExamPaper> studentPage(ExamPaperPageVM requestVM) {
+        Page<ExamPaper> page = new Page<ExamPaper>(requestVM.getCurrent(), requestVM.getSize());
+        page.setSearchCount(true); // 设置计算总记录数
+        return examPaperMapper.studentPage(requestVM,page);
     }
 
 
@@ -203,4 +210,37 @@ public class ExamPaperServiceImpl extends BaseServiceImpl<ExamPaper> implements
             return titleItem;
         }).collect(Collectors.toList());
     }
+
+    /**
+     * 查询章节试卷(作业) 按章节ID chapterId 查询,按用户ID userId 查询个人记录
+     * @param chapterId 章节ID
+     * @param userId 用户ID
+     * @return List<Map<String, Object>>
+     */
+    @Override
+    public List<Map<String, Object>> queryListByChapterId(String chapterId, String userId, String type) {
+        List<Map<String, Object>> resultList = new ArrayList<>();
+        try {
+            if(chapterId == null || StringUtils.isEmpty(userId)){
+                return resultList;
+            }
+            CourseChapterPaper param = new CourseChapterPaper();
+            param.setChapterId(chapterId);
+            param.setType(type);
+            // 全部的试卷(作业)关联关系
+            List<CourseChapterPaper> courseChapterList = courseChapterPaperService.queryList(param);
+            if(courseChapterList.isEmpty()){
+                return resultList;
+            }
+            List<String> paperIds = courseChapterList.stream().map(CourseChapterPaper::getPaperId).collect(Collectors.toList());
+            List<ExamPaper> paperList = examPaperMapper.selectByIds(paperIds);
+            resultList = paperList.stream()
+                    .map(BeanUtil::beanToMap)
+                    .collect(Collectors.toList());
+        } catch (Exception e) {
+            log.error("查询查询章节试卷(作业)异常:{}", e);
+            e.printStackTrace();
+        }
+        return resultList;
+    }
 }

+ 19 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/exam/ExamPaperPageVM.java

@@ -10,6 +10,9 @@ public class ExamPaperPageVM extends BasePage {
     private Integer subjectId;
     private Integer levelId;
 
+    private Integer current;
+    private Integer size;
+
     public Integer getPaperType() {
         return paperType;
     }
@@ -33,4 +36,20 @@ public class ExamPaperPageVM extends BasePage {
     public void setLevelId(Integer levelId) {
         this.levelId = levelId;
     }
+
+    public Integer getCurrent() {
+        return current;
+    }
+
+    public void setCurrent(Integer current) {
+        this.current = current;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
 }

+ 20 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/exampaper/ExamPaperAnswerPageVM.java

@@ -8,6 +8,10 @@ public class ExamPaperAnswerPageVM extends BasePage {
 
     private String createUser;
 
+    private Integer current;
+
+    private Integer size;
+
     public Integer getSubjectId() {
         return subjectId;
     }
@@ -23,4 +27,20 @@ public class ExamPaperAnswerPageVM extends BasePage {
     public void setCreateUser(String createUser) {
         this.createUser = createUser;
     }
+
+    public Integer getCurrent() {
+        return current;
+    }
+
+    public void setCurrent(Integer current) {
+        this.current = current;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
 }

+ 19 - 0
snowy-plugin/snowy-plugin-exam/snowy-plugin-exam-func/src/main/java/vip/xiaonuo/exam/viewmodel/student/question/answer/QuestionPageStudentRequestVM.java

@@ -5,6 +5,9 @@ import vip.xiaonuo.exam.base.BasePage;
 public class QuestionPageStudentRequestVM extends BasePage {
     private String createUser;
 
+    private Integer current;
+    private Integer size;
+
     public String getCreateUser() {
         return createUser;
     }
@@ -12,4 +15,20 @@ public class QuestionPageStudentRequestVM extends BasePage {
     public void setCreateUser(String createUser) {
         this.createUser = createUser;
     }
+
+    public Integer getCurrent() {
+        return current;
+    }
+
+    public void setCurrent(Integer current) {
+        this.current = current;
+    }
+
+    public Integer getSize() {
+        return size;
+    }
+
+    public void setSize(Integer size) {
+        this.size = size;
+    }
 }

+ 2 - 6
snowy-server/snowy-gateway-app/src/main/java/vip/xiaonuo/gateway/config/GatewayConfigure.java

@@ -144,13 +144,9 @@ public class GatewayConfigure {
             /* 资源中心 */
             "/api/webapp/disk/resourcecentre/page",
             "/api/webapp/disk/resourcecentre/detail",
-            "/api/webapp/disk/courseauditrecord/addViewCount",
+            "/api/webapp/disk/courseauditrecord/addViewCount"
+
 
-            "/api/webapp/disk/minio/upload",
-            "/api/webapp/disk/minio/checkExits",
-            "/api/webapp/disk/minio/merge",
-            "/api/webapp/disk/minio/delete",
-            "/api/webapp/disk/minio/checkMd5List"
     };
 
     /**