Browse Source

增加同步知识点练习

mingfu 1 week ago
parent
commit
b78d03dbbc

+ 44 - 0
back-ui/src/api/learn/learnKnowledgeCourse.js

@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 查询同步知识点树列表
+export function listLearnKnowledgeCourse(query) {
+  return request({
+    url: '/learn/learnKnowledgeCourse/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询同步知识点树详细
+export function getLearnKnowledgeCourse(id) {
+  return request({
+    url: '/learn/learnKnowledgeCourse/' + id,
+    method: 'get'
+  })
+}
+
+// 新增同步知识点树
+export function addLearnKnowledgeCourse(data) {
+  return request({
+    url: '/learn/learnKnowledgeCourse',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改同步知识点树
+export function updateLearnKnowledgeCourse(data) {
+  return request({
+    url: '/learn/learnKnowledgeCourse',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除同步知识点树
+export function delLearnKnowledgeCourse(id) {
+  return request({
+    url: '/learn/learnKnowledgeCourse/' + id,
+    method: 'delete'
+  })
+}

+ 328 - 0
back-ui/src/views/learn/learnKnowledgeCourse/index.vue

@@ -0,0 +1,328 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="知识点名称" prop="name">
+        <el-input
+          v-model="queryParams.name"
+          placeholder="请输入知识点名称"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="父ID" prop="pid">
+        <el-input
+          v-model="queryParams.pid"
+          placeholder="请输入父ID"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="祖级列表" prop="ancestors">
+        <el-input
+          v-model="queryParams.ancestors"
+          placeholder="请输入祖级列表"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="排序" prop="sort">
+        <el-input
+          v-model="queryParams.sort"
+          placeholder="请输入排序"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="级数" prop="level">
+        <el-input
+          v-model="queryParams.level"
+          placeholder="请输入级数"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="题目数" prop="questionsCount">
+        <el-input
+          v-model="queryParams.questionsCount"
+          placeholder="请输入题目数"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="适用省份" prop="locations">
+        <el-input
+          v-model="queryParams.locations"
+          placeholder="请输入适用省份"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="适用考生类型" prop="examineeTypes">
+        <el-input
+          v-model="queryParams.examineeTypes"
+          placeholder="请输入适用考生类型"
+          clearable
+          @keyup.enter="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="Search" @click="handleQuery">搜索</el-button>
+        <el-button icon="Refresh" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="Plus"
+          @click="handleAdd"
+          v-hasPermi="['learn:learnKnowledgeCourse:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['learn:learnKnowledgeCourse:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['learn:learnKnowledgeCourse:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['learn:learnKnowledgeCourse:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="learnKnowledgeCourseList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="知识点id" align="center" prop="id" />
+      <el-table-column label="知识点名称" align="center" prop="name" />
+      <el-table-column label="父ID" align="center" prop="pid" />
+      <el-table-column label="祖级列表" align="center" prop="ancestors" />
+      <el-table-column label="排序" align="center" prop="sort" />
+      <el-table-column label="级数" align="center" prop="level" />
+      <el-table-column label="题目数" align="center" prop="questionsCount" />
+      <el-table-column label="知识点" align="center" prop="knowledges" />
+      <el-table-column label="适用省份" align="center" prop="locations" />
+      <el-table-column label="适用考生类型" align="center" prop="examineeTypes" />
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['learn:learnKnowledgeCourse:edit']">修改</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['learn:learnKnowledgeCourse:remove']">删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    
+    <pagination
+      v-show="total>0"
+      :total="total"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 添加或修改同步知识点树对话框 -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="learnKnowledgeCourseRef" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="知识点名称" prop="name">
+          <el-input v-model="form.name" placeholder="请输入知识点名称" />
+        </el-form-item>
+        <el-form-item label="父ID" prop="pid">
+          <el-input v-model="form.pid" placeholder="请输入父ID" />
+        </el-form-item>
+        <el-form-item label="排序" prop="sort">
+          <el-input v-model="form.sort" placeholder="请输入排序" />
+        </el-form-item>
+        <el-form-item label="级数" prop="level">
+          <el-input v-model="form.level" placeholder="请输入级数" />
+        </el-form-item>
+        <el-form-item label="题目数" prop="questionsCount">
+          <el-input v-model="form.questionsCount" placeholder="请输入题目数" />
+        </el-form-item>
+        <el-form-item label="知识点" prop="knowledges">
+          <el-input v-model="form.knowledges" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+        <el-form-item label="适用省份" prop="locations">
+          <el-input v-model="form.locations" placeholder="请输入适用省份" />
+        </el-form-item>
+        <el-form-item label="适用考生类型" prop="examineeTypes">
+          <el-input v-model="form.examineeTypes" placeholder="请输入适用考生类型" />
+        </el-form-item>
+      </el-form>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">确 定</el-button>
+          <el-button @click="cancel">取 消</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="LearnKnowledgeCourse">
+import { listLearnKnowledgeCourse, getLearnKnowledgeCourse, delLearnKnowledgeCourse, addLearnKnowledgeCourse, updateLearnKnowledgeCourse } from "@/api/learn/learnKnowledgeCourse"
+
+const { proxy } = getCurrentInstance()
+
+const learnKnowledgeCourseList = ref([])
+const open = ref(false)
+const loading = ref(true)
+const showSearch = ref(true)
+const ids = ref([])
+const single = ref(true)
+const multiple = ref(true)
+const total = ref(0)
+const title = ref("")
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    name: null,
+    pid: null,
+    ancestors: null,
+    sort: null,
+    level: null,
+    questionsCount: null,
+    knowledges: null,
+    locations: null,
+    examineeTypes: null
+  },
+  rules: {
+  }
+})
+
+const { queryParams, form, rules } = toRefs(data)
+
+/** 查询同步知识点树列表 */
+function getList() {
+  loading.value = true
+  listLearnKnowledgeCourse(queryParams.value).then(response => {
+    learnKnowledgeCourseList.value = response.rows
+    total.value = response.total
+    loading.value = false
+  })
+}
+
+// 取消按钮
+function cancel() {
+  open.value = false
+  reset()
+}
+
+// 表单重置
+function reset() {
+  form.value = {
+    id: null,
+    name: null,
+    pid: null,
+    ancestors: null,
+    sort: null,
+    level: null,
+    questionsCount: null,
+    knowledges: null,
+    locations: null,
+    examineeTypes: null
+  }
+  proxy.resetForm("learnKnowledgeCourseRef")
+}
+
+/** 搜索按钮操作 */
+function handleQuery() {
+  queryParams.value.pageNum = 1
+  getList()
+}
+
+/** 重置按钮操作 */
+function resetQuery() {
+  proxy.resetForm("queryRef")
+  handleQuery()
+}
+
+// 多选框选中数据
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.id)
+  single.value = selection.length != 1
+  multiple.value = !selection.length
+}
+
+/** 新增按钮操作 */
+function handleAdd() {
+  reset()
+  open.value = true
+  title.value = "添加同步知识点树"
+}
+
+/** 修改按钮操作 */
+function handleUpdate(row) {
+  reset()
+  const _id = row.id || ids.value
+  getLearnKnowledgeCourse(_id).then(response => {
+    form.value = response.data
+    open.value = true
+    title.value = "修改同步知识点树"
+  })
+}
+
+/** 提交按钮 */
+function submitForm() {
+  proxy.$refs["learnKnowledgeCourseRef"].validate(valid => {
+    if (valid) {
+      if (form.value.id != null) {
+        updateLearnKnowledgeCourse(form.value).then(response => {
+          proxy.$modal.msgSuccess("修改成功")
+          open.value = false
+          getList()
+        })
+      } else {
+        addLearnKnowledgeCourse(form.value).then(response => {
+          proxy.$modal.msgSuccess("新增成功")
+          open.value = false
+          getList()
+        })
+      }
+    }
+  })
+}
+
+/** 删除按钮操作 */
+function handleDelete(row) {
+  const _ids = row.id || ids.value
+  proxy.$modal.confirm('是否确认删除同步知识点树编号为"' + _ids + '"的数据项?').then(function() {
+    return delLearnKnowledgeCourse(_ids)
+  }).then(() => {
+    getList()
+    proxy.$modal.msgSuccess("删除成功")
+  }).catch(() => {})
+}
+
+/** 导出按钮操作 */
+function handleExport() {
+  proxy.download('learn/learnKnowledgeCourse/export', {
+    ...queryParams.value
+  }, `learnKnowledgeCourse_${new Date().getTime()}.xlsx`)
+}
+
+getList()
+</script>

+ 8 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/front/FrontPaperController.java

@@ -109,6 +109,14 @@ public class FrontPaperController {
         return AjaxResult.success(finalList);
     }
 
+    @ApiOperation("03 课程同步知识点树")
+    @GetMapping(value = "courseKnowledge")
+    public AjaxResult getCourseKnowledge() {
+        SysUser sysUser = SecurityUtils.getLoginUser().getUser();
+        List<LearnTeacherService.TreeNode> nodeList = learnTeacherService.getCourseKnowledgeTree(sysUser.getUserId());
+        return AjaxResult.success(nodeList);
+    }
+
     @ApiOperation("04 取试卷")
     @GetMapping(value = "paper")
     public AjaxResult loadPaper(@ApiParam("考卷类型PaperType") PaperType type, @ApiParam("考卷标识") Long id) {

+ 104 - 0
ie-admin/src/main/java/com/ruoyi/web/controller/learn/LearnKnowledgeCourseController.java

@@ -0,0 +1,104 @@
+package com.ruoyi.web.controller.learn;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.learn.domain.LearnKnowledgeCourse;
+import com.ruoyi.learn.service.ILearnKnowledgeCourseService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 同步知识点树Controller
+ * 
+ * @author ruoyi
+ * @date 2025-11-04
+ */
+@RestController
+@RequestMapping("/learn/learnKnowledgeCourse")
+public class LearnKnowledgeCourseController extends BaseController
+{
+    @Autowired
+    private ILearnKnowledgeCourseService learnKnowledgeCourseService;
+
+    /**
+     * 查询同步知识点树列表
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        startPage();
+        List<LearnKnowledgeCourse> list = learnKnowledgeCourseService.selectLearnKnowledgeCourseList(learnKnowledgeCourse);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出同步知识点树列表
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:export')")
+    @Log(title = "同步知识点树", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        List<LearnKnowledgeCourse> list = learnKnowledgeCourseService.selectLearnKnowledgeCourseList(learnKnowledgeCourse);
+        ExcelUtil<LearnKnowledgeCourse> util = new ExcelUtil<LearnKnowledgeCourse>(LearnKnowledgeCourse.class);
+        util.exportExcel(response, list, "同步知识点树数据");
+    }
+
+    /**
+     * 获取同步知识点树详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:query')")
+    @GetMapping(value = "/{id}")
+    public AjaxResult getInfo(@PathVariable("id") Long id)
+    {
+        return success(learnKnowledgeCourseService.selectLearnKnowledgeCourseById(id));
+    }
+
+    /**
+     * 新增同步知识点树
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:add')")
+    @Log(title = "同步知识点树", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        return toAjax(learnKnowledgeCourseService.insertLearnKnowledgeCourse(learnKnowledgeCourse));
+    }
+
+    /**
+     * 修改同步知识点树
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:edit')")
+    @Log(title = "同步知识点树", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        return toAjax(learnKnowledgeCourseService.updateLearnKnowledgeCourse(learnKnowledgeCourse));
+    }
+
+    /**
+     * 删除同步知识点树
+     */
+    @PreAuthorize("@ss.hasPermi('learn:learnKnowledgeCourse:remove')")
+    @Log(title = "同步知识点树", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{ids}")
+    public AjaxResult remove(@PathVariable Long[] ids)
+    {
+        return toAjax(learnKnowledgeCourseService.deleteLearnKnowledgeCourseByIds(ids));
+    }
+}

+ 32 - 0
ie-admin/src/main/java/com/ruoyi/web/service/CommService.java

@@ -12,6 +12,7 @@ import com.ruoyi.common.utils.StringUtils;
 import com.ruoyi.dz.domain.DzCards;
 import com.ruoyi.dz.service.IDzCardsService;
 import com.ruoyi.enums.CardTimeStatus;
+import com.ruoyi.learn.domain.LearnKnowledgeCourse;
 import com.ruoyi.learn.domain.LearnKnowledgeTree;
 import com.ruoyi.system.service.ISysConfigService;
 import org.springframework.stereotype.Service;
@@ -109,4 +110,35 @@ public class CommService {
         }
         return treeNodeList;
     }
+
+    public List<LearnTeacherService.TreeNode> buildCourseKnowledgeTree(List<LearnKnowledgeCourse> ktList, Map<Long, Integer[]> knowCountMap) {
+        List<LearnTeacherService.TreeNode> treeNodeList = Lists.newArrayList();
+        Map<Long, LearnTeacherService.TreeNode> teMap = Maps.newHashMap();
+        Integer[] counts;
+        for(LearnKnowledgeCourse kt : ktList) {
+            LearnTeacherService.TreeNode tn;
+            if(null != knowCountMap && null != (counts = knowCountMap.get(kt.getId()))) {
+                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),  counts);
+            } else {
+                tn = new LearnTeacherService.TreeNode(kt.getId(), kt.getName(),  null);
+            }
+            teMap.put(kt.getId(), tn);
+        }
+        for(LearnKnowledgeCourse kt : ktList) {
+            if(null == kt.getPid()) {
+                treeNodeList.add(teMap.get(kt.getId()));
+                continue;
+            }
+            LearnTeacherService.TreeNode parent = teMap.get(kt.getPid());
+            LearnTeacherService.TreeNode node = teMap.get(kt.getId());
+            if(null != node.getQuestionCount()) {
+                parent.setQuestionCount(parent.getQuestionCount() + node.getQuestionCount());
+                parent.setFinishedCount(parent.getFinishedCount() + node.getFinishedCount());
+                parent.setRightCount(parent.getRightCount() + node.getRightCount());
+                parent.calcRatio();
+            }
+            parent.getChildren().add(node);
+        }
+        return treeNodeList;
+    }
 }

+ 40 - 13
ie-admin/src/main/java/com/ruoyi/web/service/ExamService.java

@@ -30,6 +30,7 @@ import org.springframework.transaction.annotation.Transactional;
 import javax.validation.ValidationException;
 import java.util.*;
 import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 /**
  * 考试服务
@@ -42,6 +43,7 @@ public class ExamService {
     private final ILearnPlanService learnPlanService;
     private final LearnQuestionsMapper learnQuestionsMapper;
     private final IDzSubjectService dzSubjectService;
+    private final LearnKnowledgeCourseMapper learnKnowledgeCourseMapper;
     private Set<PaperType> paperTypeSet = Sets.newHashSet(PaperType.Real, PaperType.Custom, PaperType.Test);
     private final LearnPaperMapper paperMapper;
     private final LearnKnowledgeTreeMapper knowledgeTreeMapper;
@@ -53,7 +55,7 @@ public class ExamService {
     private final IAMarjorPlanService marjorPlanService;
     private final ISysUserService sysUserService;
 
-    public ExamService(LearnPaperMapper paperMapper, LearnKnowledgeTreeMapper knowledgeTreeMapper, LearnExamineeMapper examineeMapper, ILearnPaperService learnPaperService, PaperService paperService, IAMarjorPlanService marjorPlanService, LearnAnswerMapper learnAnswerMapper, LearnExamineeMapper learnExamineeMapper, ISysUserService sysUserService, LearnStudentMapper learnStudentMapper, ILearnPlanService learnPlanService, LearnQuestionsMapper learnQuestionsMapper, IDzSubjectService dzSubjectService, LearnWrongBookMapper wrongBookMapper, LearnWrongDetailMapper wrongDetailMapper) {
+    public ExamService(LearnPaperMapper paperMapper, LearnKnowledgeTreeMapper knowledgeTreeMapper, LearnExamineeMapper examineeMapper, ILearnPaperService learnPaperService, PaperService paperService, IAMarjorPlanService marjorPlanService, LearnAnswerMapper learnAnswerMapper, LearnExamineeMapper learnExamineeMapper, ISysUserService sysUserService, LearnStudentMapper learnStudentMapper, ILearnPlanService learnPlanService, LearnQuestionsMapper learnQuestionsMapper, IDzSubjectService dzSubjectService, LearnWrongBookMapper wrongBookMapper, LearnWrongDetailMapper wrongDetailMapper, LearnKnowledgeCourseMapper learnKnowledgeCourseMapper) {
         this.paperMapper = paperMapper;
         this.knowledgeTreeMapper = knowledgeTreeMapper;
         this.examineeMapper = examineeMapper;
@@ -69,6 +71,7 @@ public class ExamService {
         this.dzSubjectService = dzSubjectService;
         this.wrongBookMapper = wrongBookMapper;
         this.wrongDetailMapper = wrongDetailMapper;
+        this.learnKnowledgeCourseMapper = learnKnowledgeCourseMapper;
     }
 
     /**
@@ -87,7 +90,12 @@ public class ExamService {
             if(UserTypeEnum.isCard(user.getUserType()) && !UserRegStatus.Student.equals(user.getRegStatus())) {
                 throw new RuntimeException("VIP功能不可用");
             }
-            return openExaminee(relatedId, SecurityUtils.getUserId(), directed);
+            return openExamineeForPractice(relatedId, SecurityUtils.getUserId(), directed);
+        } else if(PaperType.Course.equals(paperType)) {
+            if(UserTypeEnum.isCard(user.getUserType()) && !UserRegStatus.Student.equals(user.getRegStatus())) {
+                throw new RuntimeException("VIP功能不可用");
+            }
+            return openExamineeForCourse(relatedId, SecurityUtils.getUserId(), directed);
         } else if(PaperType.Simulated.equals(paperType)) {
             SysUser exist = sysUserService.selectUserById(SecurityUtils.getUserId());
             LearnStudent ls = learnStudentMapper.selectLearnStudentByStudentId(exist.getUserId());
@@ -242,6 +250,9 @@ public class ExamService {
             if(PaperType.Practice.getVal().equals(exitExaminee.getPaperType())) {
                 learnPlanService.updateLearnPlan(exitExaminee.getStudentId());
                 calculateWrongAnswers(exitExaminee, questionMap, answersList, PaperType.Practice.name());
+            } else if(PaperType.Course.getVal().equals(exitExaminee.getPaperType())) {
+                learnPlanService.updateLearnPlan(exitExaminee.getStudentId());
+                calculateWrongAnswers(exitExaminee, questionMap, answersList, PaperType.Course.name());
             } else if(PaperType.Simulated.getVal().equals(exitExaminee.getPaperType())) {
                 calculateWrongAnswers(exitExaminee, questionMap, answersList, PaperType.Simulated.name());
             }
@@ -420,11 +431,17 @@ public class ExamService {
 
     }
 
-    /**
-     * 根据知识点生成一次性练习卷并开始做题
-     * @return
-     */
-    private AnswerSheet openExaminee(Long knowledgeId, Long studentId, Boolean directed) {
+
+    private AnswerSheet openExamineeForCourse(Long knowledgeId, Long studentId, Boolean directed) {
+        LearnKnowledgeCourse kc = learnKnowledgeCourseMapper.selectLearnKnowledgeCourseById(knowledgeId);
+        if(null == kc || StringUtils.isBlank(kc.getKnowledges())) {
+            throw new RuntimeException("无效同步知识点");
+        }
+        return openExaminee(PaperType.Course, knowledgeId, Stream.of(kc.getKnowledges().split(",")).map(Long::parseLong).collect(Collectors.toList()), studentId, false,
+                0L, kc.getName(), null, null, "") ;
+    }
+
+    private AnswerSheet openExamineeForPractice(Long knowledgeId, Long studentId, Boolean directed) {
         String directKey;
         AMarjorPlan plan = null;
         LearnStudent ls = null;
@@ -438,8 +455,18 @@ public class ExamService {
             directKey = StringUtils.trimToEmpty(ls.getDirectKey());
         }
         LearnKnowledgeTree knowledgeTree = knowledgeTreeMapper.selectLearnKnowledgeTreeById(knowledgeId);
+        return openExaminee(PaperType.Practice, knowledgeId, Lists.newArrayList(knowledgeId), studentId, directed,
+                knowledgeTree.getSubjectId(), knowledgeTree.getName(), ls, plan, directKey) ;
+    }
+
+    /**
+     * 根据知识点生成一次性练习卷并开始做题
+     * @return
+     */
+    private AnswerSheet openExaminee(PaperType paperType, Long knowledgeId, List<Long> useKnowledgeIds, Long studentId, Boolean directed,
+                                     Long subjectId, String knowledName, LearnStudent ls, AMarjorPlan plan, String directKey) {
         LearnPaper paper = new LearnPaper();
-        paper.setPaperType(PaperType.Practice.name());
+        paper.setPaperType(paperType.name());
         paper.setRelateId(knowledgeId);
         paper.setYear(Calendar.getInstance().get(Calendar.YEAR));
         paper.setStatus(PaperStatus.TmpValid.getVal());
@@ -450,7 +477,7 @@ public class ExamService {
             LearnExaminee learnExaminee = new LearnExaminee();
             learnExaminee.setStudentId(studentId);
             learnExaminee.setPaperId(existPaper.getId());
-            learnExaminee.setPaperType(PaperType.Practice.getVal());
+            learnExaminee.setPaperType(paperType.getVal());
             learnExaminee.setState(ExamineeStatus.Exam.getVal());
             List<LearnExaminee> examineeList = examineeMapper.selectLearnExamineeList(learnExaminee);
             if (CollectionUtils.isNotEmpty(examineeList) && ExamineeStatus.Exam.getVal().equals(examineeList.get(0).getState())) {
@@ -470,20 +497,20 @@ public class ExamService {
             up.setStatus(PaperStatus.Valid.getVal());
             paperMapper.updateLearnPaper(up);
         }
-        List<LearnPaperQuestion> pqList = paperService.getQuestionsByRandom(studentId,  15, knowledgeId, Arrays.stream(QuestionType.values()).map(QuestionType::getTitle).collect(Collectors.toList()));
+        List<LearnPaperQuestion> pqList = paperService.getQuestionsByRandom(studentId,  15, useKnowledgeIds, Arrays.stream(QuestionType.values()).map(QuestionType::getTitle).collect(Collectors.toList()));
         if(CollectionUtils.isEmpty(pqList)) {
             throw new RuntimeException("本知识点题已做完");
         }
         paper.setPaperSource(0);
         paper.setFenshu(0);
-        paper.setSubjectId(knowledgeTree.getSubjectId());
-        paper.setPaperName(studentId + "-" + knowledgeTree.getName() + "-" + DateUtils.format(new Date(), "yyyyMMddHHmmss"));
+        paper.setSubjectId(subjectId);
+        paper.setPaperName(studentId + "-" + knowledName + "-" + DateUtils.format(new Date(), "yyyyMMddHHmmss"));
         paper.setRelateId(knowledgeId);
         paperService.savePaper(paper, pqList);
 
         LearnExaminee learnExaminee = new LearnExaminee();
         learnExaminee.setStudentId(studentId);
-        learnExaminee.setPaperType(PaperType.Practice.getVal());
+        learnExaminee.setPaperType(paperType.getVal());
         learnExaminee.setPaperId(paper.getId());
         learnExaminee.setPaperKey(String.valueOf(knowledgeId));
         learnExaminee.setState(ExamineeStatus.Exam.getVal());

+ 36 - 1
ie-admin/src/main/java/com/ruoyi/web/service/LearnTeacherService.java

@@ -44,8 +44,9 @@ public class LearnTeacherService {
     private final CommService commService;
     private final LearnTestPaperMapper learnTestPaperMapper;
     private final LearnQuestionsMapper learnQuestionsMapper;
+    private final LearnKnowledgeCourseMapper learnKnowledgeCourseMapper;
 
-    public LearnTeacherService(DzClassesMapper dzClassesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper, LearnStudentMapper learnStudentMapper, AMarjorPlanMapper marjorPlanMapper, BBusiWishUniversitiesMapper busiWishUniversitiesMapper, LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper, PaperService paperService, CommService commService, LearnTestPaperMapper learnTestPaperMapper, LearnQuestionsMapper learnQuestionsMapper) {
+    public LearnTeacherService(DzClassesMapper dzClassesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper, LearnStudentMapper learnStudentMapper, AMarjorPlanMapper marjorPlanMapper, BBusiWishUniversitiesMapper busiWishUniversitiesMapper, LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper, PaperService paperService, CommService commService, LearnTestPaperMapper learnTestPaperMapper, LearnQuestionsMapper learnQuestionsMapper, LearnKnowledgeCourseMapper learnKnowledgeCourseMapper) {
         this.dzClassesMapper = dzClassesMapper;
         this.learnKnowledgeTreeMapper = learnKnowledgeTreeMapper;
         this.learnStudentMapper = learnStudentMapper;
@@ -56,6 +57,7 @@ public class LearnTeacherService {
         this.commService = commService;
         this.learnTestPaperMapper = learnTestPaperMapper;
         this.learnQuestionsMapper = learnQuestionsMapper;
+        this.learnKnowledgeCourseMapper = learnKnowledgeCourseMapper;
     }
 
     public List<LearnQuestions> getQuestionTypes(Long subjectId, Collection<Long> knowledgeIds) {
@@ -314,6 +316,39 @@ public class LearnTeacherService {
         return commService.buildTree(ktList, knowledgeIdSet, knowCountMap);
     }
 
+    public List<TreeNode> getCourseKnowledgeTree(Long studentId) {
+        LearnKnowledgeCourse ktCond = new LearnKnowledgeCourse();
+        List<LearnKnowledgeCourse> ktList = learnKnowledgeCourseMapper.selectLearnKnowledgeCourseList(ktCond);
+        Map<Long, Integer[]> knowCountMap = null;
+        if(NumberUtils.isPositive(studentId) && !CollectionUtils.isEmpty(ktList)) {
+            Map<Long, Set<Long>> q2coursesMap = Maps.newHashMap();
+            for(LearnKnowledgeCourse kt : ktList) {
+                if(StringUtils.isNotBlank(kt.getKnowledges())) {
+                    for(String idStr : kt.getKnowledges().split(",")) {
+                        Long id = Long.parseLong(idStr);
+                        Set<Long> courseSet = q2coursesMap.computeIfAbsent(id, k -> Sets.newHashSet());
+                        courseSet.add(kt.getId());
+                    }
+                }
+            }
+            Map cond = Maps.newHashMap();
+            cond.put("studentId", studentId);
+            cond.put("knowIds", q2coursesMap.keySet());
+            knowCountMap = Maps.newHashMap();
+            for(LearnQuestions qs : learnQuestionsMapper.statByKnowledge(cond)) {
+                for(Long qnId : q2coursesMap.get(qs.getKnowledgeId())) {
+                    Integer[] counts = knowCountMap.get(qnId);
+                    if(null == counts) {
+                        knowCountMap.put(qnId, new Integer[] { qs.getNumber().intValue(), qs.getId().intValue(), qs.getYear().intValue()} );
+                    } else {
+                        knowCountMap.put(qnId, new Integer[] { counts[0] + qs.getNumber().intValue(), counts[1] + qs.getId().intValue(), counts[2] + qs.getYear().intValue()} );
+                    }
+                }
+            }
+        }
+        return commService.buildCourseKnowledgeTree(ktList, knowCountMap);
+    }
+
     public String updateDirected(Long studentId, Long universityId, Long planId) {
         LearnStudent upStudent = new LearnStudent();
         upStudent.setStudentId(studentId);

+ 8 - 7
ie-admin/src/main/java/com/ruoyi/web/service/PaperService.java

@@ -43,8 +43,9 @@ public class PaperService {
     private final IBBusiWishUniversitiesService wishUniversitiesService;
     private final BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper;
     private final LearnKnowledgeTreeMapper learnKnowledgeTreeMapper;
+    private final LearnKnowledgeCourseMapper learnKnowledgeCourseMapper;
 
-    PaperService(LearnPaperMapper paperMapper, LearnPaperQuestionMapper paperQuestionMapper, LearnQuestionsMapper questionsMapper, ILearnQuestionsService learnQuestionsService, LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper, IBBusiWishUniversitiesService wishUniversitiesService, BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper) {
+    PaperService(LearnPaperMapper paperMapper, LearnPaperQuestionMapper paperQuestionMapper, LearnQuestionsMapper questionsMapper, ILearnQuestionsService learnQuestionsService, LearnDirectedKnowledgeMapper learnDirectedKnowledgeMapper, IBBusiWishUniversitiesService wishUniversitiesService, BBusiWishUniversitiesMapper bBusiWishUniversitiesMapper, LearnKnowledgeTreeMapper learnKnowledgeTreeMapper, LearnKnowledgeCourseMapper learnKnowledgeCourseMapper) {
         this.paperMapper = paperMapper;
         this.paperQuestionMapper = paperQuestionMapper;
         this.questionsMapper = questionsMapper;
@@ -53,10 +54,10 @@ public class PaperService {
         this.wishUniversitiesService = wishUniversitiesService;
         this.bBusiWishUniversitiesMapper = bBusiWishUniversitiesMapper;
         this.learnKnowledgeTreeMapper = learnKnowledgeTreeMapper;
+        this.learnKnowledgeCourseMapper = learnKnowledgeCourseMapper;
         // buildAllPapers(2);
-        // buildSimulatedPaper(20154L, 1001L);
-        // buildSimulatedPaper(20950L, 1001L);
         // buildSimulatedPaperForUniversity(20950L, 11L, 78L, 2);
+        // buildSimulatedPaperForUniversity(20962L, 11L, 156L, 2);
         // test2();
         // testCulture();
     }
@@ -397,8 +398,8 @@ public class PaperService {
         return pqList;
     }
 
-    public List<LearnPaperQuestion> getQuestionsByRandom(Long studentId, Integer total, Long knowledgeId, List<String> types) {
-        Map<String, KnowTypeAssign> knowTypeAssignMap = buildKnowTypeAssignMap(studentId, "1", types, Lists.newArrayList(knowledgeId), false);
+    public List<LearnPaperQuestion> getQuestionsByRandom(Long studentId, Integer total, Collection<Long> knowledgeIds, List<String> types) {
+        Map<String, KnowTypeAssign> knowTypeAssignMap = buildKnowTypeAssignMap(studentId, "1", types, knowledgeIds, false);
         List<KnowTypeAssign> knowTypeAssignList = Lists.newArrayList(knowTypeAssignMap.values());
         List<LearnPaperQuestion> pqList = Lists.newArrayList();
         Set<Long> existQuestionIdSet = Sets.newHashSet();
@@ -414,7 +415,7 @@ public class PaperService {
             if(knowTypeAssign.getExclCount() > knowTypeAssign.getExclAssign()) {
                 List<LearnQuestions> questions = typeQuestionMap.get(knowTypeAssign.getType());
                 if(null == questions) {
-                    qCond.setKnowledgeId(knowledgeId);
+                    qCond.setKnowledgeId(knowTypeAssign.getKnowId());
                     qCond.setQtpye(knowTypeAssign.getType());
                     qCond.setId(studentId);
                     qCond.setNumber(knowTypeAssign.exclCount > 500 ? (long) random.nextInt(knowTypeAssign.exclCount.intValue() - 500) :  0L);
@@ -424,7 +425,7 @@ public class PaperService {
                 }
                 if(!questions.isEmpty()) {
                     int oldSize = pqList.size();
-                    addRandomList(knowledgeId, QuestionType.of(knowTypeAssign.getType()), questions, random, total.longValue(), 1L, 1.0, existQuestionIdSet, 1, pqList);
+                    addRandomList(knowTypeAssign.getKnowId(), QuestionType.of(knowTypeAssign.getType()), questions, random, total.longValue(), 1L, 1.0, existQuestionIdSet, 1, pqList);
                     if(oldSize != pqList.size()) {
                         knowTypeAssign.exclAssign++;
                     }

+ 1 - 1
ie-system/src/main/java/com/ruoyi/enums/PaperType.java

@@ -11,7 +11,7 @@ import java.util.stream.Collectors;
 @Getter
 @AllArgsConstructor
 public enum PaperType {
-    Real(10, "真题卷"), Simulated(20, "定向模拟卷"), Test(30, "批次测试卷"), Practice(50, "知识点"),
+    Real(10, "真题卷"), Simulated(20, "定向模拟卷"), Test(30, "批次测试卷"), Course(45, "同步知识点"), Practice(50, "知识点"),
     Custom(51, "自组卷"), WrongQuestions(52, "错题"), KeyQuestions(53, "必刷题");
 
     private final Integer val;

+ 172 - 0
ie-system/src/main/java/com/ruoyi/learn/domain/LearnKnowledgeCourse.java

@@ -0,0 +1,172 @@
+package com.ruoyi.learn.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+
+/**
+ * 同步知识点树对象 learn_knowledge_course
+ * 
+ * @author ruoyi
+ * @date 2025-11-04
+ */
+public class LearnKnowledgeCourse extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 知识点id */
+    private Long id;
+
+    /** 知识点名称 */
+    @Excel(name = "知识点名称")
+    private String name;
+
+    /** 父ID */
+    @Excel(name = "父ID")
+    private Long pid;
+
+    /** 祖级列表 */
+    @Excel(name = "祖级列表")
+    private String ancestors;
+
+    /** 排序 */
+    @Excel(name = "排序")
+    private Integer sort;
+
+    /** 级数 */
+    @Excel(name = "级数")
+    private Integer level;
+
+    /** 题目数 */
+    @Excel(name = "题目数")
+    private Integer questionsCount;
+
+    /** 知识点 */
+    @Excel(name = "知识点")
+    private String knowledges;
+
+    /** 适用省份 */
+    @Excel(name = "适用省份")
+    private String locations;
+
+    /** 适用考生类型 */
+    @Excel(name = "适用考生类型")
+    private String examineeTypes;
+
+    public void setId(Long id) 
+    {
+        this.id = id;
+    }
+
+    public Long getId() 
+    {
+        return id;
+    }
+
+    public void setName(String name) 
+    {
+        this.name = name;
+    }
+
+    public String getName() 
+    {
+        return name;
+    }
+
+    public void setPid(Long pid) 
+    {
+        this.pid = pid;
+    }
+
+    public Long getPid() 
+    {
+        return pid;
+    }
+
+    public void setAncestors(String ancestors) 
+    {
+        this.ancestors = ancestors;
+    }
+
+    public String getAncestors() 
+    {
+        return ancestors;
+    }
+
+    public void setSort(Integer sort) 
+    {
+        this.sort = sort;
+    }
+
+    public Integer getSort() 
+    {
+        return sort;
+    }
+
+    public void setLevel(Integer level) 
+    {
+        this.level = level;
+    }
+
+    public Integer getLevel() 
+    {
+        return level;
+    }
+
+    public void setQuestionsCount(Integer questionsCount) 
+    {
+        this.questionsCount = questionsCount;
+    }
+
+    public Integer getQuestionsCount() 
+    {
+        return questionsCount;
+    }
+
+    public void setKnowledges(String knowledges) 
+    {
+        this.knowledges = knowledges;
+    }
+
+    public String getKnowledges() 
+    {
+        return knowledges;
+    }
+
+    public void setLocations(String locations) 
+    {
+        this.locations = locations;
+    }
+
+    public String getLocations() 
+    {
+        return locations;
+    }
+
+    public void setExamineeTypes(String examineeTypes) 
+    {
+        this.examineeTypes = examineeTypes;
+    }
+
+    public String getExamineeTypes() 
+    {
+        return examineeTypes;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("id", getId())
+            .append("name", getName())
+            .append("pid", getPid())
+            .append("ancestors", getAncestors())
+            .append("sort", getSort())
+            .append("level", getLevel())
+            .append("questionsCount", getQuestionsCount())
+            .append("knowledges", getKnowledges())
+            .append("locations", getLocations())
+            .append("examineeTypes", getExamineeTypes())
+            .toString();
+    }
+}

+ 3 - 1
ie-system/src/main/java/com/ruoyi/learn/domain/TestPaperVO.java

@@ -122,8 +122,10 @@ public class TestPaperVO {
                 JSONArray knowledgeList = obj.getJSONArray("knowledges");
                 if (null != knowledgeList && knowledgeList.size() > 0) {
                     ktd.setKnowledges(knowledgeList.stream().map(t -> Long.parseLong(t.toString())).collect(Collectors.toList()));
+                } else if(StringUtils.isBlank(knowledges)) {
+                    return;
                 } else {
-                    ktd.setKnowledges(Stream.of(knowledges.split(",")).map(Long::parseLong).collect(Collectors.toList()));
+                    ktd.setKnowledges(Stream.of(StringUtils.trimToEmpty(knowledges).split(",")).map(Long::parseLong).collect(Collectors.toList()));
                 }
                 JSONObject typeObj = obj.getJSONObject("types");
                 List<TypeDef2> subTypes = Lists.newArrayList();

+ 61 - 0
ie-system/src/main/java/com/ruoyi/learn/mapper/LearnKnowledgeCourseMapper.java

@@ -0,0 +1,61 @@
+package com.ruoyi.learn.mapper;
+
+import java.util.List;
+import com.ruoyi.learn.domain.LearnKnowledgeCourse;
+
+/**
+ * 同步知识点树Mapper接口
+ * 
+ * @author ruoyi
+ * @date 2025-11-04
+ */
+public interface LearnKnowledgeCourseMapper 
+{
+    /**
+     * 查询同步知识点树
+     * 
+     * @param id 同步知识点树主键
+     * @return 同步知识点树
+     */
+    public LearnKnowledgeCourse selectLearnKnowledgeCourseById(Long id);
+
+    /**
+     * 查询同步知识点树列表
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 同步知识点树集合
+     */
+    public List<LearnKnowledgeCourse> selectLearnKnowledgeCourseList(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 新增同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    public int insertLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 修改同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    public int updateLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 删除同步知识点树
+     * 
+     * @param id 同步知识点树主键
+     * @return 结果
+     */
+    public int deleteLearnKnowledgeCourseById(Long id);
+
+    /**
+     * 批量删除同步知识点树
+     * 
+     * @param ids 需要删除的数据主键集合
+     * @return 结果
+     */
+    public int deleteLearnKnowledgeCourseByIds(Long[] ids);
+}

+ 61 - 0
ie-system/src/main/java/com/ruoyi/learn/service/ILearnKnowledgeCourseService.java

@@ -0,0 +1,61 @@
+package com.ruoyi.learn.service;
+
+import java.util.List;
+import com.ruoyi.learn.domain.LearnKnowledgeCourse;
+
+/**
+ * 同步知识点树Service接口
+ * 
+ * @author ruoyi
+ * @date 2025-11-04
+ */
+public interface ILearnKnowledgeCourseService 
+{
+    /**
+     * 查询同步知识点树
+     * 
+     * @param id 同步知识点树主键
+     * @return 同步知识点树
+     */
+    public LearnKnowledgeCourse selectLearnKnowledgeCourseById(Long id);
+
+    /**
+     * 查询同步知识点树列表
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 同步知识点树集合
+     */
+    public List<LearnKnowledgeCourse> selectLearnKnowledgeCourseList(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 新增同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    public int insertLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 修改同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    public int updateLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse);
+
+    /**
+     * 批量删除同步知识点树
+     * 
+     * @param ids 需要删除的同步知识点树主键集合
+     * @return 结果
+     */
+    public int deleteLearnKnowledgeCourseByIds(Long[] ids);
+
+    /**
+     * 删除同步知识点树信息
+     * 
+     * @param id 同步知识点树主键
+     * @return 结果
+     */
+    public int deleteLearnKnowledgeCourseById(Long id);
+}

+ 93 - 0
ie-system/src/main/java/com/ruoyi/learn/service/impl/LearnKnowledgeCourseServiceImpl.java

@@ -0,0 +1,93 @@
+package com.ruoyi.learn.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.learn.mapper.LearnKnowledgeCourseMapper;
+import com.ruoyi.learn.domain.LearnKnowledgeCourse;
+import com.ruoyi.learn.service.ILearnKnowledgeCourseService;
+
+/**
+ * 同步知识点树Service业务层处理
+ * 
+ * @author ruoyi
+ * @date 2025-11-04
+ */
+@Service
+public class LearnKnowledgeCourseServiceImpl implements ILearnKnowledgeCourseService 
+{
+    @Autowired
+    private LearnKnowledgeCourseMapper learnKnowledgeCourseMapper;
+
+    /**
+     * 查询同步知识点树
+     * 
+     * @param id 同步知识点树主键
+     * @return 同步知识点树
+     */
+    @Override
+    public LearnKnowledgeCourse selectLearnKnowledgeCourseById(Long id)
+    {
+        return learnKnowledgeCourseMapper.selectLearnKnowledgeCourseById(id);
+    }
+
+    /**
+     * 查询同步知识点树列表
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 同步知识点树
+     */
+    @Override
+    public List<LearnKnowledgeCourse> selectLearnKnowledgeCourseList(LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        return learnKnowledgeCourseMapper.selectLearnKnowledgeCourseList(learnKnowledgeCourse);
+    }
+
+    /**
+     * 新增同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    @Override
+    public int insertLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        return learnKnowledgeCourseMapper.insertLearnKnowledgeCourse(learnKnowledgeCourse);
+    }
+
+    /**
+     * 修改同步知识点树
+     * 
+     * @param learnKnowledgeCourse 同步知识点树
+     * @return 结果
+     */
+    @Override
+    public int updateLearnKnowledgeCourse(LearnKnowledgeCourse learnKnowledgeCourse)
+    {
+        return learnKnowledgeCourseMapper.updateLearnKnowledgeCourse(learnKnowledgeCourse);
+    }
+
+    /**
+     * 批量删除同步知识点树
+     * 
+     * @param ids 需要删除的同步知识点树主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLearnKnowledgeCourseByIds(Long[] ids)
+    {
+        return learnKnowledgeCourseMapper.deleteLearnKnowledgeCourseByIds(ids);
+    }
+
+    /**
+     * 删除同步知识点树信息
+     * 
+     * @param id 同步知识点树主键
+     * @return 结果
+     */
+    @Override
+    public int deleteLearnKnowledgeCourseById(Long id)
+    {
+        return learnKnowledgeCourseMapper.deleteLearnKnowledgeCourseById(id);
+    }
+}

+ 96 - 0
ie-system/src/main/resources/mapper/learn/LearnKnowledgeCourseMapper.xml

@@ -0,0 +1,96 @@
+<?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="com.ruoyi.learn.mapper.LearnKnowledgeCourseMapper">
+    
+    <resultMap type="LearnKnowledgeCourse" id="LearnKnowledgeCourseResult">
+        <result property="id"    column="id"    />
+        <result property="name"    column="name"    />
+        <result property="pid"    column="pid"    />
+        <result property="ancestors"    column="ancestors"    />
+        <result property="sort"    column="sort"    />
+        <result property="level"    column="level"    />
+        <result property="questionsCount"    column="questionsCount"    />
+        <result property="knowledges"    column="knowledges"    />
+        <result property="locations"    column="locations"    />
+        <result property="examineeTypes"    column="examineeTypes"    />
+    </resultMap>
+
+    <sql id="selectLearnKnowledgeCourseVo">
+        select id, name, pid, ancestors, sort, level, questionsCount, knowledges, locations, examineeTypes from learn_knowledge_course
+    </sql>
+
+    <select id="selectLearnKnowledgeCourseList" parameterType="LearnKnowledgeCourse" resultMap="LearnKnowledgeCourseResult">
+        <include refid="selectLearnKnowledgeCourseVo"/>
+        <where>  
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="pid != null "> and pid = #{pid}</if>
+            <if test="ancestors != null  and ancestors != ''"> and ancestors = #{ancestors}</if>
+            <if test="sort != null "> and sort = #{sort}</if>
+            <if test="level != null "> and level = #{level}</if>
+            <if test="questionsCount != null "> and questionsCount = #{questionsCount}</if>
+            <if test="knowledges != null  and knowledges != ''"> and knowledges = #{knowledges}</if>
+            <if test="locations != null  and locations != ''"> and locations = #{locations}</if>
+            <if test="examineeTypes != null  and examineeTypes != ''"> and examineeTypes = #{examineeTypes}</if>
+        </where>
+    </select>
+    
+    <select id="selectLearnKnowledgeCourseById" parameterType="Long" resultMap="LearnKnowledgeCourseResult">
+        <include refid="selectLearnKnowledgeCourseVo"/>
+        where id = #{id}
+    </select>
+
+    <insert id="insertLearnKnowledgeCourse" parameterType="LearnKnowledgeCourse" useGeneratedKeys="true" keyProperty="id">
+        insert into learn_knowledge_course
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null">name,</if>
+            <if test="pid != null">pid,</if>
+            <if test="ancestors != null">ancestors,</if>
+            <if test="sort != null">sort,</if>
+            <if test="level != null">level,</if>
+            <if test="questionsCount != null">questionsCount,</if>
+            <if test="knowledges != null">knowledges,</if>
+            <if test="locations != null">locations,</if>
+            <if test="examineeTypes != null">examineeTypes,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null">#{name},</if>
+            <if test="pid != null">#{pid},</if>
+            <if test="ancestors != null">#{ancestors},</if>
+            <if test="sort != null">#{sort},</if>
+            <if test="level != null">#{level},</if>
+            <if test="questionsCount != null">#{questionsCount},</if>
+            <if test="knowledges != null">#{knowledges},</if>
+            <if test="locations != null">#{locations},</if>
+            <if test="examineeTypes != null">#{examineeTypes},</if>
+         </trim>
+    </insert>
+
+    <update id="updateLearnKnowledgeCourse" parameterType="LearnKnowledgeCourse">
+        update learn_knowledge_course
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="name != null">name = #{name},</if>
+            <if test="pid != null">pid = #{pid},</if>
+            <if test="ancestors != null">ancestors = #{ancestors},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="level != null">level = #{level},</if>
+            <if test="questionsCount != null">questionsCount = #{questionsCount},</if>
+            <if test="knowledges != null">knowledges = #{knowledges},</if>
+            <if test="locations != null">locations = #{locations},</if>
+            <if test="examineeTypes != null">examineeTypes = #{examineeTypes},</if>
+        </trim>
+        where id = #{id}
+    </update>
+
+    <delete id="deleteLearnKnowledgeCourseById" parameterType="Long">
+        delete from learn_knowledge_course where id = #{id}
+    </delete>
+
+    <delete id="deleteLearnKnowledgeCourseByIds" parameterType="String">
+        delete from learn_knowledge_course where id in 
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+</mapper>