文件本地上传+知识图谱功能
This commit is contained in:
parent
5ce697523a
commit
c66439995f
@ -12,4 +12,5 @@ import org.springframework.stereotype.Component;
|
||||
public class AIPlatformConfig {
|
||||
private String host;
|
||||
private String api_key;
|
||||
private String profile;
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package xyz.playedu.api.controller.backend.jc;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
@ -7,6 +8,7 @@ import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.jc.domain.Knowledge;
|
||||
import xyz.playedu.jc.param.KnowledgeParam;
|
||||
import xyz.playedu.jc.service.IKnowledgeService;
|
||||
|
||||
import java.util.HashMap;
|
||||
@ -22,48 +24,52 @@ public class KnowledgeController {
|
||||
@Autowired
|
||||
private IKnowledgeService knowledgeService;
|
||||
|
||||
/** 分页列表 */
|
||||
@GetMapping("/index")
|
||||
public JsonResponse index(@RequestParam HashMap<String, Object> params) {
|
||||
PaginationResult<Knowledge> result = knowledgeService.paginate(params);
|
||||
return JsonResponse.data(result);
|
||||
|
||||
/**
|
||||
* 获取知识点卡片列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResponse list(KnowledgeParam param) {
|
||||
List<Knowledge> list = knowledgeService.listVo(param);
|
||||
return JsonResponse.data(list);
|
||||
}
|
||||
|
||||
/** 全量列表 */
|
||||
@GetMapping("/list")
|
||||
public JsonResponse list() {
|
||||
List<Knowledge> list = knowledgeService.list();
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取知识点树结构
|
||||
*/
|
||||
@GetMapping("/treeList")
|
||||
public JsonResponse treeList(KnowledgeParam param) {
|
||||
List<Knowledge> list = knowledgeService.treeList(param);
|
||||
return JsonResponse.data(list);
|
||||
}
|
||||
|
||||
/** 详情 */
|
||||
@GetMapping("/{id}")
|
||||
public JsonResponse detail(@PathVariable("id") Integer id) {
|
||||
Knowledge one = knowledgeService.getById(id);
|
||||
return JsonResponse.data(one);
|
||||
return JsonResponse.data( knowledgeService.getByIdVo(id));
|
||||
}
|
||||
|
||||
/** 新增 */
|
||||
@Log(title = "新增知识点", businessType = BusinessTypeConstant.INSERT)
|
||||
@PostMapping
|
||||
public JsonResponse store(@RequestBody Knowledge knowledge) {
|
||||
knowledgeService.save(knowledge);
|
||||
@PostMapping("/saveOrUpdateVo")
|
||||
public JsonResponse saveOrUpdateVo(@RequestBody Knowledge knowledge) {
|
||||
knowledgeService.saveOrUpdateVo(knowledge);
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
/** 修改 */
|
||||
@Log(title = "修改知识点", businessType = BusinessTypeConstant.UPDATE)
|
||||
@PutMapping
|
||||
public JsonResponse update(@RequestBody Knowledge knowledge) {
|
||||
knowledgeService.updateById(knowledge);
|
||||
return JsonResponse.success();
|
||||
}
|
||||
|
||||
|
||||
/** 删除 */
|
||||
@Log(title = "删除知识点", businessType = BusinessTypeConstant.DELETE)
|
||||
@DeleteMapping("/{id}")
|
||||
public JsonResponse destroy(@PathVariable("id") Integer id) {
|
||||
knowledgeService.removeById(id);
|
||||
Knowledge byId = knowledgeService.getById(id);
|
||||
LambdaQueryWrapper<Knowledge> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.likeRight(Knowledge::getKnowledgeCode, byId.getKnowledgeCode());
|
||||
knowledgeService.remove(queryWrapper);
|
||||
return JsonResponse.success();
|
||||
}
|
||||
}
|
||||
|
||||
@ -0,0 +1,60 @@
|
||||
package xyz.playedu.api.controller.backend.system;
|
||||
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import xyz.playedu.common.config.PlatformConfig;
|
||||
import xyz.playedu.common.config.ServerConfig;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.common.util.FileUploadUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 通用请求处理
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/common")
|
||||
public class LocalFileController {
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalFileController.class);
|
||||
private static final String FILE_DELIMETER = ",";
|
||||
@Autowired
|
||||
private ServerConfig serverConfig;
|
||||
|
||||
/**
|
||||
* 通用上传请求(单个)
|
||||
*/
|
||||
@PostMapping("/upload")
|
||||
public JsonResponse uploadFile(MultipartFile file) throws Exception {
|
||||
// 上传文件路径
|
||||
String filePath = PlatformConfig.getUploadPath();
|
||||
// 上传并返回新文件名称
|
||||
String fileName = FileUploadUtils.upload(filePath, file);
|
||||
try {
|
||||
String url = serverConfig.getUrl() + fileName;
|
||||
JSONObject ajax = new JSONObject();
|
||||
ajax.put("url", url);
|
||||
ajax.put("path", fileName);
|
||||
ajax.put("newFileName", FileUploadUtils.getName(fileName));
|
||||
ajax.put("originalFilename", file.getOriginalFilename());
|
||||
return JsonResponse.data(ajax);
|
||||
} catch (Exception e) {
|
||||
return JsonResponse.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@ -54,6 +54,8 @@ public class UploadController {
|
||||
|
||||
@Autowired private AppConfigService appConfigService;
|
||||
|
||||
|
||||
|
||||
@PostMapping("/minio")
|
||||
@Log(title = "上传-MinIO", businessType = BusinessTypeConstant.UPLOAD)
|
||||
public JsonResponse uploadMinio(
|
||||
|
||||
@ -0,0 +1,49 @@
|
||||
package xyz.playedu.api.controller.frontend;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import xyz.playedu.common.annotation.Log;
|
||||
import xyz.playedu.common.constant.BusinessTypeConstant;
|
||||
import xyz.playedu.common.types.JsonResponse;
|
||||
import xyz.playedu.jc.domain.Knowledge;
|
||||
import xyz.playedu.jc.param.KnowledgeParam;
|
||||
import xyz.playedu.jc.service.IKnowledgeService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识点管理
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/v1/jc/knowledge")
|
||||
public class KnowledgeController {
|
||||
|
||||
@Autowired
|
||||
private IKnowledgeService knowledgeService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取知识点卡片列表
|
||||
*/
|
||||
@GetMapping("/list")
|
||||
public JsonResponse list(KnowledgeParam param) {
|
||||
List<Knowledge> list = knowledgeService.listVo(param);
|
||||
return JsonResponse.data(list);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取知识点树结构
|
||||
*/
|
||||
@GetMapping("/treeList")
|
||||
public JsonResponse treeList(KnowledgeParam param) {
|
||||
List<Knowledge> list = knowledgeService.treeList(param);
|
||||
return JsonResponse.data(list);
|
||||
}
|
||||
|
||||
/** 详情 */
|
||||
@GetMapping("/getDetail")
|
||||
public JsonResponse detail(@RequestParam("id") Integer id) {
|
||||
return JsonResponse.data( knowledgeService.stuGetByIdVo(id));
|
||||
}
|
||||
}
|
||||
@ -3,10 +3,14 @@ server:
|
||||
tomcat:
|
||||
max-swallow-size: 10000MB
|
||||
connection-timeout: 600000
|
||||
|
||||
ai:
|
||||
platform:
|
||||
host: "http://localhost:9380/"
|
||||
api-key: "ragflow-VlZWVjMDg0ZjAzMTExZWZhZDhkZTU5ZD"
|
||||
platform:
|
||||
config:
|
||||
profile: D:/ruoyi/uploadPath
|
||||
spring:
|
||||
profiles:
|
||||
active: kafka,quartz,dev
|
||||
|
||||
@ -0,0 +1,50 @@
|
||||
package xyz.playedu.common.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
|
||||
@Component
|
||||
@ConfigurationProperties(prefix = "platform.config")
|
||||
public class PlatformConfig {
|
||||
|
||||
private static String profile;
|
||||
|
||||
|
||||
public static String getProfile() {
|
||||
return profile;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void setProfile(String profile) {
|
||||
PlatformConfig.profile = profile;
|
||||
}
|
||||
/**
|
||||
* 获取导入上传路径
|
||||
*/
|
||||
public static String getImportPath() {
|
||||
return getProfile() + "/import";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取头像上传路径
|
||||
*/
|
||||
public static String getAvatarPath() {
|
||||
return getProfile() + "/avatar";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下载路径
|
||||
*/
|
||||
public static String getDownloadPath() {
|
||||
return getProfile() + "/download/";
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上传路径
|
||||
*/
|
||||
public static String getUploadPath() {
|
||||
return getProfile() + "/upload";
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,31 @@
|
||||
package xyz.playedu.common.config;
|
||||
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import org.springframework.stereotype.Component;
|
||||
import xyz.playedu.common.util.ServletUtils;
|
||||
|
||||
|
||||
/**
|
||||
* 服务相关配置
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
@Component
|
||||
public class ServerConfig {
|
||||
public static String getDomain(HttpServletRequest request) {
|
||||
StringBuffer url = request.getRequestURL();
|
||||
String contextPath = request.getServletContext().getContextPath();
|
||||
return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取完整的请求路径,包括:域名,端口,上下文访问路径
|
||||
*
|
||||
* @return 服务地址
|
||||
*/
|
||||
public String getUrl() {
|
||||
HttpServletRequest request = ServletUtils.getRequest();
|
||||
return getDomain(request);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,171 @@
|
||||
package xyz.playedu.common.util;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.Objects;
|
||||
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
|
||||
import org.springframework.web.multipart.MultipartFile;
|
||||
import xyz.playedu.common.config.PlatformConfig;
|
||||
|
||||
|
||||
/**
|
||||
* 文件上传工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class FileUploadUtils {
|
||||
/**
|
||||
* 默认大小 50M
|
||||
*/
|
||||
public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
|
||||
|
||||
/**
|
||||
* 默认的文件名最大长度 100
|
||||
*/
|
||||
public static final int DEFAULT_FILE_NAME_LENGTH = 100;
|
||||
|
||||
/**
|
||||
* 默认上传的地址
|
||||
*/
|
||||
private static String defaultBaseDir = PlatformConfig.getProfile();
|
||||
public static final String RESOURCE_PREFIX = "/profile";
|
||||
|
||||
public static String getDefaultBaseDir() {
|
||||
return defaultBaseDir;
|
||||
}
|
||||
|
||||
public static void setDefaultBaseDir(String defaultBaseDir) {
|
||||
FileUploadUtils.defaultBaseDir = defaultBaseDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* 以默认配置进行文件上传
|
||||
*
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
* @throws Exception
|
||||
*/
|
||||
public static final String upload(MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 根据文件路径上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @return 文件名称
|
||||
* @throws IOException
|
||||
*/
|
||||
public static final String upload(String baseDir, MultipartFile file) throws IOException {
|
||||
try {
|
||||
return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
|
||||
} catch (Exception e) {
|
||||
throw new IOException(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件上传
|
||||
*
|
||||
* @param baseDir 相对应用的基目录
|
||||
* @param file 上传的文件
|
||||
* @param allowedExtension 上传文件类型
|
||||
* @return 返回上传成功的文件名
|
||||
* @throws IOException 比如读写文件出错时
|
||||
*/
|
||||
public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
|
||||
throws Exception {
|
||||
int fileNamelength = Objects.requireNonNull(file.getOriginalFilename()).length();
|
||||
if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH) {
|
||||
throw new Exception("文件名过长"+FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
|
||||
}
|
||||
|
||||
|
||||
String fileName = extractFilename(file);
|
||||
|
||||
String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
|
||||
file.transferTo(Paths.get(absPath));
|
||||
return getPathFileName(baseDir, fileName);
|
||||
}
|
||||
|
||||
/**
|
||||
* 编码文件名
|
||||
*/
|
||||
public static final String extractFilename(MultipartFile file) {
|
||||
return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
|
||||
FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
|
||||
}
|
||||
|
||||
public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException {
|
||||
File desc = new File(uploadDir + File.separator + fileName);
|
||||
|
||||
if (!desc.exists()) {
|
||||
if (!desc.getParentFile().exists()) {
|
||||
desc.getParentFile().mkdirs();
|
||||
}
|
||||
}
|
||||
return desc;
|
||||
}
|
||||
|
||||
public static final String getPathFileName(String uploadDir, String fileName) throws IOException {
|
||||
int dirLastIndex = PlatformConfig.getProfile().length() + 1;
|
||||
String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
|
||||
return RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 判断MIME类型是否是允许的MIME类型
|
||||
*
|
||||
* @param extension
|
||||
* @param allowedExtension
|
||||
* @return
|
||||
*/
|
||||
public static final boolean isAllowedExtension(String extension, String[] allowedExtension) {
|
||||
for (String str : allowedExtension) {
|
||||
if (str.equalsIgnoreCase(extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件名的后缀
|
||||
*
|
||||
* @param file 表单文件
|
||||
* @return 后缀名
|
||||
*/
|
||||
public static final String getExtension(MultipartFile file) {
|
||||
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||
if (StringUtils.isEmpty(extension)) {
|
||||
extension = MimeTypeUtils.getExtension(Objects.requireNonNull(file.getContentType()));
|
||||
}
|
||||
return extension;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
|
||||
*
|
||||
* @param fileName 路径名称
|
||||
* @return 没有文件路径的名称
|
||||
*/
|
||||
public static String getName(String fileName) {
|
||||
if (fileName == null) {
|
||||
return null;
|
||||
}
|
||||
int lastUnixPos = fileName.lastIndexOf('/');
|
||||
int lastWindowsPos = fileName.lastIndexOf('\\');
|
||||
int index = Math.max(lastUnixPos, lastWindowsPos);
|
||||
return fileName.substring(index + 1);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,56 @@
|
||||
package xyz.playedu.common.util;
|
||||
|
||||
/**
|
||||
* 媒体类型工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class MimeTypeUtils {
|
||||
public static final String IMAGE_PNG = "image/png";
|
||||
|
||||
public static final String IMAGE_JPG = "image/jpg";
|
||||
|
||||
public static final String IMAGE_JPEG = "image/jpeg";
|
||||
|
||||
public static final String IMAGE_BMP = "image/bmp";
|
||||
|
||||
public static final String IMAGE_GIF = "image/gif";
|
||||
|
||||
public static final String[] IMAGE_EXTENSION = {"bmp", "gif", "jpg", "jpeg", "png"};
|
||||
|
||||
public static final String[] FLASH_EXTENSION = {"swf", "flv"};
|
||||
|
||||
public static final String[] MEDIA_EXTENSION = {"swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
|
||||
"asf", "rm", "rmvb"};
|
||||
|
||||
public static final String[] VIDEO_EXTENSION = {"mp4", "avi", "rmvb"};
|
||||
|
||||
public static final String[] DEFAULT_ALLOWED_EXTENSION = {
|
||||
// 图片
|
||||
"bmp", "gif", "jpg", "jpeg", "png",
|
||||
// word excel powerpoint
|
||||
"doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
|
||||
// 压缩文件
|
||||
"rar", "zip", "gz", "bz2",
|
||||
// 视频格式
|
||||
"mp4", "avi", "rmvb",
|
||||
// pdf
|
||||
"pdf"};
|
||||
|
||||
public static String getExtension(String prefix) {
|
||||
switch (prefix) {
|
||||
case IMAGE_PNG:
|
||||
return "png";
|
||||
case IMAGE_JPG:
|
||||
return "jpg";
|
||||
case IMAGE_JPEG:
|
||||
return "jpeg";
|
||||
case IMAGE_BMP:
|
||||
return "bmp";
|
||||
case IMAGE_GIF:
|
||||
return "gif";
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
package xyz.playedu.common.util;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
|
||||
/**
|
||||
* @author ruoyi 序列生成类
|
||||
*/
|
||||
public class Seq {
|
||||
// 通用序列类型
|
||||
public static final String commSeqType = "COMMON";
|
||||
|
||||
// 上传序列类型
|
||||
public static final String uploadSeqType = "UPLOAD";
|
||||
// 机器标识
|
||||
private static final String machineCode = "A";
|
||||
// 通用接口序列数
|
||||
private static AtomicInteger commSeq = new AtomicInteger(1);
|
||||
// 上传接口序列数
|
||||
private static AtomicInteger uploadSeq = new AtomicInteger(1);
|
||||
|
||||
/**
|
||||
* 获取通用序列号
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId() {
|
||||
return getId(commSeqType);
|
||||
}
|
||||
|
||||
/**
|
||||
* 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(String type) {
|
||||
AtomicInteger atomicInt = commSeq;
|
||||
if (uploadSeqType.equals(type)) {
|
||||
atomicInt = uploadSeq;
|
||||
}
|
||||
return getId(atomicInt, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
|
||||
*
|
||||
* @param atomicInt 序列数
|
||||
* @param length 数值长度
|
||||
* @return 序列值
|
||||
*/
|
||||
public static String getId(AtomicInteger atomicInt, int length) {
|
||||
String result = DateUtil.format(DateUtil.date(), "yyyyMMddHHmmss");
|
||||
result += machineCode;
|
||||
result += getSeq(atomicInt, length);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
|
||||
*
|
||||
* @return 序列值
|
||||
*/
|
||||
private synchronized static String getSeq(AtomicInteger atomicInt, int length) {
|
||||
// 先取值再+1
|
||||
int value = atomicInt.getAndIncrement();
|
||||
|
||||
// 如果更新后值>=10 的 (length)幂次方则重置为1
|
||||
int maxSeq = (int) Math.pow(10, length);
|
||||
if (atomicInt.get() >= maxSeq) {
|
||||
atomicInt.set(1);
|
||||
}
|
||||
// 转字符串,用0左补齐
|
||||
return StringUtils.padl(value, length);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,72 @@
|
||||
package xyz.playedu.common.util;
|
||||
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import jakarta.servlet.http.HttpServletResponse;
|
||||
import jakarta.servlet.http.HttpSession;
|
||||
import org.springframework.web.context.request.RequestAttributes;
|
||||
import org.springframework.web.context.request.RequestContextHolder;
|
||||
import org.springframework.web.context.request.ServletRequestAttributes;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 客户端工具类
|
||||
*
|
||||
* @author ruoyi
|
||||
*/
|
||||
public class ServletUtils {
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取request
|
||||
*/
|
||||
public static HttpServletRequest getRequest() {
|
||||
return getRequestAttributes().getRequest();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取response
|
||||
*/
|
||||
public static HttpServletResponse getResponse() {
|
||||
return getRequestAttributes().getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取session
|
||||
*/
|
||||
public static HttpSession getSession() {
|
||||
return getRequest().getSession();
|
||||
}
|
||||
|
||||
public static ServletRequestAttributes getRequestAttributes() {
|
||||
RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
|
||||
return (ServletRequestAttributes) attributes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 将字符串渲染到客户端
|
||||
*
|
||||
* @param response 渲染对象
|
||||
* @param string 待渲染的字符串
|
||||
*/
|
||||
public static void renderString(HttpServletResponse response, String string) {
|
||||
try {
|
||||
response.setStatus(200);
|
||||
response.setContentType("application/json");
|
||||
response.setCharacterEncoding("utf-8");
|
||||
response.getWriter().print(string);
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_book_chapter")
|
||||
public class BookChapter {
|
||||
public class BookChapter extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -34,23 +35,11 @@ public class BookChapter {
|
||||
/** 章节名 */
|
||||
@TableField("name")
|
||||
private String name;
|
||||
/** 层级 */
|
||||
private Integer level;
|
||||
|
||||
/** 排序 */
|
||||
@TableField("sort")
|
||||
private Integer sort;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_book_department_user")
|
||||
public class BookDepartmentUser {
|
||||
public class BookDepartmentUser extends TenantBaseDO {
|
||||
|
||||
/** 教材ID */
|
||||
@TableField("book_id")
|
||||
@ -28,18 +29,4 @@ public class BookDepartmentUser {
|
||||
@TableField("type")
|
||||
private Integer type;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_book_paper")
|
||||
public class BookPaper {
|
||||
public class BookPaper extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -32,18 +33,4 @@ public class BookPaper {
|
||||
@TableField("extra")
|
||||
private String extra;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
@ -6,6 +6,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -15,7 +16,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_chapter_content")
|
||||
public class ChapterContent {
|
||||
public class ChapterContent extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -34,28 +35,9 @@ public class ChapterContent {
|
||||
@TableField("type")
|
||||
private String type;
|
||||
|
||||
// /** 关联资源ID(逗号分隔) */
|
||||
// @TableField("resource_ids")
|
||||
// private String resourceIds;
|
||||
//
|
||||
// /** 关联知识点ID(逗号分隔) */
|
||||
// @TableField("knowledge_ids")
|
||||
// private String knowledgeIds;
|
||||
private String knowledgeCode;
|
||||
|
||||
/** 创建人 */
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
/** 更新人 */
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
/** 章节名称 */
|
||||
@TableField(exist = false)
|
||||
private String chapterName;
|
||||
}
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_discussion")
|
||||
public class Discussion {
|
||||
public class Discussion extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -51,20 +52,12 @@ public class Discussion {
|
||||
@TableField("status")
|
||||
private Integer status;
|
||||
|
||||
/** 创建人(可以是用户名) */
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
/** 知识点编码 */
|
||||
@TableField(exist = false)
|
||||
private String knowledgeCode;
|
||||
@TableField(exist = false)
|
||||
private String chapterName;
|
||||
@TableField(exist = false)
|
||||
private String orderType;
|
||||
|
||||
/** 更新人 */
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_discussion_detail")
|
||||
public class DiscussionDetail {
|
||||
public class DiscussionDetail extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -46,19 +47,4 @@ public class DiscussionDetail {
|
||||
/** 讨论内容 */
|
||||
@TableField("content")
|
||||
private String content;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
|
||||
@ -31,8 +31,8 @@ public class JCResource {
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
@TableField("konwledge_code")
|
||||
private String konwledgeCode;
|
||||
@TableField("knowledge_code")
|
||||
private String knowledgeCode;
|
||||
|
||||
|
||||
/** 文本描述 AI分析或自动填入 */
|
||||
|
||||
@ -5,8 +5,10 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识点表
|
||||
@ -14,7 +16,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_knowledge")
|
||||
public class Knowledge {
|
||||
public class Knowledge extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -31,9 +33,9 @@ public class Knowledge {
|
||||
@TableField("name")
|
||||
private String name;
|
||||
|
||||
/** 知识点code(字段名拼写为 konwledge_code) */
|
||||
@TableField("konwledge_code")
|
||||
private String konwledgeCode;
|
||||
/** 知识点code(字段名拼写为 knowledge_code) */
|
||||
@TableField("knowledge_code")
|
||||
private String knowledgeCode;
|
||||
|
||||
/** 知识点介绍 */
|
||||
@TableField("desc")
|
||||
@ -41,11 +43,14 @@ public class Knowledge {
|
||||
|
||||
/** 层级 */
|
||||
@TableField("level")
|
||||
private String level;
|
||||
private Integer level;
|
||||
|
||||
/** 知识点类型 */
|
||||
@TableField("type")
|
||||
private String type;
|
||||
/** 是否是真实知识点 */
|
||||
@TableField("is_real")
|
||||
private String isReal;
|
||||
|
||||
/** 当前层级排序 */
|
||||
@TableField("order_num")
|
||||
@ -54,19 +59,7 @@ public class Knowledge {
|
||||
/** 预留JSON */
|
||||
@TableField("extra_json")
|
||||
private String extraJson;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
//子节点
|
||||
@TableField(exist = false)
|
||||
private List<Knowledge> children;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_note")
|
||||
public class Note {
|
||||
public class Note extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -50,19 +51,11 @@ public class Note {
|
||||
/** 存储笔记信息的JSON(位置信息等) */
|
||||
@TableField("extra_json")
|
||||
private String extraJson;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
/** 知识点编码 */
|
||||
@TableField(exist = false)
|
||||
private String knowledgeCode;
|
||||
@TableField(exist = false)
|
||||
private String chapterName;
|
||||
@TableField(exist = false)
|
||||
private String orderType;
|
||||
}
|
||||
|
||||
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.Data;
|
||||
import xyz.playedu.framework.tenant.core.db.TenantBaseDO;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
@ -14,7 +15,7 @@ import java.util.Date;
|
||||
*/
|
||||
@Data
|
||||
@TableName("jc_textbook")
|
||||
public class Textbook {
|
||||
public class Textbook extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.AUTO)
|
||||
private Integer id;
|
||||
@ -54,20 +55,4 @@ public class Textbook {
|
||||
@TableField("publish_time")
|
||||
private Date publishTime;
|
||||
|
||||
/** 创建人 */
|
||||
@TableField("creator")
|
||||
private String creator;
|
||||
|
||||
/** 更新人 */
|
||||
@TableField("updater")
|
||||
private String updater;
|
||||
|
||||
@TableField("create_time")
|
||||
private Date createTime;
|
||||
|
||||
@TableField("update_time")
|
||||
private Date updateTime;
|
||||
|
||||
@TableField("tenant_id")
|
||||
private String tenantId;
|
||||
}
|
||||
@ -1,10 +1,15 @@
|
||||
package xyz.playedu.jc.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import xyz.playedu.jc.domain.Discussion;
|
||||
import xyz.playedu.jc.domain.Note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 讨论 Mapper
|
||||
*/
|
||||
public interface DiscussionMapper extends BaseMapper<Discussion> {
|
||||
List<Discussion> listVo(@Param("param") Discussion note);
|
||||
}
|
||||
|
||||
@ -1,10 +1,14 @@
|
||||
package xyz.playedu.jc.mapper;
|
||||
|
||||
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
import xyz.playedu.jc.domain.Note;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 笔记 Mapper
|
||||
*/
|
||||
public interface NoteMapper extends BaseMapper<Note> {
|
||||
List<Note> listVo(@Param("param") Note note);
|
||||
}
|
||||
|
||||
@ -0,0 +1,13 @@
|
||||
package xyz.playedu.jc.param;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class KnowledgeParam {
|
||||
//书本id
|
||||
private Integer bookId;
|
||||
//知识点名称
|
||||
private String name;
|
||||
//知识点code
|
||||
private String knowledgeCode;
|
||||
}
|
||||
@ -1,15 +1,24 @@
|
||||
package xyz.playedu.jc.service;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.extension.service.IService;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.jc.domain.Knowledge;
|
||||
import xyz.playedu.jc.param.KnowledgeParam;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识点 Service
|
||||
*/
|
||||
public interface IKnowledgeService extends IService<Knowledge> {
|
||||
List<Knowledge> listVo(KnowledgeParam param);
|
||||
|
||||
List<Knowledge> treeList(KnowledgeParam param);
|
||||
void saveOrUpdateVo(Knowledge data);
|
||||
JSONObject getByIdVo(Integer id);
|
||||
JSONObject stuGetByIdVo(Integer id);
|
||||
|
||||
|
||||
PaginationResult<Knowledge> paginate(HashMap<String, Object> params);
|
||||
}
|
||||
|
||||
@ -1,75 +1,255 @@
|
||||
package xyz.playedu.jc.service.impl;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.apache.commons.collections4.MapUtils;
|
||||
import org.checkerframework.checker.units.qual.A;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
import xyz.playedu.common.context.FCtx;
|
||||
import xyz.playedu.common.domain.User;
|
||||
import xyz.playedu.common.types.paginate.PaginationResult;
|
||||
import xyz.playedu.jc.domain.Knowledge;
|
||||
import xyz.playedu.jc.mapper.KnowledgeMapper;
|
||||
import xyz.playedu.jc.domain.*;
|
||||
import xyz.playedu.jc.mapper.*;
|
||||
import xyz.playedu.jc.param.KnowledgeParam;
|
||||
import xyz.playedu.jc.service.IKnowledgeService;
|
||||
import xyz.playedu.jc.service.ITextbookService;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 知识点 Service 实现
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class KnowledgeServiceImpl
|
||||
extends ServiceImpl<KnowledgeMapper, Knowledge>
|
||||
implements IKnowledgeService {
|
||||
public class KnowledgeServiceImpl extends ServiceImpl<KnowledgeMapper, Knowledge> implements IKnowledgeService {
|
||||
@Autowired
|
||||
private ChapterContentMapper contentMapper;
|
||||
@Autowired
|
||||
private JCResourceMapper resourceMapper;
|
||||
@Autowired
|
||||
private BookChapterMapper chapterMapper;
|
||||
@Autowired
|
||||
private NoteMapper noteMapper;
|
||||
@Autowired
|
||||
private DiscussionMapper discussionMapper;
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public PaginationResult<Knowledge> paginate(HashMap<String, Object> params) {
|
||||
try {
|
||||
Integer page = MapUtils.getInteger(params, "page", 1);
|
||||
Integer size = MapUtils.getInteger(params, "size", 10);
|
||||
|
||||
Page<Knowledge> pageParam = new Page<>(page, size);
|
||||
public List<Knowledge> listVo(KnowledgeParam param) {
|
||||
//获取知识点卡片
|
||||
LambdaQueryWrapper<Knowledge> queryWrapper = new LambdaQueryWrapper<>();
|
||||
|
||||
Integer bookId = MapUtils.getInteger(params, "bookId");
|
||||
if (bookId != null) {
|
||||
queryWrapper.eq(Knowledge::getBookId, bookId);
|
||||
queryWrapper.eq(Knowledge::getBookId, param.getBookId())
|
||||
.eq(Knowledge::getIsReal,"1").orderByAsc(Knowledge::getOrderNum);
|
||||
return list(queryWrapper);
|
||||
}
|
||||
@Override
|
||||
public JSONObject getByIdVo(Integer id) {
|
||||
JSONObject res = new JSONObject();
|
||||
Knowledge knowledge = this.getById(id);
|
||||
res.put("knowledge", knowledge);
|
||||
//获取各个板块该知识点下的资源
|
||||
LambdaQueryWrapper<ChapterContent> contentWrapper = new LambdaQueryWrapper<>();
|
||||
contentWrapper.select(ChapterContent::getId,ChapterContent::getChapterId).like(ChapterContent::getKnowledgeCode, knowledge.getKnowledgeCode()).eq(ChapterContent::getBookId, knowledge.getBookId());
|
||||
List<ChapterContent> contents = contentMapper.selectList(contentWrapper);
|
||||
for (ChapterContent content : contents) {
|
||||
BookChapter bookChapter = chapterMapper.selectById(content.getChapterId());
|
||||
content.setChapterName(bookChapter.getName());
|
||||
}
|
||||
res.put("contents", contents);
|
||||
LambdaQueryWrapper<JCResource> resourceWrapper = new LambdaQueryWrapper<>();
|
||||
resourceWrapper.like(JCResource::getKnowledgeCode, knowledge.getKnowledgeCode()).eq(JCResource::getBookId, knowledge.getBookId());
|
||||
res.put("resources", resourceMapper.selectList(resourceWrapper));
|
||||
return res;
|
||||
}
|
||||
|
||||
Integer parentId = MapUtils.getInteger(params, "parentId");
|
||||
if (parentId != null) {
|
||||
@Override
|
||||
public JSONObject stuGetByIdVo(Integer id) {
|
||||
Knowledge knowledge = this.getById(id);
|
||||
//获取当前学生信息
|
||||
User user = FCtx.getUser();
|
||||
JSONObject res = this.getByIdVo(id);
|
||||
//获取笔记信息
|
||||
Note param = new Note();
|
||||
param.setBookId(knowledge.getBookId());
|
||||
param.setKnowledgeCode(knowledge.getKnowledgeCode());
|
||||
param.setUserId(user.getId());
|
||||
List<Note> notes = noteMapper.listVo(param);
|
||||
res.put("notes", notes);
|
||||
//获取讨论信息
|
||||
Discussion discussion = new Discussion();
|
||||
discussion.setBookId(knowledge.getBookId());
|
||||
discussion.setKnowledgeCode(knowledge.getKnowledgeCode());
|
||||
discussion.setUserId(user.getId());
|
||||
List<Discussion> discussions = discussionMapper.listVo(discussion);
|
||||
res.put("discussions", discussions);
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Knowledge> treeList(KnowledgeParam param) {
|
||||
//获取全部知识点
|
||||
LambdaQueryWrapper<Knowledge> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Knowledge::getBookId, param.getBookId()).orderByAsc(Knowledge::getOrderNum);
|
||||
List<Knowledge> allKnowledges = this.list(queryWrapper);
|
||||
// 处理为树结构
|
||||
return buildTree(allKnowledges);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveOrUpdateVo(Knowledge data) {
|
||||
if (ObjectUtil.isEmpty(data.getId())){
|
||||
Knowledge knowledge = this.getById(data.getId());
|
||||
knowledge.setDesc(data.getDesc());
|
||||
knowledge.setName(data.getName());
|
||||
knowledge.setType(data.getType());
|
||||
this.updateById(knowledge);
|
||||
return;
|
||||
}
|
||||
if (ObjectUtil.isNotEmpty(data.getParentId())||data.getParentId()==0){
|
||||
data.setLevel(1);
|
||||
data.setKnowledgeCode(generateKnowledgeCode(data.getParentId()));
|
||||
this.save(data);
|
||||
}else {
|
||||
Knowledge byId = this.getById(data.getParentId());
|
||||
data.setLevel(byId.getLevel()+1);
|
||||
data.setKnowledgeCode(generateKnowledgeCode(data.getParentId()));
|
||||
this.save(data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
private List<Knowledge> buildTree(List<Knowledge> knowledges) {
|
||||
// 创建一个map来存储id到对象的映射,方便快速查找
|
||||
HashMap<Integer, Knowledge> knowledgeMap = new HashMap<>();
|
||||
for (Knowledge knowledge : knowledges) {
|
||||
knowledgeMap.put(knowledge.getId(), knowledge);
|
||||
}
|
||||
|
||||
// 存储最终的根节点
|
||||
List<Knowledge> rootNodes = new ArrayList<>();
|
||||
|
||||
for (Knowledge knowledge : knowledges) {
|
||||
Integer parentId = knowledge.getParentId();
|
||||
if (parentId == null || parentId == 0) { // 假设没有父节点的是根节点
|
||||
rootNodes.add(knowledge);
|
||||
} else {
|
||||
Knowledge parent = knowledgeMap.get(parentId);
|
||||
if (parent != null) {
|
||||
if (parent.getChildren() == null) {
|
||||
parent.setChildren(new ArrayList<>());
|
||||
}
|
||||
parent.getChildren().add(knowledge);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rootNodes;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 生成知识点编码
|
||||
* @param parentId 父节点ID,0或null代表顶级节点
|
||||
* @return 知识点编码,如A01、A01A01等
|
||||
*/
|
||||
public String generateKnowledgeCode(Integer parentId) {
|
||||
if (parentId == null || parentId == 0) {
|
||||
// 顶级节点编码生成逻辑
|
||||
// 查询当前最大的顶级节点编码
|
||||
LambdaQueryWrapper<Knowledge> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.isNull(Knowledge::getParentId).or().eq(Knowledge::getParentId, 0);
|
||||
queryWrapper.orderByDesc(Knowledge::getId);
|
||||
List<Knowledge> topKnowledges = this.list(queryWrapper);
|
||||
|
||||
if (topKnowledges.isEmpty()) {
|
||||
return "A01";
|
||||
}
|
||||
|
||||
// 获取最后一个顶级节点的编码
|
||||
String lastCode = topKnowledges.get(0).getKnowledgeCode();
|
||||
if (lastCode == null || lastCode.isEmpty()) {
|
||||
return "A01";
|
||||
}
|
||||
|
||||
// 解析并递增编码
|
||||
return incrementCode(lastCode, 3); // 顶级节点固定3位编码
|
||||
} else {
|
||||
// 子节点编码生成逻辑
|
||||
Knowledge parent = this.getById(parentId);
|
||||
if (parent == null || parent.getKnowledgeCode() == null) {
|
||||
throw new RuntimeException("父节点不存在或无编码");
|
||||
}
|
||||
|
||||
String parentCode = parent.getKnowledgeCode();
|
||||
// 查询该父节点下的所有子节点
|
||||
LambdaQueryWrapper<Knowledge> queryWrapper = new LambdaQueryWrapper<>();
|
||||
queryWrapper.eq(Knowledge::getParentId, parentId);
|
||||
queryWrapper.orderByDesc(Knowledge::getId);
|
||||
List<Knowledge> childKnowledges = this.list(queryWrapper);
|
||||
|
||||
if (childKnowledges.isEmpty()) {
|
||||
// 第一个子节点
|
||||
return parentCode + "A01";
|
||||
}
|
||||
|
||||
String name = MapUtils.getString(params, "name");
|
||||
if (name != null && !name.isEmpty()) {
|
||||
queryWrapper.like(Knowledge::getName, name);
|
||||
// 获取最后一个子节点的编码
|
||||
String lastChildCode = childKnowledges.get(0).getKnowledgeCode();
|
||||
if (lastChildCode == null || lastChildCode.length() <= parentCode.length()) {
|
||||
return parentCode + "A01";
|
||||
}
|
||||
|
||||
queryWrapper.orderByAsc(Knowledge::getOrderNum);
|
||||
// 提取子节点部分并递增
|
||||
String childPart = lastChildCode.substring(parentCode.length());
|
||||
String newChildPart = incrementCode(childPart, 3); // 子节点部分固定3位编码
|
||||
|
||||
IPage<Knowledge> pageResult = this.page(pageParam, queryWrapper);
|
||||
|
||||
Long total = pageResult.getTotal();
|
||||
PaginationResult<Knowledge> result = new PaginationResult<>();
|
||||
result.setData(pageResult.getRecords());
|
||||
result.setTotal(total);
|
||||
result.setCurrent(page);
|
||||
result.setSize(size);
|
||||
result.setPages((total + size - 1) / size);
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("分页查询知识点失败,参数:{}", params, e);
|
||||
PaginationResult<Knowledge> emptyResult = new PaginationResult<>();
|
||||
emptyResult.setData(new ArrayList<>());
|
||||
emptyResult.setTotal(0L);
|
||||
emptyResult.setCurrent(MapUtils.getInteger(params, "page", 1));
|
||||
emptyResult.setSize(MapUtils.getInteger(params, "size", 10));
|
||||
emptyResult.setPages(0L);
|
||||
return emptyResult;
|
||||
return parentCode + newChildPart;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递增编码
|
||||
* @param code 当前编码
|
||||
* @param length 编码长度
|
||||
* @return 递增后的编码
|
||||
*/
|
||||
private String incrementCode(String code, int length) {
|
||||
if (code == null || code.isEmpty()) {
|
||||
return "A01";
|
||||
}
|
||||
|
||||
// 分离字母和数字部分
|
||||
StringBuilder letters = new StringBuilder();
|
||||
StringBuilder digits = new StringBuilder();
|
||||
|
||||
for (char c : code.toCharArray()) {
|
||||
if (Character.isLetter(c)) {
|
||||
letters.append(c);
|
||||
} else if (Character.isDigit(c)) {
|
||||
digits.append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (digits.isEmpty()) {
|
||||
return "A01";
|
||||
}
|
||||
|
||||
// 递增数字部分
|
||||
int num = Integer.parseInt(digits.toString());
|
||||
num++;
|
||||
|
||||
// 格式化回固定长度
|
||||
String format = "%0" + length + "d";
|
||||
return letters.toString() + String.format(format, num);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@ -5,9 +5,34 @@
|
||||
|
||||
<mapper namespace="xyz.playedu.jc.mapper.DiscussionMapper">
|
||||
|
||||
<!--
|
||||
目前使用 MyBatis-Plus 的通用 CRUD,这里可以先留空。
|
||||
如果后续有复杂查询,可以在这里新增 <select> / <update> 等。
|
||||
-->
|
||||
<select id="listVo" resultType="xyz.playedu.jc.domain.Discussion">
|
||||
select discussion.*, chapter.name as chapterName
|
||||
from jc_discussion discussion
|
||||
inner join jc_chapter_content content on discussion.chapter_id = content.chapter_id
|
||||
inner join jc_book_chapter chapter on content.chapter_id = chapter.id
|
||||
<where>
|
||||
<if test="param.bookId != null">
|
||||
and discussion.book_id = #{param.bookId}
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
and discussion.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test="param.chapterId != null">
|
||||
and discussion.chapter_id = #{param.chapterId}
|
||||
</if>
|
||||
<if test="param.knowledgeCode != null and knowledgeCode!=''">
|
||||
and content.knowledge_code like concat('%',#{param.knowledgeCode},'%')
|
||||
</if>
|
||||
|
||||
</where>
|
||||
<choose>
|
||||
<when test="orderType == 'time'">
|
||||
order by discussion.create_time desc
|
||||
</when>
|
||||
<otherwise>
|
||||
order by chapter.level asc, chapter.sort asc
|
||||
</otherwise>
|
||||
</choose>
|
||||
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@ -4,40 +4,6 @@
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xyz.playedu.jc.mapper.KnowledgeMapper">
|
||||
|
||||
<resultMap id="KnowledgeResultMap" type="xyz.playedu.jc.domain.Knowledge">
|
||||
<id column="id" property="id"/>
|
||||
<result column="book_id" property="bookId"/>
|
||||
<result column="parent_id" property="parentId"/>
|
||||
<result column="name" property="name"/>
|
||||
<result column="konwledge_code" property="konwledgeCode"/>
|
||||
<result column="desc" property="desc"/>
|
||||
<result column="level" property="level"/>
|
||||
<result column="type" property="type"/>
|
||||
<result column="order_num" property="orderNum"/>
|
||||
<result column="extra_json" property="extraJson"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="creator" property="creator"/>
|
||||
<result column="updater" property="updater"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
</resultMap>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,
|
||||
book_id,
|
||||
parent_id,
|
||||
name,
|
||||
konwledge_code,
|
||||
`desc`,
|
||||
`level`,
|
||||
`type`,
|
||||
order_num,
|
||||
extra_json,
|
||||
create_time,
|
||||
update_time,
|
||||
creator,
|
||||
updater,
|
||||
tenant_id
|
||||
</sql>
|
||||
|
||||
</mapper>
|
||||
|
||||
@ -4,38 +4,35 @@
|
||||
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xyz.playedu.jc.mapper.NoteMapper">
|
||||
|
||||
<resultMap id="NoteResultMap" type="xyz.playedu.jc.domain.Note">
|
||||
<id column="id" property="id"/>
|
||||
<result column="book_id" property="bookId"/>
|
||||
<result column="user_id" property="userId"/>
|
||||
<result column="chapter_id" property="chapterId"/>
|
||||
<result column="content" property="content"/>
|
||||
<result column="txt" property="txt"/>
|
||||
<result column="section_id" property="sectionId"/>
|
||||
<result column="section_origin_id" property="sectionOriginId"/>
|
||||
<result column="extra_json" property="extraJson"/>
|
||||
<result column="create_time" property="createTime"/>
|
||||
<result column="update_time" property="updateTime"/>
|
||||
<result column="creator" property="creator"/>
|
||||
<result column="updater" property="updater"/>
|
||||
<result column="tenant_id" property="tenantId"/>
|
||||
</resultMap>
|
||||
<select id="listVo" resultType="xyz.playedu.jc.domain.Note">
|
||||
select note.*, chapter.name as chapterName
|
||||
from jc_note note
|
||||
inner join jc_chapter_content content on note.chapter_id = content.chapter_id
|
||||
inner join jc_book_chapter chapter on content.chapter_id = chapter.id
|
||||
<where>
|
||||
<if test="param.bookId != null">
|
||||
and note.book_id = #{param.bookId}
|
||||
</if>
|
||||
<if test="param.userId != null">
|
||||
and note.user_id = #{param.userId}
|
||||
</if>
|
||||
<if test="param.chapterId != null">
|
||||
and note.chapter_id = #{param.chapterId}
|
||||
</if>
|
||||
<if test="param.knowledgeCode != null and knowledgeCode!=''">
|
||||
and content.knowledge_code like concat('%',#{param.knowledgeCode},'%')
|
||||
</if>
|
||||
|
||||
<sql id="Base_Column_List">
|
||||
id,
|
||||
book_id,
|
||||
user_id,
|
||||
chapter_id,
|
||||
content,
|
||||
txt,
|
||||
section_id,
|
||||
section_origin_id,
|
||||
extra_json,
|
||||
create_time,
|
||||
update_time,
|
||||
creator,
|
||||
updater,
|
||||
tenant_id
|
||||
</sql>
|
||||
</where>
|
||||
<choose>
|
||||
<when test="orderType == 'time'">
|
||||
order by note.create_time desc
|
||||
</when>
|
||||
<otherwise>
|
||||
order by chapter.level asc, chapter.sort asc
|
||||
</otherwise>
|
||||
</choose>
|
||||
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user