Browse Source

课程目录的保存和查询

yangfeng 1 năm trước cách đây
mục cha
commit
3c3c3ce335

+ 7 - 0
core/pom.xml

@@ -204,6 +204,13 @@
       <artifactId>bcpkix-jdk15on</artifactId>
       <version>1.68</version>
     </dependency>
+
+    <!--计算视频时长-->
+    <dependency>
+      <groupId>ws.schild</groupId>
+      <artifactId>jave-all-deps</artifactId>
+      <version>3.1.1</version>
+    </dependency>
   </dependencies>
 
 </project>

+ 97 - 52
core/src/main/java/org/jeecg/common/util/CommonUtils.java

@@ -17,6 +17,8 @@ import org.jeecgframework.poi.util.PoiPublicUtil;
 import org.springframework.jdbc.datasource.DriverManagerDataSource;
 import org.springframework.util.FileCopyUtils;
 import org.springframework.web.multipart.MultipartFile;
+import ws.schild.jave.MultimediaObject;
+import ws.schild.jave.info.MultimediaInfo;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.sql.DataSource;
@@ -24,6 +26,9 @@ import java.io.ByteArrayInputStream;
 import java.io.File;
 import java.io.IOException;
 import java.io.InputStream;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.net.URL;
 import java.sql.Connection;
 import java.sql.DatabaseMetaData;
 import java.sql.SQLException;
@@ -50,13 +55,13 @@ public class CommonUtils {
      */
     private static String FILE_NAME_REGEX = "[^A-Za-z\\.\\(\\)\\-()\\_0-9\\u4e00-\\u9fa5]";
 
-    public static String uploadOnlineImage(byte[] data,String basePath,String bizPath,String uploadType){
+    public static String uploadOnlineImage(byte[] data, String basePath, String bizPath, String uploadType) {
         String dbPath = null;
         String fileName = "image" + Math.round(Math.random() * 100000000000L);
         fileName += "." + PoiPublicUtil.getFileExtendName(data);
         try {
-            if(CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)){
-                File file = new File(basePath + File.separator + bizPath + File.separator );
+            if (CommonConstant.UPLOAD_TYPE_LOCAL.equals(uploadType)) {
+                File file = new File(basePath + File.separator + bizPath + File.separator);
                 if (!file.exists()) {
                     file.mkdirs();// 创建文件根目录
                 }
@@ -64,13 +69,13 @@ public class CommonUtils {
                 File savefile = new File(savePath);
                 FileCopyUtils.copy(data, savefile);
                 dbPath = bizPath + File.separator + fileName;
-            }else {
+            } else {
                 InputStream in = new ByteArrayInputStream(data);
-                String relativePath = bizPath+"/"+fileName;
-                if(CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)){
-                    dbPath = MinioUtil.upload(in,relativePath);
-                }else if(CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)){
-                    dbPath = OssBootUtil.upload(in,relativePath);
+                String relativePath = bizPath + "/" + fileName;
+                if (CommonConstant.UPLOAD_TYPE_MINIO.equals(uploadType)) {
+                    dbPath = MinioUtil.upload(in, relativePath);
+                } else if (CommonConstant.UPLOAD_TYPE_OSS.equals(uploadType)) {
+                    dbPath = OssBootUtil.upload(in, relativePath);
                 }
             }
         } catch (Exception e) {
@@ -81,10 +86,11 @@ public class CommonUtils {
 
     /**
      * 判断文件名是否带盘符,重新处理
+     *
      * @param fileName
      * @return
      */
-    public static String getFileName(String fileName){
+    public static String getFileName(String fileName) {
         //判断是否带有盘符信息
         // Check for Unix-style path
         int unixSep = fileName.lastIndexOf('/');
@@ -92,15 +98,15 @@ public class CommonUtils {
         int winSep = fileName.lastIndexOf('\\');
         // Cut off at latest possible point
         int pos = (winSep > unixSep ? winSep : unixSep);
-        if (pos != -1)  {
+        if (pos != -1) {
             // Any sort of path separator found...
             fileName = fileName.substring(pos + 1);
         }
         //替换上传文件名字的特殊字符
-        fileName = fileName.replace("=","").replace(",","").replace("&","")
+        fileName = fileName.replace("=", "").replace(",", "").replace("&", "")
                 .replace("#", "").replace("“", "").replace("”", "");
         //替换上传文件名字中的空格
-        fileName=fileName.replaceAll("\\s","");
+        fileName = fileName.replaceAll("\\s", "");
         //update-beign-author:taoyan date:20220302 for: /issues/3381 online 在线表单 使用文件组件时,上传文件名中含%,下载异常
         fileName = fileName.replaceAll(FILE_NAME_REGEX, "");
         //update-end-author:taoyan date:20220302 for: /issues/3381 online 在线表单 使用文件组件时,上传文件名中含%,下载异常
@@ -109,13 +115,14 @@ public class CommonUtils {
 
     /**
      * java 判断字符串里是否包含中文字符
+     *
      * @param str
      * @return
      */
     public static boolean ifContainChinese(String str) {
-        if(str.getBytes().length == str.length()){
+        if (str.getBytes().length == str.length()) {
             return false;
-        }else{
+        } else {
             Matcher m = ZHONGWEN_PATTERN.matcher(str);
             if (m.find()) {
                 return true;
@@ -126,6 +133,7 @@ public class CommonUtils {
 
     /**
      * 统一全局上传
+     *
      * @Return: java.lang.String
      */
     public static String upload(MultipartFile file, String bizPath, String uploadType) {
@@ -141,19 +149,21 @@ public class CommonUtils {
         }
         return url;
     }
+
     /**
      * 本地文件上传
-     * @param mf 文件
-     * @param bizPath  自定义路径
+     *
+     * @param mf      文件
+     * @param bizPath 自定义路径
      * @return
      */
-    public static String uploadLocal(MultipartFile mf, String bizPath, String uploadpath){
+    public static String uploadLocal(MultipartFile mf, String bizPath, String uploadpath) {
         try {
             //update-begin-author:liusq date:20210809 for: 过滤上传文件类型
             FileTypeFilter.fileTypeFilter(mf);
             //update-end-author:liusq date:20210809 for: 过滤上传文件类型
             String fileName = null;
-            File file = new File(uploadpath + File.separator + bizPath + File.separator );
+            File file = new File(uploadpath + File.separator + bizPath + File.separator);
             if (!file.exists()) {
                 // 创建文件根目录
                 file.mkdirs();
@@ -161,18 +171,18 @@ public class CommonUtils {
             // 获取文件名
             String orgName = mf.getOriginalFilename();
             orgName = CommonUtils.getFileName(orgName);
-            if(orgName.indexOf(SymbolConstant.SPOT)!=-1){
+            if (orgName.indexOf(SymbolConstant.SPOT) != -1) {
                 fileName = orgName.substring(0, orgName.lastIndexOf(".")) + "_" + System.currentTimeMillis() + orgName.substring(orgName.lastIndexOf("."));
-            }else{
-                fileName = orgName+ "_" + System.currentTimeMillis();
+            } else {
+                fileName = orgName + "_" + System.currentTimeMillis();
             }
             String savePath = file.getPath() + File.separator + fileName;
             File savefile = new File(savePath);
             FileCopyUtils.copy(mf.getBytes(), savefile);
             String dbpath = null;
-            if(oConvertUtils.isNotEmpty(bizPath)){
+            if (oConvertUtils.isNotEmpty(bizPath)) {
                 dbpath = bizPath + File.separator + fileName;
-            }else{
+            } else {
                 dbpath = fileName;
             }
             if (dbpath.contains(SymbolConstant.DOUBLE_BACKSLASH)) {
@@ -181,7 +191,7 @@ public class CommonUtils {
             return dbpath;
         } catch (IOException e) {
             log.error(e.getMessage(), e);
-        }catch (Exception e) {
+        } catch (Exception e) {
             log.error(e.getMessage(), e);
         }
         return "";
@@ -189,6 +199,7 @@ public class CommonUtils {
 
     /**
      * 统一全局上传 带桶
+     *
      * @Return: java.lang.String
      */
     public static String upload(MultipartFile file, String bizPath, String uploadType, String customBucket) {
@@ -200,22 +211,25 @@ public class CommonUtils {
                 url = OssBootUtil.upload(file, bizPath, customBucket);
             }
         } catch (Exception e) {
-            log.error(e.getMessage(),e);
+            log.error(e.getMessage(), e);
         }
         return url;
     }
 
-    /** 当前系统数据库类型 */
+    /**
+     * 当前系统数据库类型
+     */
     private static String DB_TYPE = "";
     private static DbType dbTypeEnum = null;
 
     /**
      * 全局获取平台数据库类型(作废了)
+     *
      * @return
      */
     @Deprecated
     public static String getDatabaseType() {
-        if(oConvertUtils.isNotEmpty(DB_TYPE)){
+        if (oConvertUtils.isNotEmpty(DB_TYPE)) {
             return DB_TYPE;
         }
         DataSource dataSource = SpringContextUtils.getApplicationContext().getBean(DataSource.class);
@@ -223,13 +237,14 @@ public class CommonUtils {
             return getDatabaseTypeByDataSource(dataSource);
         } catch (SQLException e) {
             //e.printStackTrace();
-            log.warn(e.getMessage(),e);
+            log.warn(e.getMessage(), e);
             return "";
         }
     }
 
     /**
      * 全局获取平台数据库类型(对应mybaisPlus枚举)
+     *
      * @return
      */
     public static DbType getDatabaseTypeEnum() {
@@ -248,18 +263,20 @@ public class CommonUtils {
 
     /**
      * 根据数据源key获取DataSourceProperty
+     *
      * @param sourceKey
      * @return
      */
-    public static DataSourceProperty getDataSourceProperty(String sourceKey){
+    public static DataSourceProperty getDataSourceProperty(String sourceKey) {
         DynamicDataSourceProperties prop = SpringContextUtils.getApplicationContext().getBean(DynamicDataSourceProperties.class);
         Map<String, DataSourceProperty> map = prop.getDatasource();
-        DataSourceProperty db = (DataSourceProperty)map.get(sourceKey);
+        DataSourceProperty db = (DataSourceProperty) map.get(sourceKey);
         return db;
     }
 
     /**
      * 根据sourceKey 获取数据源连接
+     *
      * @param sourceKey
      * @return
      * @throws SQLException
@@ -270,8 +287,8 @@ public class CommonUtils {
         }
         DynamicDataSourceProperties prop = SpringContextUtils.getApplicationContext().getBean(DynamicDataSourceProperties.class);
         Map<String, DataSourceProperty> map = prop.getDatasource();
-        DataSourceProperty db = (DataSourceProperty)map.get(sourceKey);
-        if(db==null){
+        DataSourceProperty db = (DataSourceProperty) map.get(sourceKey);
+        if (db == null) {
             return null;
         }
         DriverManagerDataSource ds = new DriverManagerDataSource();
@@ -284,40 +301,42 @@ public class CommonUtils {
 
     /**
      * 获取数据库类型
+     *
      * @param dataSource
      * @return
      * @throws SQLException
      */
-    private static String getDatabaseTypeByDataSource(DataSource dataSource) throws SQLException{
-        if("".equals(DB_TYPE)) {
+    private static String getDatabaseTypeByDataSource(DataSource dataSource) throws SQLException {
+        if ("".equals(DB_TYPE)) {
             Connection connection = dataSource.getConnection();
             try {
                 DatabaseMetaData md = connection.getMetaData();
                 String dbType = md.getDatabaseProductName().toUpperCase();
-                String sqlserver= "SQL SERVER";
-                if(dbType.indexOf(DataBaseConstant.DB_TYPE_MYSQL)>=0) {
+                String sqlserver = "SQL SERVER";
+                if (dbType.indexOf(DataBaseConstant.DB_TYPE_MYSQL) >= 0) {
                     DB_TYPE = DataBaseConstant.DB_TYPE_MYSQL;
-                }else if(dbType.indexOf(DataBaseConstant.DB_TYPE_ORACLE)>=0 ||dbType.indexOf(DataBaseConstant.DB_TYPE_DM)>=0) {
+                } else if (dbType.indexOf(DataBaseConstant.DB_TYPE_ORACLE) >= 0 || dbType.indexOf(DataBaseConstant.DB_TYPE_DM) >= 0) {
                     DB_TYPE = DataBaseConstant.DB_TYPE_ORACLE;
-                }else if(dbType.indexOf(DataBaseConstant.DB_TYPE_SQLSERVER)>=0||dbType.indexOf(sqlserver)>=0) {
+                } else if (dbType.indexOf(DataBaseConstant.DB_TYPE_SQLSERVER) >= 0 || dbType.indexOf(sqlserver) >= 0) {
                     DB_TYPE = DataBaseConstant.DB_TYPE_SQLSERVER;
-                }else if(dbType.indexOf(DataBaseConstant.DB_TYPE_POSTGRESQL)>=0) {
+                } else if (dbType.indexOf(DataBaseConstant.DB_TYPE_POSTGRESQL) >= 0) {
                     DB_TYPE = DataBaseConstant.DB_TYPE_POSTGRESQL;
-                }else if(dbType.indexOf(DataBaseConstant.DB_TYPE_MARIADB)>=0) {
+                } else if (dbType.indexOf(DataBaseConstant.DB_TYPE_MARIADB) >= 0) {
                     DB_TYPE = DataBaseConstant.DB_TYPE_MARIADB;
-                }else {
+                } else {
                     log.error("数据库类型:[" + dbType + "]不识别!");
                     //throw new JeecgBootException("数据库类型:["+dbType+"]不识别!");
                 }
             } catch (Exception e) {
                 log.error(e.getMessage(), e);
-            }finally {
+            } finally {
                 connection.close();
             }
         }
         return DB_TYPE;
 
     }
+
     /**
      * 获取服务器地址
      *
@@ -327,14 +346,14 @@ public class CommonUtils {
     public static String getBaseUrl(HttpServletRequest request) {
         //1.【兼容】兼容微服务下的 base path-------
         String xGatewayBasePath = request.getHeader(ServiceNameConstants.X_GATEWAY_BASE_PATH);
-        if(oConvertUtils.isNotEmpty(xGatewayBasePath)){
-            log.info("x_gateway_base_path = "+ xGatewayBasePath);
-            return  xGatewayBasePath;
+        if (oConvertUtils.isNotEmpty(xGatewayBasePath)) {
+            log.info("x_gateway_base_path = " + xGatewayBasePath);
+            return xGatewayBasePath;
         }
         //2.【兼容】SSL认证之后,request.getScheme()获取不到https的问题
         // https://blog.csdn.net/weixin_34376986/article/details/89767950
         String scheme = request.getHeader(CommonConstant.X_FORWARDED_SCHEME);
-        if(oConvertUtils.isEmpty(scheme)){
+        if (oConvertUtils.isEmpty(scheme)) {
             scheme = request.getScheme();
         }
 
@@ -346,10 +365,10 @@ public class CommonUtils {
         //返回 host domain
         String baseDomainPath = null;
         int length = 80;
-        if(length == serverPort){
-            baseDomainPath = scheme + "://" + serverName  + contextPath ;
-        }else{
-            baseDomainPath = scheme + "://" + serverName + ":" + serverPort + contextPath ;
+        if (length == serverPort) {
+            baseDomainPath = scheme + "://" + serverName + contextPath;
+        } else {
+            baseDomainPath = scheme + "://" + serverName + ":" + serverPort + contextPath;
         }
         log.debug("-----Common getBaseUrl----- : " + baseDomainPath);
         return baseDomainPath;
@@ -396,6 +415,7 @@ public class CommonUtils {
 
     /**
      * 将list集合以分割符的方式进行分割
+     *
      * @param list      String类型的集合文本
      * @param separator 分隔符
      * @return
@@ -406,7 +426,7 @@ public class CommonUtils {
         }
         return "";
     }
- 
+
     /**
      * 通过table的条件SQL
      *
@@ -437,4 +457,29 @@ public class CommonUtils {
             return tableSql;
         }
     }
+
+    /**
+     * 获取视频时长 秒
+     *
+     * @param videoPath
+     * @return
+     */
+    public static long getVideoDuration(String videoPath) {
+        // 视频时长
+        long time = 0;
+        try {
+            MultimediaObject media = new MultimediaObject(new URL("http://localhost:8080/exam-boot/sys/common/static/" + videoPath));
+            MultimediaInfo info = media.getInfo();
+            // 时长,毫秒级
+            long duration = info.getDuration();
+            // 毫秒级时长转化为秒
+            BigDecimal bigDecimal1 = new BigDecimal(duration);
+            BigDecimal bigDecimal2 = new BigDecimal(1000);
+            // 四舍五入,只保留整数
+            time = bigDecimal1.divide(bigDecimal2, 0, RoundingMode.HALF_UP).longValue();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return time;
+    }
 }

+ 1 - 0
system/system-biz/src/main/java/org/jeecg/modules/system/controller/CommonController.java

@@ -214,6 +214,7 @@ public class CommonController {
                 try {
                     outputStream.close();
                 } catch (IOException e) {
+                    log.info("imgPath:{}", imgPath);
                     log.error(e.getMessage(), e);
                 }
             }

+ 107 - 116
web/src/main/java/com/ynfy/buss/course/course/controller/CourseController.java

@@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.core.metadata.IPage;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.ynfy.buss.course.course.entity.Course;
 import com.ynfy.buss.course.course.service.ICourseService;
+import com.ynfy.buss.course.coursecatalog.service.ICourseCatalogService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import lombok.extern.slf4j.Slf4j;
@@ -21,126 +22,116 @@ import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import java.util.Arrays;
 
- /**
+/**
  * @Description: course
  * @Author: jeecg-boot
- * @Date:   2023-10-24
+ * @Date: 2023-10-24
  * @Version: V1.0
  */
-@Api(tags="course")
+@Api(tags = "course")
 @RestController
 @RequestMapping("/course")
 @Slf4j
 public class CourseController extends JeecgController<Course, ICourseService> {
-	@Autowired
-	private ICourseService courseService;
-	
-	/**
-	 * 分页列表查询
-	 *
-	 * @param course
-	 * @param pageNo
-	 * @param pageSize
-	 * @param req
-	 * @return
-	 */
-	//@AutoLog(value = "course-分页列表查询")
-	@ApiOperation(value="course-分页列表查询", notes="course-分页列表查询")
-	@RequiresPermissions("course:list")
-	@GetMapping(value = "/list")
-	public Result<IPage<Course>> queryPageList(Course course,
-								   @RequestParam(name="pageNo", defaultValue="1") Integer pageNo,
-								   @RequestParam(name="pageSize", defaultValue="10") Integer pageSize,
-								   HttpServletRequest req) {
-		QueryWrapper<Course> queryWrapper = QueryGenerator.initQueryWrapper(course, req.getParameterMap());
-		Page<Course> page = new Page<Course>(pageNo, pageSize);
-		IPage<Course> pageList = courseService.page(page, queryWrapper);
-		return Result.OK(pageList);
-	}
-	
-	/**
-	 *   添加
-	 *
-	 * @param course
-	 * @return
-	 */
-	@AutoLog(value = "course-添加")
-	@ApiOperation(value="course-添加", notes="course-添加")
-	@RequiresPermissions("course:save")
-	@PostMapping(value = "/add")
-	public Result<String> add(@RequestBody Course course) {
-		courseService.save(course);
-		return Result.OK("添加成功!");
-	}
-	
-	/**
-	 *  编辑
-	 *
-	 * @param course
-	 * @return
-	 */
-	@AutoLog(value = "course-编辑")
-	@ApiOperation(value="course-编辑", notes="course-编辑")
-	@RequiresPermissions("course:save")
-	@RequestMapping(value = "/edit", method = {RequestMethod.PUT,RequestMethod.POST})
-	public Result<String> edit(@RequestBody Course course) {
-		courseService.updateById(course);
-		return Result.OK("编辑成功!");
-	}
-	
-	/**
-	 *   通过id删除
-	 *
-	 * @param id
-	 * @return
-	 */
-	@AutoLog(value = "course-通过id删除")
-	@ApiOperation(value="course-通过id删除", notes="course-通过id删除")
-	@RequiresPermissions("course:delete")
-	@DeleteMapping(value = "/delete")
-	public Result<String> delete(@RequestParam(name="id",required=true) String id) {
-		courseService.removeById(id);
-		return Result.OK("删除成功!");
-	}
-	
-	/**
-	 *  批量删除
-	 *
-	 * @param ids
-	 * @return
-	 */
-	@AutoLog(value = "course-批量删除")
-	@ApiOperation(value="course-批量删除", notes="course-批量删除")
-	@RequiresPermissions("course:delete")
-	@DeleteMapping(value = "/deleteBatch")
-	public Result<String> deleteBatch(@RequestParam(name="ids",required=true) String ids) {
-		this.courseService.removeByIds(Arrays.asList(ids.split(",")));
-		return Result.OK("批量删除成功!");
-	}
-	
-	/**
-	 * 通过id查询
-	 *
-	 * @param id
-	 * @return
-	 */
-	//@AutoLog(value = "course-通过id查询")
-	@ApiOperation(value="course-通过id查询", notes="course-通过id查询")
-	@GetMapping(value = "/queryById")
-	public Result<Course> queryById(@RequestParam(name="id",required=true) String id) {
-		Course course = courseService.getById(id);
-		if(course==null) {
-			return Result.error("未找到对应数据");
-		}
-		return Result.OK(course);
-	}
+    @Autowired
+    private ICourseService courseService;
+
+    @Autowired
+    private ICourseCatalogService courseCatalogService;
+
+    /**
+     * 分页列表查询
+     *
+     * @param course
+     * @param pageNo
+     * @param pageSize
+     * @param req
+     * @return
+     */
+    //@AutoLog(value = "course-分页列表查询")
+    @ApiOperation(value = "course-分页列表查询", notes = "course-分页列表查询")
+    @RequiresPermissions("course:list")
+    @GetMapping(value = "/list")
+    public Result<IPage<Course>> queryPageList(Course course,
+                                               @RequestParam(name = "pageNo", defaultValue = "1") Integer pageNo,
+                                               @RequestParam(name = "pageSize", defaultValue = "10") Integer pageSize,
+                                               HttpServletRequest req) {
+        QueryWrapper<Course> queryWrapper = QueryGenerator.initQueryWrapper(course, req.getParameterMap());
+        Page<Course> page = new Page<Course>(pageNo, pageSize);
+        IPage<Course> pageList = courseService.page(page, queryWrapper);
+        return Result.OK(pageList);
+    }
+
+    /**
+     * 添加
+     *
+     * @param course
+     * @return
+     */
+    @AutoLog(value = "course-添加")
+    @ApiOperation(value = "course-添加", notes = "course-添加")
+    @RequiresPermissions("course:save")
+    @PostMapping(value = "/save")
+    public Result<String> save(@RequestBody Course course) {
+        courseService.saveCourse(course);
+        return Result.OK("添加成功!");
+    }
+
+
+    /**
+     * 通过id删除
+     *
+     * @param id
+     * @return
+     */
+    @AutoLog(value = "course-通过id删除")
+    @ApiOperation(value = "course-通过id删除", notes = "course-通过id删除")
+    @RequiresPermissions("course:delete")
+    @DeleteMapping(value = "/delete")
+    public Result<String> delete(@RequestParam(name = "id", required = true) String id) {
+        courseService.removeById(id);
+        return Result.OK("删除成功!");
+    }
+
+    /**
+     * 批量删除
+     *
+     * @param ids
+     * @return
+     */
+    @AutoLog(value = "course-批量删除")
+    @ApiOperation(value = "course-批量删除", notes = "course-批量删除")
+    @RequiresPermissions("course:delete")
+    @DeleteMapping(value = "/deleteBatch")
+    public Result<String> deleteBatch(@RequestParam(name = "ids", required = true) String ids) {
+        this.courseService.removeByIds(Arrays.asList(ids.split(",")));
+        return Result.OK("批量删除成功!");
+    }
+
+    /**
+     * 通过id查询
+     *
+     * @param id
+     * @return
+     */
+    //@AutoLog(value = "course-通过id查询")
+    @ApiOperation(value = "course-通过id查询", notes = "course-通过id查询")
+    @GetMapping(value = "/queryById")
+    public Result<Course> queryById(@RequestParam(name = "id", required = true) String id) {
+        Course course = courseService.getById(id);
+        if (course == null) {
+            return Result.error("未找到对应数据");
+        }
+        course.setCatalogList(courseCatalogService.listByCourseId(course.getId()));
+        return Result.OK(course);
+    }
 
     /**
-    * 导出excel
-    *
-    * @param request
-    * @param course
-    */
+     * 导出excel
+     *
+     * @param request
+     * @param course
+     */
     //@RequiresPermissions("course:exportXls")
     @RequestMapping(value = "/exportXls")
     public ModelAndView exportXls(HttpServletRequest request, Course course) {
@@ -148,12 +139,12 @@ public class CourseController extends JeecgController<Course, ICourseService> {
     }
 
     /**
-      * 通过excel导入数据
-    *
-    * @param request
-    * @param response
-    * @return
-    */
+     * 通过excel导入数据
+     *
+     * @param request
+     * @param response
+     * @return
+     */
     //@RequiresPermissions("course:importExcel")
     @RequestMapping(value = "/importExcel", method = RequestMethod.POST)
     public Result<?> importExcel(HttpServletRequest request, HttpServletResponse response) {

+ 9 - 0
web/src/main/java/com/ynfy/buss/course/course/entity/Course.java

@@ -1,9 +1,11 @@
 package com.ynfy.buss.course.course.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ynfy.buss.course.coursecatalog.entity.CourseCatalog;
 import io.swagger.annotations.ApiModel;
 import io.swagger.annotations.ApiModelProperty;
 import lombok.Data;
@@ -16,6 +18,7 @@ import org.springframework.format.annotation.DateTimeFormat;
 import java.io.Serializable;
 import java.math.BigDecimal;
 import java.util.Date;
+import java.util.List;
 
 /**
  * @Description: course
@@ -164,4 +167,10 @@ public class Course implements Serializable {
      */
     @ApiModelProperty(value = "updateBy")
     private String updateBy;
+
+    /**
+     * 目录
+     */
+    @TableField(exist = false)
+    private List<CourseCatalog> catalogList;
 }

+ 1 - 0
web/src/main/java/com/ynfy/buss/course/course/service/ICourseService.java

@@ -11,4 +11,5 @@ import com.ynfy.buss.course.course.entity.Course;
  */
 public interface ICourseService extends IService<Course> {
 
+    void saveCourse(Course course);
 }

+ 12 - 0
web/src/main/java/com/ynfy/buss/course/course/service/impl/CourseServiceImpl.java

@@ -4,6 +4,9 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ynfy.buss.course.course.mapper.CourseMapper;
 import com.ynfy.buss.course.course.service.ICourseService;
 import com.ynfy.buss.course.course.entity.Course;
+import com.ynfy.buss.course.coursecatalog.service.ICourseCatalogService;
+import com.ynfy.buss.exam.questionanswer.service.IQuestionAnswerService;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
 /**
@@ -15,4 +18,13 @@ import org.springframework.stereotype.Service;
 @Service
 public class CourseServiceImpl extends ServiceImpl<CourseMapper, Course> implements ICourseService {
 
+    @Autowired
+    private ICourseCatalogService courseCatalogService;
+
+    @Override
+    public void saveCourse(Course course) {
+        this.saveOrUpdate(course);
+        // 保存题目答案选项
+        courseCatalogService.saveAll(course.getId(), course.getCatalogList());
+    }
 }

+ 70 - 31
web/src/main/java/com/ynfy/buss/course/coursecatalog/entity/CourseCatalog.java

@@ -1,6 +1,7 @@
 package com.ynfy.buss.course.coursecatalog.entity;
 
 import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
 import com.baomidou.mybatisplus.annotation.TableId;
 import com.baomidou.mybatisplus.annotation.TableName;
 import com.fasterxml.jackson.annotation.JsonFormat;
@@ -14,75 +15,113 @@ import org.springframework.format.annotation.DateTimeFormat;
 
 import java.io.Serializable;
 import java.util.Date;
+import java.util.List;
 
 /**
  * @Description: course_catalog
  * @Author: jeecg-boot
- * @Date:   2023-10-25
+ * @Date: 2023-10-25
  * @Version: V1.0
  */
 @Data
 @TableName("course_catalog")
 @Accessors(chain = true)
 @EqualsAndHashCode(callSuper = false)
-@ApiModel(value="course_catalog对象", description="course_catalog")
+@ApiModel(value = "course_catalog对象", description = "course_catalog")
 public class CourseCatalog implements Serializable {
     private static final long serialVersionUID = 1L;
 
-	/**id*/
-	@TableId(type = IdType.ASSIGN_ID)
+    /**
+     * id
+     */
+    @TableId(type = IdType.ASSIGN_ID)
     @ApiModelProperty(value = "id")
     private String id;
-	/**父id*/
-	@Excel(name = "父id", width = 15)
+    /**
+     * 父id
+     */
+    @Excel(name = "父id", width = 15)
     @ApiModelProperty(value = "父id")
     private String parentId;
-	/**课程id*/
-	@Excel(name = "课程id", width = 15)
+    /**
+     * 课程id
+     */
+    @Excel(name = "课程id", width = 15)
     @ApiModelProperty(value = "课程id")
     private String courseId;
-	/**目录或任务名称*/
-	@Excel(name = "目录或任务名称", width = 15)
+    /**
+     * 目录或任务名称
+     */
+    @Excel(name = "目录或任务名称", width = 15)
     @ApiModelProperty(value = "目录或任务名称")
     private String name;
-	/**目录介绍*/
-	@Excel(name = "目录介绍", width = 15)
+    /**
+     * 目录介绍
+     */
+    @Excel(name = "目录介绍", width = 15)
     @ApiModelProperty(value = "目录介绍")
     private String catalogIntro;
-	/**1:目录,2:任务*/
-	@Excel(name = "1:目录,2:任务", width = 15)
+    /**
+     * 1:目录,2:任务
+     */
+    @Excel(name = "1:目录,2:任务", width = 15)
     @ApiModelProperty(value = "1:目录,2:任务")
     private Integer type;
-	/**资源类型  1:视频,2:文档*/
-	@Excel(name = "资源类型  1:视频,2:文档", width = 15)
+    /**
+     * 资源类型  1:视频,2:文档
+     */
+    @Excel(name = "资源类型  1:视频,2:文档", width = 15)
     @ApiModelProperty(value = "资源类型  1:视频,2:文档")
     private Integer resourceType;
-	/**资源id*/
-	@Excel(name = "资源id", width = 15)
+    /**
+     * 资源id
+     */
+    @Excel(name = "资源id", width = 15)
     @ApiModelProperty(value = "资源id")
     private String resourceId;
-	/**视频时长*/
-	@Excel(name = "视频时长", width = 15)
+    /**
+     * 视频时长
+     */
+    @Excel(name = "视频时长", width = 15)
     @ApiModelProperty(value = "视频时长")
-    private String videoHour;
-	/**必学时长*/
-	@Excel(name = "必学时长", width = 15)
+    private Long videoHour;
+    /**
+     * 必学时长
+     */
+    @Excel(name = "必学时长", width = 15)
     @ApiModelProperty(value = "必学时长")
     private Integer mustLearnTime;
-	/**createTime*/
-	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+
+    @Excel(name = "排序", width = 15)
+    @ApiModelProperty(value = "排序")
+    private Integer sort;
+
+    /**
+     * createTime
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @ApiModelProperty(value = "createTime")
     private Date createTime;
-	/**createBy*/
+    /**
+     * createBy
+     */
     @ApiModelProperty(value = "createBy")
     private String createBy;
-	/**updateTime*/
-	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
-    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
+    /**
+     * updateTime
+     */
+    @JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
     @ApiModelProperty(value = "updateTime")
     private Date updateTime;
-	/**updateBy*/
+    /**
+     * updateBy
+     */
     @ApiModelProperty(value = "updateBy")
     private String updateBy;
+
+    @TableField(exist = false)
+    private List<CourseCatalog> childList;
+
 }

+ 45 - 0
web/src/main/java/com/ynfy/buss/course/coursecatalog/enums/CatalogType.java

@@ -0,0 +1,45 @@
+package com.ynfy.buss.course.coursecatalog.enums;
+
+
+/**
+ * 课程目录类型
+ */
+public enum CatalogType {
+    CATALOG(1, "目录"),
+    TASK(2, "任务");
+
+    private Integer code;
+
+    private String value;
+
+    CatalogType(Integer code, String value) {
+        this.code = code;
+        this.value = value;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public static CatalogType getByCode(Integer code) {
+        for (CatalogType catalogType : values()) {
+            if (catalogType.getCode().equals(code)) {
+                return catalogType;
+            }
+        }
+        return null;
+    }
+
+}

+ 45 - 0
web/src/main/java/com/ynfy/buss/course/coursecatalog/enums/ResourceType.java

@@ -0,0 +1,45 @@
+package com.ynfy.buss.course.coursecatalog.enums;
+
+
+/**
+ * 资源类型
+ */
+public enum ResourceType {
+    VIDEO(1, "视频"),
+    FILE(2, "文档");
+
+    private Integer code;
+
+    private String value;
+
+    ResourceType(Integer code, String value) {
+        this.code = code;
+        this.value = value;
+    }
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getValue() {
+        return value;
+    }
+
+    public void setValue(String value) {
+        this.value = value;
+    }
+
+    public static ResourceType getByCode(Integer code) {
+        for (ResourceType resourceType : values()) {
+            if (resourceType.getCode().equals(code)) {
+                return resourceType;
+            }
+        }
+        return null;
+    }
+
+}

+ 15 - 1
web/src/main/java/com/ynfy/buss/course/coursecatalog/service/ICourseCatalogService.java

@@ -3,12 +3,26 @@ package com.ynfy.buss.course.coursecatalog.service;
 import com.baomidou.mybatisplus.extension.service.IService;
 import com.ynfy.buss.course.coursecatalog.entity.CourseCatalog;
 
+import java.util.List;
+
 /**
  * @Description: course_catalog
  * @Author: jeecg-boot
- * @Date:   2023-10-24
+ * @Date: 2023-10-24
  * @Version: V1.0
  */
 public interface ICourseCatalogService extends IService<CourseCatalog> {
 
+    void remove(String courseId);
+
+    void saveAll(String courseId, List<CourseCatalog> catalogList);
+
+
+    /**
+     * 根据课程id获取目录
+     *
+     * @param courseId
+     * @return
+     */
+    List<CourseCatalog> listByCourseId(String courseId);
 }

+ 98 - 1
web/src/main/java/com/ynfy/buss/course/coursecatalog/service/impl/CourseCatalogServiceImpl.java

@@ -1,18 +1,115 @@
 package com.ynfy.buss.course.coursecatalog.service.impl;
 
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
 import com.ynfy.buss.course.coursecatalog.entity.CourseCatalog;
+import com.ynfy.buss.course.coursecatalog.enums.CatalogType;
+import com.ynfy.buss.course.coursecatalog.enums.ResourceType;
 import com.ynfy.buss.course.coursecatalog.mapper.CourseCatalogMapper;
 import com.ynfy.buss.course.coursecatalog.service.ICourseCatalogService;
+import org.apache.commons.lang3.StringUtils;
+import org.jeecg.common.util.CommonUtils;
 import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.stream.Collectors;
 
 /**
  * @Description: course_catalog
  * @Author: jeecg-boot
- * @Date:   2023-10-24
+ * @Date: 2023-10-24
  * @Version: V1.0
  */
 @Service
 public class CourseCatalogServiceImpl extends ServiceImpl<CourseCatalogMapper, CourseCatalog> implements ICourseCatalogService {
 
+    /**
+     * 删除
+     *
+     * @param courseId
+     */
+    @Override
+    public void remove(String courseId) {
+        QueryWrapper<CourseCatalog> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(CourseCatalog::getCourseId, courseId);
+        this.remove(wrapper);
+    }
+
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void saveAll(String courseId, List<CourseCatalog> catalogList) {
+        remove(courseId);
+        List<CourseCatalog> newCatalogList = new ArrayList<>();
+        if (!CollectionUtils.isEmpty(catalogList)) {
+            int sort = 1;
+            for (CourseCatalog item : catalogList) {
+                //根节点
+                item.setCourseId(courseId);
+                item.setSort(sort);
+                if (ResourceType.VIDEO.getCode().equals(item.getResourceType())) {//如果是视频,则计算视频时长
+                    item.setVideoHour(CommonUtils.getVideoDuration(item.getResourceId()));
+                }
+                sort++;
+                newCatalogList.add(item);
+
+                //子节点
+                if (!CollectionUtils.isEmpty(item.getChildList())) {
+                    int index = 1;
+                    for (CourseCatalog child : item.getChildList()) {
+                        if (ResourceType.VIDEO.getCode().equals(child.getResourceType())) {
+                            child.setVideoHour(CommonUtils.getVideoDuration(child.getResourceId()));
+                        }
+                        child.setCourseId(courseId);
+                        child.setSort(index);
+                        newCatalogList.add(child);
+                        index++;
+                    }
+                }
+            }
+            saveBatch(newCatalogList);
+        }
+    }
+
+    /**
+     * 根据课程id获取目录
+     *
+     * @param courseId
+     * @return
+     */
+    @Override
+    public List<CourseCatalog> listByCourseId(String courseId) {
+        QueryWrapper<CourseCatalog> wrapper = new QueryWrapper<>();
+        wrapper.lambda().eq(CourseCatalog::getCourseId, courseId);
+        List<CourseCatalog> courseCatalogList = list(wrapper);
+        if (!CollectionUtils.isEmpty(courseCatalogList)) {
+            //获取根节点
+            List<CourseCatalog> rootList = courseCatalogList.stream().filter(courseCatalog ->
+                            StringUtils.isBlank(courseCatalog.getParentId())).sorted(Comparator.comparing(CourseCatalog::getSort))
+                    .collect(Collectors.toList());
+            if (!CollectionUtils.isEmpty(rootList)) {
+                rootList.forEach(root -> {
+                    //如果根节点是目录,获取任务子节点
+                    if (CatalogType.CATALOG.getCode().equals(root.getType())) {
+                        List<CourseCatalog> childList = courseCatalogList.stream().filter(courseCatalog ->
+                                StringUtils.isNotBlank(courseCatalog.getParentId()) && courseCatalog.getParentId().equals(root.getId())
+                        ).sorted(Comparator.comparing(CourseCatalog::getSort)).collect(Collectors.toList());
+                        if (!CollectionUtils.isEmpty(childList)) {
+                            if (CollectionUtils.isEmpty(root.getChildList())) {
+                                root.setChildList(new ArrayList<>());
+                            }
+                            root.getChildList().addAll(childList);
+                        }
+                    }
+                });
+            }
+            return rootList;
+        }
+        return Collections.emptyList();
+    }
+
 }