Explorar el Código

初步实现知识模块

201250038 hace 2 años
padre
commit
ffefe45335
Se han modificado 14 ficheros con 689 adiciones y 263 borrados
  1. 23 0
      seecoder-bok-common/src/main/java/cn/seecoder/bok/common/KnowledgeStatus.java
  2. 58 135
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/domain/Knowledge.java
  3. 147 0
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/domain/KnowledgePoint.java
  4. 4 4
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/mapper/KnowledgeMapper.java
  5. 19 0
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/repository/KnowledgePointRepository.java
  6. 7 17
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/repository/KnowledgeRepository.java
  7. 32 0
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/KnowledgePointService.java
  8. 208 25
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/KnowledgeService.java
  9. 30 34
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/QuestionService.java
  10. 43 5
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/StatisticService.java
  11. 2 2
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/UserInteractionService.java
  12. 75 38
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/KnowledgeController.java
  13. 38 0
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/KnowledgePointController.java
  14. 3 3
      seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/StatisticController.java

+ 23 - 0
seecoder-bok-common/src/main/java/cn/seecoder/bok/common/KnowledgeStatus.java

@@ -0,0 +1,23 @@
+package cn.seecoder.bok.common;
+
+import com.fasterxml.jackson.annotation.JsonValue;
+
+public enum KnowledgeStatus {
+    APPROVED("APPROVED"),
+    CREATING("CREATING"),
+    UPDATING("UPDATING"),
+    DELETING("DELETING"),
+    REFUSED("REFUSED"),
+    DELETED("DELETED");
+
+    private final String name;
+
+    KnowledgeStatus(String name) {
+        this.name = name;
+    }
+
+    @JsonValue
+    public String getName() {
+        return name;
+    }
+}

+ 58 - 135
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/domain/Knowledge.java

@@ -1,135 +1,58 @@
-package cn.seecoder.seecoderbokserver.domain;
-
-import javax.persistence.Column;
-import javax.persistence.Entity;
-import javax.persistence.Id;
-import javax.persistence.Table;
-
-/**
- * @author: Leonezhurui
- * @Date: 2021/8/30 - 9:16 上午
- * @Package: SEEC-BOK
- *
- * 知识点
- */
-
-@Entity
-@Table(name = "knowledge")
-public class Knowledge {
-    @Id
-    private int id;
-
-    @Column(name = "name", nullable = false)
-    private String name;
-
-    @Column(name = "name_eng", nullable = false)
-    private String nameEng;
-
-    /**
-     * 缩写
-     */
-    @Column(name = "abbreviation", nullable = false)
-    private String abbreviation;
-
-    @Column(name = "parent_id", nullable = false)
-    private int parentId;
-
-    @Column(name = "parent_name", nullable = false)
-    private String parentName;
-
-    @Column(name = "uid", nullable = false)
-    private int uid;
-
-    @Column(name = "pid", nullable = false)
-    private int pid;
-
-    @Column(name = "isleaf", nullable = false)
-    private int isleaf;
-
-    @Override
-    public String toString() {
-        return "Knowledge{" +
-                "id=" + id +
-                ", name='" + name + '\'' +
-                ", nameEng='" + nameEng + '\'' +
-                ", abbreviation='" + abbreviation + '\'' +
-                ", parentId=" + parentId +
-                ", parentName='" + parentName + '\'' +
-                ", uid=" + uid +
-                ", pid=" + pid +
-                ", isleaf=" + isleaf +
-                '}';
-    }
-
-    public int getId() {
-        return id;
-    }
-
-    public void setId(int id) {
-        this.id = id;
-    }
-
-    public String getName() {
-        return name;
-    }
-
-    public void setName(String name) {
-        this.name = name;
-    }
-
-    public String getNameEng() {
-        return nameEng;
-    }
-
-    public void setNameEng(String nameEng) {
-        this.nameEng = nameEng;
-    }
-
-    public String getAbbreviation() {
-        return abbreviation;
-    }
-
-    public void setAbbreviation(String abbreviation) {
-        this.abbreviation = abbreviation;
-    }
-
-    public int getParentId() {
-        return parentId;
-    }
-
-    public void setParentId(int parentId) {
-        this.parentId = parentId;
-    }
-
-    public String getParentName() {
-        return parentName;
-    }
-
-    public void setParentName(String parentName) {
-        this.parentName = parentName;
-    }
-
-    public int getUid() {
-        return uid;
-    }
-
-    public void setUid(int uid) {
-        this.uid = uid;
-    }
-
-    public int getPid() {
-        return pid;
-    }
-
-    public void setPid(int pid) {
-        this.pid = pid;
-    }
-
-    public int getIsleaf() {
-        return isleaf;
-    }
-
-    public void setIsleaf(int isleaf) {
-        this.isleaf = isleaf;
-    }
-}
+package cn.seecoder.seecoderbokserver.domain;
+
+import lombok.Data;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.annotation.TypeAlias;
+import org.springframework.data.elasticsearch.annotations.Document;
+import org.springframework.data.elasticsearch.annotations.Field;
+import org.springframework.data.elasticsearch.annotations.FieldType;
+
+import java.util.List;
+
+@Data
+@Document(indexName = "knowledge")
+@TypeAlias("knowledge")
+public class Knowledge {
+    @Id
+    @Field(name = "uuid", type = FieldType.Keyword)
+    private String uuid;
+
+    @Field(name = "type", type = FieldType.Keyword)
+    private String type;
+
+    @Field(name = "status", type = FieldType.Keyword)
+    private String status;
+
+    @Field(name = "id", type = FieldType.Keyword)
+    private String id;
+
+    @Field(name = "title", type = FieldType.Text)
+    private String title;
+
+    @Field(name = "abstract", type = FieldType.Text)
+    private String abstractContent;
+
+    @Field(name = "author", type = FieldType.Text)
+    private String author;
+
+    @Field(name = "journal", type = FieldType.Text)
+    private String journal;
+
+    @Field(name = "publisher", type = FieldType.Text)
+    private String publisher;
+
+    @Field(name = "year", type = FieldType.Integer)
+    private String year;
+
+    @Field(name = "organization", type = FieldType.Text)
+    private String organization;
+
+    @Field(name = "link", type = FieldType.Text)
+    private String link;
+
+    @Field(name = "knowledge_point", type = FieldType.Text)
+    private List<String> knowledgePoint;
+
+    @Field(name = "old_uuid", type = FieldType.Keyword)
+    private String oldUuid;
+}

+ 147 - 0
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/domain/KnowledgePoint.java

@@ -0,0 +1,147 @@
+package cn.seecoder.seecoderbokserver.domain;
+
+import javax.persistence.Column;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.persistence.Table;
+
+/**
+ * @author: Leonezhurui
+ * @Date: 2021/8/30 - 9:16 上午
+ * @Package: SEEC-BOK
+ *
+ * 知识点
+ */
+
+@Entity
+@Table(name = "knowledge")
+public class KnowledgePoint {
+    @Id
+    private int id;
+
+    @Column(name = "name", nullable = false)
+    private String name;
+
+    @Column(name = "name_eng", nullable = false)
+    private String nameEng;
+
+    /**
+     * 缩写
+     */
+    @Column(name = "abbreviation", nullable = false)
+    private String abbreviation;
+
+    @Column(name = "parent_id", nullable = false)
+    private int parentId;
+
+    @Column(name = "parent_name", nullable = false)
+    private String parentName;
+
+    @Column(name = "uid", nullable = false)
+    private int uid;
+
+    @Column(name = "pid", nullable = false)
+    private int pid;
+
+    @Column(name = "isleaf", nullable = false)
+    private int isleaf;
+
+    @Column(name = "grasp", nullable = false)
+    private int grasp;
+
+    @Override
+    public String toString() {
+        return "Knowledge{" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ", nameEng='" + nameEng + '\'' +
+                ", abbreviation='" + abbreviation + '\'' +
+                ", parentId=" + parentId +
+                ", parentName='" + parentName + '\'' +
+                ", uid=" + uid +
+                ", pid=" + pid +
+                ", isleaf=" + isleaf +
+                ", grasp=" + grasp +
+                '}';
+    }
+
+    public int getId() {
+        return id;
+    }
+
+    public void setId(int id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getNameEng() {
+        return nameEng;
+    }
+
+    public void setNameEng(String nameEng) {
+        this.nameEng = nameEng;
+    }
+
+    public String getAbbreviation() {
+        return abbreviation;
+    }
+
+    public void setAbbreviation(String abbreviation) {
+        this.abbreviation = abbreviation;
+    }
+
+    public int getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(int parentId) {
+        this.parentId = parentId;
+    }
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public int getGrasp() {
+        return grasp;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public int getUid() {
+        return uid;
+    }
+
+    public void setUid(int uid) {
+        this.uid = uid;
+    }
+
+    public int getPid() {
+        return pid;
+    }
+
+    public void setPid(int pid) {
+        this.pid = pid;
+    }
+
+    public int getIsleaf() {
+        return isleaf;
+    }
+
+    public void setIsleaf(int isleaf) {
+        this.isleaf = isleaf;
+    }
+
+    public void setGrasp(int grasp) {
+        this.grasp = grasp;
+    }
+}

+ 4 - 4
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/mapper/KnowledgeMapper.java

@@ -1,7 +1,7 @@
 package cn.seecoder.seecoderbokserver.mapper;
 
 import cn.seecoder.bok.common.vo.KnowledgeNodeVO;
-import cn.seecoder.seecoderbokserver.domain.Knowledge;
+import cn.seecoder.seecoderbokserver.domain.KnowledgePoint;
 import org.mapstruct.Mapper;
 
 /**
@@ -13,16 +13,16 @@ import org.mapstruct.Mapper;
 public interface KnowledgeMapper {
     /**
      * domain -> vo
-     * @param knowledge
+     * @param knowledgePoint
      * @return KnowledgeNodeVO
      */
-    KnowledgeNodeVO knowledgeToKnowledgeNodeVO(Knowledge knowledge);
+    KnowledgeNodeVO knowledgeToKnowledgeNodeVO(KnowledgePoint knowledgePoint);
 
     /**
      * vo -> domain
      * @param knowledgeNodeVO
      * @return Knowledge
      */
-    Knowledge knowledgeNodeVOToKnowledge(KnowledgeNodeVO knowledgeNodeVO);
+    KnowledgePoint knowledgeNodeVOToKnowledge(KnowledgeNodeVO knowledgeNodeVO);
 
 }

+ 19 - 0
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/repository/KnowledgePointRepository.java

@@ -0,0 +1,19 @@
+package cn.seecoder.seecoderbokserver.repository;
+
+import cn.seecoder.seecoderbokserver.domain.KnowledgePoint;
+import org.springframework.data.jpa.repository.JpaRepository;
+import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
+
+import java.util.List;
+
+/**
+ * @author: Leonezhurui
+ * @Date: 2021/8/30 - 9:37 上午
+ * @Package: SEEC-BOK
+ */
+
+public interface KnowledgePointRepository extends JpaRepository<KnowledgePoint, Integer>, JpaSpecificationExecutor<KnowledgePoint> {
+    List<KnowledgePoint> findByAbbreviationLike(String keyPoints);
+
+    KnowledgePoint findByAbbreviation(String knowledgeAbbr);
+}

+ 7 - 17
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/repository/KnowledgeRepository.java

@@ -1,17 +1,7 @@
-package cn.seecoder.seecoderbokserver.repository;
-
-import cn.seecoder.seecoderbokserver.domain.Knowledge;
-import org.springframework.data.jpa.repository.JpaRepository;
-import org.springframework.data.jpa.repository.JpaSpecificationExecutor;
-
-import java.util.List;
-
-/**
- * @author: Leonezhurui
- * @Date: 2021/8/30 - 9:37 上午
- * @Package: SEEC-BOK
- */
-
-public interface KnowledgeRepository extends JpaRepository<Knowledge, Integer>, JpaSpecificationExecutor<Knowledge> {
-    List<Knowledge> findByAbbreviationLike(String keyPoints);
-}
+package cn.seecoder.seecoderbokserver.repository;
+
+import cn.seecoder.seecoderbokserver.domain.Knowledge;
+import org.springframework.data.elasticsearch.repository.ElasticsearchRepository;
+
+public interface KnowledgeRepository extends ElasticsearchRepository<Knowledge, String> {
+}

+ 32 - 0
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/KnowledgePointService.java

@@ -0,0 +1,32 @@
+package cn.seecoder.seecoderbokserver.service;
+
+import cn.seecoder.seecoderbokserver.domain.KnowledgePoint;
+import cn.seecoder.seecoderbokserver.repository.KnowledgePointRepository;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author: Leonezhurui
+ * @Date: 2021/8/30 - 9:42 上午
+ * @Package: SEEC-BOK
+ */
+
+@Service
+public class KnowledgePointService {
+    private final KnowledgePointRepository knowledgePointRepository;
+
+    public KnowledgePointService(KnowledgePointRepository knowledgePointRepository) {this.knowledgePointRepository = knowledgePointRepository;}
+
+    public List<KnowledgePoint> findByAbbreviationLike(String keyPoints) {
+        return knowledgePointRepository.findByAbbreviationLike("%" + keyPoints + "%");
+    }
+
+    public void updateGrasp(String knowledgeAbbr, int grasp) {
+        KnowledgePoint knowledgePoint = knowledgePointRepository.findByAbbreviation(knowledgeAbbr);
+        if (knowledgePoint != null) {
+            knowledgePoint.setGrasp(grasp);
+            knowledgePointRepository.save(knowledgePoint);
+        }
+    }
+}

+ 208 - 25
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/KnowledgeService.java

@@ -1,25 +1,208 @@
-package cn.seecoder.seecoderbokserver.service;
-
-import cn.seecoder.bok.common.vo.KnowledgeNodeVO;
-import cn.seecoder.seecoderbokserver.domain.Knowledge;
-import cn.seecoder.seecoderbokserver.repository.KnowledgeRepository;
-import org.springframework.stereotype.Service;
-
-import java.util.List;
-
-/**
- * @author: Leonezhurui
- * @Date: 2021/8/30 - 9:42 上午
- * @Package: SEEC-BOK
- */
-
-@Service
-public class KnowledgeService {
-    private final KnowledgeRepository knowledgeRepository;
-
-    public KnowledgeService(KnowledgeRepository knowledgeRepository) {this.knowledgeRepository = knowledgeRepository;}
-
-    public List<Knowledge> findByAbbreviationLike(String keyPoints){
-        return knowledgeRepository.findByAbbreviationLike("%"+keyPoints+"%");
-    }
-}
+package cn.seecoder.seecoderbokserver.service;
+
+import cn.seecoder.bok.common.KnowledgeStatus;
+import cn.seecoder.seecoderbokserver.domain.Knowledge;
+import cn.seecoder.seecoderbokserver.repository.KnowledgeRepository;
+import cn.seecoder.seecoderbokserver.utility.EmptyCheck;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.elasticsearch.core.ElasticsearchOperations;
+import org.springframework.data.elasticsearch.core.SearchHit;
+import org.springframework.data.elasticsearch.core.SearchHits;
+import org.springframework.data.elasticsearch.core.query.Criteria;
+import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
+import org.springframework.data.elasticsearch.core.query.Query;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+import java.util.UUID;
+import java.util.stream.Collectors;
+
+@Service
+public class KnowledgeService {
+
+    private final KnowledgeRepository knowledgeRepository;
+
+    private final ElasticsearchOperations elasticsearchOperations;
+
+    public KnowledgeService(KnowledgeRepository knowledgeRepository, ElasticsearchOperations elasticsearchOperations) {
+        this.knowledgeRepository = knowledgeRepository;
+        this.elasticsearchOperations = elasticsearchOperations;
+    }
+
+    /**
+     * 创建知识。将知识状态设置为CREATING
+     *
+     * @param knowledge 知识
+     * @return 创建的知识
+     */
+    public Knowledge create(Knowledge knowledge) {
+        knowledge.setStatus(KnowledgeStatus.CREATING.getName());
+        knowledge.setUuid(UUID.randomUUID().toString());
+        return knowledgeRepository.save(knowledge);
+    }
+
+    /**
+     * 根据uuid删除知识。将知识状态设置为DELETING
+     *
+     * @param uuid 知识uuid
+     * @return 是否删除成功
+     */
+    public boolean delete(String uuid) {
+        Knowledge knowledge = this.findByUUID(uuid);
+        if (knowledge != null) {
+            knowledge.setStatus(KnowledgeStatus.DELETING.getName());
+            knowledgeRepository.save(knowledge);
+            return true;
+        } else {
+            return false;
+        }
+    }
+
+    /**
+     * 更新知识。将旧知识状态设置为DELETING,新知识状态设置为UPDATING
+     *
+     * @param knowledge 新知识
+     * @return 更新后的知识
+     */
+    public Knowledge update(Knowledge knowledge) {
+        Knowledge oldKnowledge = knowledgeRepository.findById(knowledge.getOldUuid()).orElse(null);
+        if (oldKnowledge != null) {
+            oldKnowledge.setStatus(KnowledgeStatus.DELETING.getName());
+            knowledgeRepository.save(oldKnowledge);
+        }
+        knowledge.setUuid(UUID.randomUUID().toString());
+        knowledge.setStatus(KnowledgeStatus.UPDATING.getName());
+        return knowledgeRepository.save(knowledge);
+    }
+
+    /**
+     * 审批知识。
+     *
+     * @param uuid 知识uuid
+     * @return 是否审批成功
+     */
+    public boolean approve(String uuid) {
+        Knowledge knowledge = knowledgeRepository.findById(uuid).orElse(null);
+        if (knowledge == null) {
+            return false;
+        }
+        KnowledgeStatus oldStatus = KnowledgeStatus.valueOf(knowledge.getStatus());
+        switch (oldStatus) {
+            case CREATING:
+                knowledge.setStatus(KnowledgeStatus.APPROVED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+            case DELETING:
+                knowledge.setStatus(KnowledgeStatus.DELETED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+            case UPDATING:
+                approve(knowledge.getOldUuid());
+                knowledge.setStatus(KnowledgeStatus.APPROVED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+        }
+        return false;
+    }
+
+    /**
+     * 拒绝知识。
+     *
+     * @param uuid 知识uuid
+     * @return 是否拒绝成功
+     */
+    public boolean refuse(String uuid) {
+        Knowledge knowledge = knowledgeRepository.findById(uuid).orElse(null);
+        if (knowledge == null) {
+            return false;
+        }
+        KnowledgeStatus oldStatus = KnowledgeStatus.valueOf(knowledge.getStatus());
+        switch (oldStatus) {
+            case CREATING:
+                knowledge.setStatus(KnowledgeStatus.REFUSED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+            case DELETING:
+                knowledge.setStatus(KnowledgeStatus.APPROVED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+            case UPDATING:
+                refuse(knowledge.getOldUuid());
+                knowledge.setStatus(KnowledgeStatus.REFUSED.getName());
+                knowledgeRepository.save(knowledge);
+                return true;
+        }
+        return false;
+    }
+
+    public Iterable<Knowledge> saveAll(Iterable<Knowledge> knowledges) {
+        return knowledgeRepository.saveAll(knowledges);
+    }
+
+    /**
+     * 查找未审批的知识
+     *
+     * @param pageable 分页信息
+     * @param status   知识状态
+     * @return 未审批的知识
+     */
+    public Page<Knowledge> findUnChecked(Pageable pageable, KnowledgeStatus status) {
+        Criteria criteria = new Criteria();
+        if (!EmptyCheck.instance.isEmpty(status.getName())) {
+            criteria = criteria.and("status").matches(status);
+        }
+        return findByCriteria(pageable, criteria);
+    }
+
+    /**
+     * 查找知识
+     *
+     * @param keyword        关键字
+     * @param knowledgePoint 知识点
+     * @param pageable       分页信息
+     * @return 知识
+     */
+    public Page<Knowledge> find(String keyword, List<String> knowledgePoint, Pageable pageable) {
+        Criteria criteria = new Criteria();
+        if (!EmptyCheck.instance.isEmpty(keyword)) {
+            criteria = criteria.and("abstract").matches(keyword)
+                    .or("title").matches(keyword);
+        }
+        if (!EmptyCheck.instance.isEmpty(knowledgePoint)) {
+            criteria = criteria.and("knowledge_point").matchesAll(knowledgePoint);
+        }
+        return findByCriteria(pageable, criteria);
+    }
+
+    /**
+     * 根据uuid查找知识
+     *
+     * @param uuid 知识uuid
+     * @return 知识
+     */
+    public Knowledge findByUUID(String uuid) {
+        return knowledgeRepository.findById(uuid).orElse(null);
+    }
+
+
+    /**
+     * 根据条件查找知识
+     *
+     * @param pageable 分页信息
+     * @param criteria 条件
+     * @return 知识
+     */
+    private Page<Knowledge> findByCriteria(Pageable pageable, Criteria criteria) {
+        Query query = new CriteriaQuery(criteria);
+        query.setPageable(pageable);
+        SearchHits<Knowledge> searchHits = elasticsearchOperations.search(query, Knowledge.class);
+        List<Knowledge> knowledges = searchHits.stream()
+                .map(SearchHit::getContent)
+                .collect(Collectors.toList());
+        return new PageImpl<>(knowledges, pageable, searchHits.getTotalHits());
+    }
+
+
+}

+ 30 - 34
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/QuestionService.java

@@ -22,13 +22,9 @@ import org.springframework.data.elasticsearch.core.SearchHits;
 import org.springframework.data.elasticsearch.core.query.Criteria;
 import org.springframework.data.elasticsearch.core.query.CriteriaQuery;
 import org.springframework.data.elasticsearch.core.query.Query;
-import org.springframework.lang.Nullable;
 import org.springframework.stereotype.Service;
 
-import java.util.Arrays;
-import java.util.List;
-import java.util.Optional;
-import java.util.UUID;
+import java.util.*;
 import java.util.stream.Collectors;
 
 /**
@@ -51,8 +47,27 @@ public class QuestionService {
     }
 
     public Page<Question> find(String stem, List<String> tags, List<QuestionType> types, List<String> keyPoints,
-                               List<Integer> weight, List<String> knowledgeIds, Pageable pageable) {
-        return completeQuery(stem, tags, types, keyPoints, weight, knowledgeIds, pageable);
+                               List<Integer> weights, List<String> knowledgeIds, Pageable pageable) {
+        Criteria criteria = new Criteria();
+        if (!EmptyCheck.instance.isEmpty(stem)) {
+            criteria = criteria.and("stem").matches(stem);
+        }
+        if (!EmptyCheck.instance.isEmpty(tags)) {
+            criteria = criteria.and("tags").matchesAll(String.join(",", tags));
+        }
+        if (!EmptyCheck.instance.isEmpty(knowledgeIds)) {
+            criteria = criteria.and("knowledge_id").matchesAll(String.join(",", knowledgeIds));
+        }
+        if (!EmptyCheck.instance.isEmpty(keyPoints)) {
+            criteria = criteria.and("key_points").matchesAll(String.join(",", keyPoints));
+        }
+        if (!EmptyCheck.instance.isEmpty(weights)) {
+            criteria = criteria.and("weight").in(weights);
+        }
+        if (!EmptyCheck.instance.isEmpty(types)) {
+            criteria = criteria.and("type").in(types.stream().map(QuestionType::getName).collect(Collectors.toList()));
+        }
+        return findQuestionByCriteria(pageable, criteria);
     }
 
     public Iterable<Question> findAllById(Iterable<String> ids) {
@@ -74,41 +89,16 @@ public class QuestionService {
         questionRepository.deleteById(id);
     }
 
-    public Page<Question> completeQuery(@Nullable String stem, @Nullable List<String> tags,
-                                        List<QuestionType> types, @Nullable List<String> keyPoints, List<Integer> weights,
-                                        @Nullable List<String> knowledgeId, Pageable pageable) {
-        Criteria criteria = new Criteria();
-        if (!EmptyCheck.instance.isEmpty(stem)) {
-            criteria = criteria.and("stem").matches(stem);
-        }
-        if (!EmptyCheck.instance.isEmpty(tags)) {
-            criteria = criteria.and("tags").matchesAll(String.join(",", tags));
-        }
-        if (!EmptyCheck.instance.isEmpty(knowledgeId)) {
-            criteria = criteria.and("knowledge_id").matchesAll(String.join(",", knowledgeId));
-        }
-        if (!EmptyCheck.instance.isEmpty(keyPoints)) {
-            criteria = criteria.and("key_points").matchesAll(String.join(",", keyPoints));
-        }
-        if (!EmptyCheck.instance.isEmpty(weights)) {
-            criteria = criteria.and("weight").in(weights);
-        }
-        if (!EmptyCheck.instance.isEmpty(types)) {
-            criteria = criteria.and("type").in(types.stream().map(QuestionType::getName).collect(Collectors.toList()));
-        }
-        return getQuestions(pageable, criteria);
-    }
-
     public Page<Question> findUncheckedQuestion(QuestionState state, Pageable pageable) {
         Criteria criteria = new Criteria();
         if (!EmptyCheck.instance.isEmpty(state.getName())) {
             criteria = criteria.and("state").matches(state);
         }
-        return getQuestions(pageable, criteria);
+        return findQuestionByCriteria(pageable, criteria);
     }
 
     @NotNull
-    private Page<Question> getQuestions(Pageable pageable, Criteria criteria) {
+    private Page<Question> findQuestionByCriteria(Pageable pageable, Criteria criteria) {
         Query query = new CriteriaQuery(criteria);
         Sort nextSort = Sort.by(pageable.getSort()
                 .map(order -> "id".equals(order.getProperty())
@@ -123,6 +113,12 @@ public class QuestionService {
         return new PageImpl<>(questions, pageable, questionSearchHits.getTotalHits());
     }
 
+    List<Question> findByKnowledgeId(String knowledgeId) {
+        List<String> knowledgeIds = new ArrayList<>();
+        knowledgeIds.add(knowledgeId);
+        return this.find(null, null, null, knowledgeIds, null, null, PageRequest.of(0, 1000)).getContent();
+    }
+
     /**
      * 根据题干和答案生成答案解析
      *

+ 43 - 5
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/StatisticService.java

@@ -1,11 +1,14 @@
 package cn.seecoder.seecoderbokserver.service;
 
+import cn.seecoder.seecoderbokserver.domain.Question;
 import cn.seecoder.seecoderbokserver.domain.Statistic;
 import cn.seecoder.seecoderbokserver.exception.MyServiceException;
 import cn.seecoder.seecoderbokserver.repository.StatisticRepository;
+import cn.seecoder.seecoderbokserver.utility.EmptyCheck;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
+import java.util.List;
 import java.util.Optional;
 import java.util.concurrent.locks.Lock;
 import java.util.concurrent.locks.ReentrantLock;
@@ -14,9 +17,15 @@ import java.util.concurrent.locks.ReentrantLock;
 public class StatisticService {
 
     private final StatisticRepository statisticRepository;
+    private final GraspService graspService;
 
-    public StatisticService(StatisticRepository statisticRepository) {
+    private KnowledgePointService knowledgePointService;
+
+    private QuestionService questionService;
+
+    public StatisticService(StatisticRepository statisticRepository, GraspService graspService) {
         this.statisticRepository = statisticRepository;
+        this.graspService = graspService;
     }
 
     // 可重入锁,用于保证并发更新作答统计时的正确性
@@ -46,10 +55,8 @@ public class StatisticService {
         }
         // 这里要加锁,因为先查询再更新的操作不是原子的
         lock.lock();
-        Optional<Statistic> optional = statisticRepository.findById(questionId);
-        Statistic s;
-        if (optional.isPresent()) {
-            s = optional.get();
+        Statistic s = statisticRepository.findById(questionId).orElse(null);
+        if (s != null) {
             s.setFrequency(s.getFrequency() + frequency);
             s.setCorrectFrequency(s.getCorrectFrequency() + correctFrequency);
         } else {
@@ -57,6 +64,37 @@ public class StatisticService {
         }
         statisticRepository.save(s);
         lock.unlock();
+
+        // 更新知识点掌握率
+        // 1. 获取知识点缩写
+        Question question = questionService.findById(questionId).orElse(null);
+        if (question == null) {
+            throw new MyServiceException("400", "question not found");
+        }
+        List<String> knowledgeAbbrs = question.getKnowledgeId();
+        int weight = Optional.ofNullable(question.getWeight()).orElse(3);
+        if (EmptyCheck.instance.isEmpty(knowledgeAbbrs)) {
+            throw new MyServiceException("400", "knowledgeAbbrs not found");
+        }
+        // 2. 对于每个知识点,获取所有相关的题目的统计信息
+        for (String knowledgeAbbr : knowledgeAbbrs) {
+            List<Question> questions = questionService.findByKnowledgeId(knowledgeAbbr);
+            if (EmptyCheck.instance.isEmpty(questions)) {
+                throw new MyServiceException("400", "questions not found");
+            }
+            // 3. 计算知识点掌握率
+            int grasp, total = 0, correct = 0;
+            for (Question q : questions) {
+                s = statisticRepository.findById(q.getId()).orElse(null);
+                if (s != null) {
+                    total += s.getFrequency() * weight;
+                    correct += s.getCorrectFrequency() * weight;
+                }
+            }
+            grasp = total == 0 ? 0 : correct * 100 / total;
+            // 4. 更新知识点掌握率
+            knowledgePointService.updateGrasp(knowledgeAbbr, grasp);
+        }
     }
 
 }

+ 2 - 2
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/service/UserInteractionService.java

@@ -63,9 +63,9 @@ public class UserInteractionService {
     /**
      * 评价问题
      *
-     * @param userId  user id
+     * @param userId     user id
      * @param questionId question id
-     * @param rateDTO rate dto
+     * @param rateDTO    rate dto
      * @return interaction
      */
     public Interaction rateQuestion(String userId, String questionId, RateDTO rateDTO) {

+ 75 - 38
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/KnowledgeController.java

@@ -1,38 +1,75 @@
-package cn.seecoder.seecoderbokserver.web.rest;
-
-import cn.seecoder.bok.common.api.SeecoderBokKnowledgeApi;
-import cn.seecoder.bok.common.vo.KnowledgeNodeVO;
-import cn.seecoder.seecoderbokserver.mapper.KnowledgeMapper;
-import cn.seecoder.seecoderbokserver.service.KnowledgeService;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
-
-import java.util.List;
-import java.util.stream.Collectors;
-
-/**
- * @author: Leonezhurui
- * @Date: 2021/8/30 - 9:46 上午
- * @Package: SEEC-BOK
- */
-
-@RestController
-@RequestMapping("/api/knowledge")
-public class KnowledgeController implements SeecoderBokKnowledgeApi {
-    private final KnowledgeService knowledgeService;
-    private final KnowledgeMapper knowledgeMapper;
-
-    public KnowledgeController(KnowledgeService knowledgeService, KnowledgeMapper knowledgeMapper) {
-        this.knowledgeService = knowledgeService;
-        this.knowledgeMapper = knowledgeMapper;
-    }
-
-    @Override
-    @GetMapping("")
-    public List<KnowledgeNodeVO> getKnowledgeNode(@RequestParam(name = "abbreviation_keyPoints") String keyPoints) {
-        return knowledgeService.findByAbbreviationLike(keyPoints).stream().map(knowledgeMapper::knowledgeToKnowledgeNodeVO).collect(Collectors.toList());
-    }
-
-}
+package cn.seecoder.seecoderbokserver.web.rest;
+
+import cn.seecoder.bok.common.KnowledgeStatus;
+import cn.seecoder.seecoderbokserver.domain.Knowledge;
+import cn.seecoder.seecoderbokserver.service.KnowledgeService;
+import org.springframework.data.domain.PageRequest;
+import org.springframework.web.bind.annotation.*;
+
+import javax.validation.constraints.NotNull;
+import java.util.List;
+
+@RestController
+@RequestMapping("/api/knowledge")
+public class KnowledgeController {
+
+    private final KnowledgeService knowledgeService;
+
+    public KnowledgeController(KnowledgeService knowledgeService) {
+        this.knowledgeService = knowledgeService;
+    }
+
+    @PostMapping("/create")
+    public Response create(@NotNull @RequestBody Knowledge knowledge) {
+        return Response.buildSuccess(knowledgeService.create(knowledge));
+    }
+
+    @PostMapping("/delete")
+    public Response delete(@NotNull @RequestBody String uuid) {
+        if (knowledgeService.delete(uuid)) {
+            return Response.buildSuccess("删除成功");
+        } else {
+            return Response.buildFailed("500", "删除失败");
+        }
+    }
+
+    @PostMapping("/update")
+    public Response update(@NotNull @RequestBody Knowledge knowledge) {
+        return Response.buildSuccess(knowledgeService.update(knowledge));
+    }
+
+    @PostMapping("/approve")
+    public Response approve(@NotNull @RequestBody String uuid) {
+        return Response.buildSuccess(knowledgeService.approve(uuid));
+    }
+
+    @PostMapping("/refuse")
+    public Response refuse(@NotNull @RequestBody String uuid) {
+        return Response.buildSuccess(knowledgeService.refuse(uuid));
+    }
+
+    @GetMapping("/getByStatus")
+    public Response getByStatus(@RequestParam(name = "offset") int offset,
+                                @RequestParam(name = "pageSize") int pageSize,
+                                @RequestParam(name = "status") KnowledgeStatus status) {
+        PageRequest pageRequest = PageRequest.of(offset, pageSize);
+        return Response.buildSuccess(knowledgeService.findUnChecked(
+                pageRequest, status));
+    }
+
+    @GetMapping("/search")
+    public Response search(@RequestParam(name = "offset") int offset,
+                           @RequestParam(name = "pageSize") int pageSize,
+                           @RequestParam(name = "keyword") String keyword,
+                           @RequestParam(name = "knowledge_point") List<String> knowledgePoint) {
+        PageRequest pageRequest = PageRequest.of(offset, pageSize);
+        return Response.buildSuccess(knowledgeService.find(keyword, knowledgePoint, pageRequest));
+    }
+
+    @GetMapping("/getByUUID")
+    public Response getByUUID(@RequestParam(name = "uuid") String uuid) {
+        return Response.buildSuccess(knowledgeService.findByUUID(uuid));
+    }
+
+
+}

+ 38 - 0
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/KnowledgePointController.java

@@ -0,0 +1,38 @@
+package cn.seecoder.seecoderbokserver.web.rest;
+
+import cn.seecoder.bok.common.api.SeecoderBokKnowledgeApi;
+import cn.seecoder.bok.common.vo.KnowledgeNodeVO;
+import cn.seecoder.seecoderbokserver.mapper.KnowledgeMapper;
+import cn.seecoder.seecoderbokserver.service.KnowledgePointService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * @author: Leonezhurui
+ * @Date: 2021/8/30 - 9:46 上午
+ * @Package: SEEC-BOK
+ */
+
+@RestController
+@RequestMapping("/api/knowledgePoint")
+public class KnowledgePointController implements SeecoderBokKnowledgeApi {
+    private final KnowledgePointService knowledgePointService;
+    private final KnowledgeMapper knowledgeMapper;
+
+    public KnowledgePointController(KnowledgePointService knowledgePointService, KnowledgeMapper knowledgeMapper) {
+        this.knowledgePointService = knowledgePointService;
+        this.knowledgeMapper = knowledgeMapper;
+    }
+
+    @Override
+    @GetMapping("")
+    public List<KnowledgeNodeVO> getKnowledgeNode(@RequestParam(name = "abbreviation_keyPoints") String keyPoints) {
+        return knowledgePointService.findByAbbreviationLike(keyPoints).stream().map(knowledgeMapper::knowledgeToKnowledgeNodeVO).collect(Collectors.toList());
+    }
+
+}

+ 3 - 3
seecoder-bok-server/src/main/java/cn/seecoder/seecoderbokserver/web/rest/StatisticController.java

@@ -30,9 +30,9 @@ public class StatisticController {
      */
     @PostMapping("/update")
     public Response updateStatistic(@RequestParam(required = true, name = "questionId") String questionId,
-                                @RequestParam(required = true, name = "frequency") int frequency,
-                                @RequestParam(required = true, name = "correctFrequency") int correctFrequency) {
-        statisticService.updateStatistic(questionId, frequency, correctFrequency);
+                                @RequestParam(required = true, name = "totalCount") int totalCount,
+                                @RequestParam(required = true, name = "correctCount") int correctCount) {
+        statisticService.updateStatistic(questionId, totalCount, correctCount);
         return Response.buildSuccess("更新成功");
     }