Browse Source

feat(server): 题库搜索

Go 5 years ago
parent
commit
7721e6040a
26 changed files with 415 additions and 69 deletions
  1. 3 3
      front/project/www/routes/paper/question/detail/index.js
  2. 22 0
      server/data/src/main/java/com/qxgmat/data/relation/QuestionNoRelationMapper.java
  3. 5 0
      server/data/src/main/java/com/qxgmat/data/relation/SentenceQuestionRelationMapper.java
  4. 5 0
      server/data/src/main/java/com/qxgmat/data/relation/TextbookQuestionRelationMapper.java
  5. 75 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionNoRelationMapper.xml
  6. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionRelationMapper.xml
  7. 8 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/SentenceQuestionRelationMapper.xml
  8. 9 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookQuestionRelationMapper.xml
  9. 10 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  10. 6 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  11. 2 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  12. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java
  13. 6 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  14. 17 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  15. 50 25
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  16. 17 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionNoDetailDto.java
  17. 39 8
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java
  18. 10 2
      server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java
  19. 9 13
      server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java
  20. 7 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  21. 3 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  22. 56 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java
  23. 9 4
      server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java
  24. 9 4
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookQuestionService.java
  25. 30 7
      server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java
  26. 6 0
      server/gateway-api/src/main/java/com/qxgmat/task/ScheduledTask.java

+ 3 - 3
front/project/www/routes/paper/question/detail/index.js

@@ -94,12 +94,12 @@ export default class extends Component {
     if (!userQuestion.collect) {
       My.addQuestionCollect(userQuestion.questionModule, questionNo.id).then(() => {
         userQuestion.collect = true;
-        flow.change({ userQuestion });
+        flow.setState({ userQuestion });
       });
     } else {
       My.delQuestionCollect(userQuestion.questionModule, questionNo.id).then(() => {
-        userQuestion.collect = true;
-        flow.change({ userQuestion });
+        userQuestion.collect = false;
+        flow.setState({ userQuestion });
       });
     }
   }

+ 22 - 0
server/data/src/main/java/com/qxgmat/data/relation/QuestionNoRelationMapper.java

@@ -21,10 +21,32 @@ public interface QuestionNoRelationMapper {
             @Param("correct") Integer correct
     );
 
+    void accumulationCollect(
+            @Param("id") Number questionNoId,
+            @Param("collect") int collect
+    );
+
     List<QuestionNo> searchStem(
             @Param("stem") String stem
     );
 
+    List<QuestionNoRelation> searchStemFulltext(
+            @Param("keyword") String keyword,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("module") String module,
+            @Param("structIds") Integer[] structIds,
+            @Param("place") String place,
+            @Param("difficult") String difficult,
+            @Param("qxCatId") Integer qxCatId,
+            String order,
+            String direction
+    );
+
+    List<QuestionNo> searchNoFulltext(
+            @Param("keyword") String keyword,
+            @Param("qxCatId") Integer qxCatId
+    );
+
     List<QuestionNo> randomExamination(
             @Param("structId") Number structId,
             @Param("targetTypes") Collection targetTypes,

+ 5 - 0
server/data/src/main/java/com/qxgmat/data/relation/SentenceQuestionRelationMapper.java

@@ -13,4 +13,9 @@ public interface SentenceQuestionRelationMapper {
             @Param("time") Integer time,
             @Param("correct") Integer correct
     );
+
+    void accumulationCollect(
+            @Param("id") Number questionNoId,
+            @Param("collect") int collect
+    );
 }

+ 5 - 0
server/data/src/main/java/com/qxgmat/data/relation/TextbookQuestionRelationMapper.java

@@ -18,6 +18,11 @@ public interface TextbookQuestionRelationMapper {
             @Param("correct") Integer correct
     );
 
+    void accumulationCollect(
+            @Param("id") Number questionNoId,
+            @Param("collect") int collect
+    );
+
     List<TextbookQuestionRelation> listAdmin(
             @Param("questionType") String questionType,
             @Param("paperId") Number paperId,

+ 75 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionNoRelationMapper.xml

@@ -33,6 +33,15 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
 
+  <!--累加收藏记录-->
+  <update id="accumulationCollect">
+    UPDATE `question_no`
+    <trim prefix="set" suffixOverrides=",">
+      `collect_number`=`collect_number`+#{collect, jdbcType=INTEGER},
+    </trim>
+    WHERE `id` = #{id, jdbcType=VARCHAR}
+  </update>
+
   <!--
     按题干搜索相似度80%以上的
   -->
@@ -47,6 +56,72 @@
   </select>
 
   <!--
+    按题干搜索相似度或者题号完全匹配,过滤千行cat
+  -->
+  <select id="searchStemFulltext" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />,
+    if(qn.`title` = #{keyword, jdbcType=VARCHAR}, 1, MATCH (q.`stem`) AGAINST (#{keyword, jdbcType=VARCHAR} IN NATURAL LANGUAGE MODE)) as `relation_score`,
+    <if test="qxCatId != null">
+      if(qn.module='examination', find_in_set(#{qxCatId}, qn.`module_struct`), 0) as `select`,
+    </if>
+    q.`collect_number` as `collect_number`,
+    qn.`total_correct` / qn.`total_number` as `correct`,
+    qn.`total_time` / qn.`total_number` as `time`
+    from `question_no` qn
+    left join `question` q on q.`id` = qn.`question_id`
+      and (q.`question_module` = 'base')
+      <if test="difficult != null">
+        and q.`difficult` = #{difficult,jdbcType=VARCHAR}
+      </if>
+      <if test="place != null">
+        and q.`place` = #{place,jdbcType=VARCHAR}
+      </if>
+    <if test="questionTypes != null">
+      and
+      <foreach collection="questionTypes" item="item" index="index" open="(" close=")" separator=" or ">
+        q.`question_type` = #{item}
+      </foreach>
+    </if>
+    where
+    (qn.`title` = #{keyword, jdbcType=VARCHAR} or MATCH (q.`stem`) AGAINST (#{keyword, jdbcType=VARCHAR} IN NATURAL LANGUAGE MODE))
+    and q.id &gt; 0
+    <if test="qxCatId != null">
+      and `select` = 0
+    </if>
+    <if test="module != null">
+      and qn.`module` = #{module,jdbcType=VARCHAR}
+    </if>
+    <if test="structIds != null">
+      and
+      <foreach collection="structIds" item="item" index="index" open="(" close=")" separator=" or ">
+        find_in_set(#{item}, qn.`module_struct`)
+      </foreach>
+    </if>
+    ORDER BY #{order} #{direction}, qn.`no`DESC
+  </select>
+
+  <!--
+    按题目id查询,过滤千行cat
+  -->
+  <select id="searchNoFulltext" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />,
+    MATCH (qn.`title`) AGAINST (#{keyword, jdbcType=VARCHAR} IN NATURAL LANGUAGE MODE) as `relation_score`
+    <if test="qxCatId != null">
+      ,
+      if(qn.module='examination', find_in_set(#{qxCatId}, qn.`module_struct`), 0) as `select`
+    </if>
+    from `question_no` qn
+    where
+    MATCH (qn.`title`) AGAINST (#{keyword, jdbcType=VARCHAR} IN NATURAL LANGUAGE MODE)
+    <if test="qxCatId != null">
+      and `select` = 0
+    </if>
+    ORDER BY `relation_score` DESC
+  </select>
+
+  <!--
     模考随机出题
   -->
   <select id="randomExamination" resultMap="IdMap">

+ 1 - 1
server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionRelationMapper.xml

@@ -25,7 +25,7 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
 
-  <!--累加做题记录-->
+  <!--累加收藏记录-->
   <update id="accumulationCollect">
     UPDATE `question`
     <trim prefix="set" suffixOverrides=",">

+ 8 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/SentenceQuestionRelationMapper.xml

@@ -25,4 +25,12 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
 
+  <!--累加收藏记录-->
+  <update id="accumulationCollect">
+    UPDATE `sentence_question`
+    <trim prefix="set" suffixOverrides=",">
+      `collect_number`=`collect_number`+#{collect, jdbcType=INTEGER},
+    </trim>
+    WHERE `id` = #{id, jdbcType=VARCHAR}
+  </update>
 </mapper>

+ 9 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookQuestionRelationMapper.xml

@@ -25,6 +25,15 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
 
+  <!--累加收藏记录-->
+  <update id="accumulationCollect">
+    UPDATE `textbook_question`
+    <trim prefix="set" suffixOverrides=",">
+      `collect_number`=`collect_number`+#{collect, jdbcType=INTEGER},
+    </trim>
+    WHERE `id` = #{id, jdbcType=VARCHAR}
+  </update>
+
   <select id="listAdmin" resultMap="IdMap">
     select
     <include refid="Id_Column_List" />

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java

@@ -22,9 +22,11 @@ import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.ManagerService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.extend.CourseExtendService;
+import com.qxgmat.service.extend.MessageExtendService;
 import com.qxgmat.service.extend.OrderFlowService;
 import com.qxgmat.service.extend.ToolsService;
 import com.qxgmat.service.inline.*;
+import com.qxgmat.task.AsyncTask;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -101,6 +103,11 @@ public class CourseController {
     @Autowired
     private ToolsService toolsService;
 
+    @Autowired
+    private MessageExtendService messageExtendService;
+
+    @Autowired
+    private AsyncTask asyncTask;
 
     @RequestMapping(value = "/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加课程", httpMethod = "POST")
@@ -271,6 +278,7 @@ public class CourseController {
             tmp.setLatestTime(entity.getTime());
             courseDataService.edit(tmp);
         }
+        asyncTask.postDataUpdate(entity.getId());
         managerLogService.log(request);
         return ResponseHelp.success(Transform.convert(entity, CourseDataHistory.class));
     }
@@ -745,6 +753,8 @@ public class CourseController {
             entity.setAnswerStatus(AskStatus.ANSWER.index);
             Manager manager = shiroHelp.getLoginManager();
             entity.setManagerId(manager.getId());
+            User user = usersService.get(in.getUserId());
+            messageExtendService.sendAskCourse(user, entity);
         }
         if (dto.getIgnoreStatus() != null && dto.getIgnoreStatus() > 0){
             entity.setAnswerStatus(AskStatus.IGNORE.index);

+ 6 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java

@@ -18,6 +18,7 @@ import com.qxgmat.dto.admin.response.UserAskQuestionDetailDto;
 import com.qxgmat.dto.admin.response.UserAskQuestionListDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.UserQuestionService;
+import com.qxgmat.service.extend.MessageExtendService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.service.ManagerService;
 import com.qxgmat.service.UsersService;
@@ -71,6 +72,9 @@ public class QuestionController {
     @Autowired
     private UserReportService userReportService;
 
+    @Autowired
+    private MessageExtendService messageExtendService;
+
     @RequestMapping(value = "/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加题目", httpMethod = "POST")
     public Response<Question> add(@RequestBody @Validated QuestionDto dto, HttpServletRequest request) {
@@ -183,6 +187,8 @@ public class QuestionController {
             entity.setAnswerStatus(AskStatus.ANSWER.index);
             Manager manager = shiroHelp.getLoginManager();
             entity.setManagerId(manager.getId());
+            User user = usersService.get(in.getUserId());
+            messageExtendService.sendAskQuestion(user, entity);
         }
 
         if (dto.getIgnoreStatus() != null && dto.getIgnoreStatus() > 0){

+ 2 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java

@@ -510,6 +510,8 @@ public class SettingController {
             entity.setAnswerStatus(AskStatus.ANSWER.index);
             Manager manager = shiroHelp.getLoginManager();
             entity.setManagerId(manager.getId());
+            User user = usersService.get(in.getUserId());
+            messageExtendService.sendFaqCallback(user, in);
         }
         if(in.getIsSystem() == 0 && dto.getSendUser() != null && dto.getSendUser()){
             // 回复邮箱

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java

@@ -206,7 +206,7 @@ public class TextbookController {
         TextbookLibraryHistory entity = Transform.dtoToEntity(dto);
         textbookLibraryService.addHistory(entity);
         // 发送机经到用户邮箱
-        asyncTask.postTextbookToEmail();
+        asyncTask.postTextbookUpdate();
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }

+ 6 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java

@@ -152,6 +152,9 @@ public class UserController {
     @Autowired
     private UserCourseRecordService userCourseRecordService;
 
+    @Autowired
+    private MessageExtendService messageExtendService;
+
     @RequestMapping(value = "/token", method = RequestMethod.GET)
     @ApiOperation(value = "获取用户token", httpMethod = "GET")
     public Response<String> token(@RequestParam int id, HttpSession session) {
@@ -488,6 +491,8 @@ public class UserController {
             entity.setHandleTime(new Date());
             Manager manager = shiroHelp.getLoginManager();
             entity.setManagerId(manager.getId());
+            User user = usersService.get(in.getUserId());
+            messageExtendService.sendFeedbackAnswer(user, in);
         }
 
         entity = userFeedbackErrorService.edit(entity);
@@ -870,6 +875,7 @@ public class UserController {
         if (dto.getIsAlert() != null && dto.getIsAlert() > 1){
             User user = usersService.get(in.getUserId());
             usersService.edit(User.builder().id(user.getId()).totalAlert(user.getTotalAlert() + 1).build());
+            messageExtendService.sendLoginAbnormal(user, in);
         }
 
         entity = userAbnormalService.edit(entity);

+ 17 - 1
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -215,6 +215,7 @@ public class MyController {
                 .id(user.getId())
                 .email(dto.getEmail())
                 .build());
+        messageExtendService.sendEmailChange(user);
         return ResponseHelp.success(true);
     }
 
@@ -803,7 +804,22 @@ public class MyController {
     @ApiOperation(value = "移除题目收藏", notes = "移除题目收藏", httpMethod = "DELETE")
     public Response<Boolean> deleteQuestionCollect(String questionModule, Integer questionNoId)  {
         User user = (User) shiroHelp.getLoginUser();
-        Boolean result = userCollectQuestionService.deleteQuestion(user.getId(), QuestionModule.ValueOf(questionModule), questionNoId);
+        Integer questionId = null;
+        switch (QuestionModule.ValueOf(questionModule)){
+            case BASE:
+                QuestionNo questionNo = questionNoService.get(questionNoId);
+                questionId = questionNo.getQuestionId();
+                break;
+            case SENTENCE:
+                SentenceQuestion sentenceQuestion = sentenceQuestionService.get(questionNoId);
+                questionId = sentenceQuestion.getQuestionId();
+                break;
+            case TEXTBOOK:
+                TextbookQuestion textbookQuestion = textbookQuestionService.get(questionNoId);
+                questionId = textbookQuestion.getQuestionId();
+                break;
+        }
+        Boolean result = userCollectQuestionService.deleteQuestion(user.getId(), questionId);
 
         return ResponseHelp.success(result);
     }

+ 50 - 25
server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java

@@ -10,6 +10,7 @@ import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
 import com.qxgmat.data.constants.enums.module.*;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
@@ -121,13 +122,24 @@ public class QuestionController {
 
     @RequestMapping(value = "/search/stem", method = RequestMethod.GET)
     @ApiOperation(value = "搜索题目编号列表:题干搜索", httpMethod = "GET")
-    public Response<PageMessage<QuestionBaseExtendDto>> searchStem(
+    public Response<PageMessage<QuestionNoDetailDto>> searchStem(
             @RequestParam(required = false, defaultValue = "1") int page,
-            @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String keyword,
+            @RequestParam(required = false, defaultValue = "10") int size,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) Integer[] structIds,
+            @RequestParam(required = false) String place,
+            @RequestParam(required = false) String difficult,
+            @RequestParam(required = false, defaultValue = "id") String order, // collect_number, correct, time, relation_score
+            @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        PageResult<QuestionNoRelation> p = questionNoService.searchStem(page, size, keyword);
-        List<QuestionBaseExtendDto> pr = Transform.convert(p, QuestionBaseExtendDto.class);
+        // 过滤千行cat的数据
+        List<ExaminationStruct> structs = examinationStructService.main();
+        ExaminationStruct qxCatStruct = structs.stream().filter((row)-> row.getExtend().equals(ServiceKey.QX_CAT.key)).findFirst().get();
+
+        Page<QuestionNoRelation> p = questionNoService.searchStemFulltext(page, size, keyword, questionTypes, module, structIds, place, difficult, qxCatStruct.getId(), order, DirectionStatus.ValueOf(direction));
+        List<QuestionNoDetailDto> pr = Transform.convert(p, QuestionNoDetailDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
@@ -136,10 +148,14 @@ public class QuestionController {
     @ApiOperation(value = "搜索题目编号列表:题目编号搜索", httpMethod = "GET")
     public Response<PageMessage<QuestionNoDto>> searchNo(
             @RequestParam(required = false, defaultValue = "1") int page,
-            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false, defaultValue = "5") int size,
             @RequestParam(required = true) String keyword,
             HttpSession session) {
-        PageResult<QuestionNoRelation> p = questionNoService.searchNo(page, size, keyword, null);
+        // 过滤千行cat的数据
+        List<ExaminationStruct> structs = examinationStructService.main();
+        ExaminationStruct qxCatStruct = structs.stream().filter((row)-> row.getExtend().equals(ServiceKey.QX_CAT.key)).findFirst().get();
+
+        Page<QuestionNo> p = questionNoService.searchNoFulltext(page, size, keyword, qxCatStruct.getId());
         List<QuestionNoDto> pr = Transform.convert(p, QuestionNoDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
@@ -166,11 +182,13 @@ public class QuestionController {
         dto.setQuestion(Transform.convert(question, QuestionDetailExtendDto.class));
         dto.setQuestionNo(Transform.convert(questionNo, QuestionNoExtendDto.class));
 
-        UserCollectQuestion collect = userCollectQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
-        dto.setCollect(collect != null);
+        if (user!=null){
+            UserCollectQuestion collect = userCollectQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
+            dto.setCollect(collect != null);
 
-        UserNoteQuestion userNoteQuestion = userNoteQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
-        dto.setNote(Transform.convert(userNoteQuestion, UserNoteQuestionExtendDto.class));
+            UserNoteQuestion userNoteQuestion = userNoteQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
+            dto.setNote(Transform.convert(userNoteQuestion, UserNoteQuestionExtendDto.class));
+        }
 
         List<UserAskQuestion> userAskQuestionList = userAskQuestionService.listByQuestion(userQuestion.getQuestionId(), true);
         dto.setAsks(Transform.convert(userAskQuestionList, UserAskQuestionExtendDto.class));
@@ -185,10 +203,13 @@ public class QuestionController {
         dto.setQuestionNos(Transform.convert(questionNoList, QuestionNoExtendDto.class));
 
         // 获取提问权限
-        Integer recordId = questionFlowService.questionRelationCourse(user.getId(), null, QuestionType.ValueOf(question.getQuestionType()));
-        if (recordId != null){
-            dto.setQuestionStatus(1);
-        }else{
+        if (user!= null){
+            Integer recordId = questionFlowService.questionRelationCourse(user.getId(), null, QuestionType.ValueOf(question.getQuestionType()));
+            if (recordId != null){
+                dto.setQuestionStatus(1);
+            }
+        }
+        if(dto.getQuestionStatus() == null){
             Integer id = questionNo.getModuleStruct()[questionNo.getModuleStruct().length - 1];
             QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(questionNo.getModule());
             // 获取基本当前权限
@@ -568,11 +589,13 @@ public class QuestionController {
         Question question = questionService.get(userQuestion.getQuestionId());
         dto.setQuestion(Transform.convert(question, QuestionDetailExtendDto.class));
 
-        UserCollectQuestion collect = userCollectQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
-        dto.setCollect(collect != null);
+        if (user != null){
+            UserCollectQuestion collect = userCollectQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
+            dto.setCollect(collect != null);
 
-        UserNoteQuestion userNoteQuestion = userNoteQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
-        dto.setNote(Transform.convert(userNoteQuestion, UserNoteQuestionExtendDto.class));
+            UserNoteQuestion userNoteQuestion = userNoteQuestionService.getByUserAndQuestion(user.getId(), userQuestion.getQuestionId());
+            dto.setNote(Transform.convert(userNoteQuestion, UserNoteQuestionExtendDto.class));
+        }
 
         List<UserAskQuestion> userAskQuestionList = userAskQuestionService.listByQuestion(userQuestion.getQuestionId(), true);
         dto.setAsks(Transform.convert(userAskQuestionList, UserAskQuestionExtendDto.class));
@@ -600,11 +623,14 @@ public class QuestionController {
                 break;
         }
         // 获取提问权限
-        PaperOrigin origin= PaperOrigin.ValueOf(userReport.getPaperOrigin());
-        Integer recordId = questionFlowService.questionRelationCourse(user.getId(), origin == PaperOrigin.PREVIEW ? userReport.getOriginId() : null, QuestionType.ValueOf(question.getQuestionType()));
-        if (recordId != null){
-            dto.setQuestionStatus(1);
-        }else{
+        PaperOrigin origin = PaperOrigin.ValueOf(userReport.getPaperOrigin());
+        if (user != null){
+            Integer recordId = questionFlowService.questionRelationCourse(user.getId(), origin == PaperOrigin.PREVIEW ? userReport.getOriginId() : null, QuestionType.ValueOf(question.getQuestionType()));
+            if (recordId != null){
+                dto.setQuestionStatus(1);
+            }
+        }
+        if (dto.getQuestionStatus() == null){
             // 获取基本当前权限
             switch(origin){
                 case EXAMINATION:
@@ -630,7 +656,6 @@ public class QuestionController {
             }
         }
 
-
         return ResponseHelp.success(dto);
     }
 

+ 17 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionNoDetailDto.java

@@ -0,0 +1,17 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.QuestionNo;
+
+@Dto(entity = QuestionNo.class)
+public class QuestionNoDetailDto {
+    private Boolean collect;
+
+    public Boolean getCollect() {
+        return collect;
+    }
+
+    public void setCollect(Boolean collect) {
+        this.collect = collect;
+    }
+}

+ 39 - 8
server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java

@@ -18,6 +18,8 @@ import com.qxgmat.data.relation.UserCollectQuestionRelationMapper;
 import com.qxgmat.data.relation.entity.UserCollectQuestionRelation;
 import com.qxgmat.service.inline.QuestionNoService;
 import com.qxgmat.service.inline.QuestionService;
+import com.qxgmat.service.inline.SentenceQuestionService;
+import com.qxgmat.service.inline.TextbookQuestionService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -35,6 +37,15 @@ public class UserCollectQuestionService extends AbstractService {
     private QuestionService questionService;
 
     @Resource
+    private QuestionNoService questionNoService;
+
+    @Resource
+    private SentenceQuestionService sentenceQuestionService;
+
+    @Resource
+    private TextbookQuestionService textbookQuestionService;
+
+    @Resource
     private UserCollectQuestionMapper userCollectQuestionMapper;
 
     @Resource
@@ -124,8 +135,7 @@ public class UserCollectQuestionService extends AbstractService {
         example.and(
                 example.createCriteria()
                         .andEqualTo("userId", entity.getUserId())
-                        .andEqualTo("questionModule", entity.getQuestionModule())
-                        .andEqualTo("questionNoId", entity.getQuestionNoId())
+                        .andEqualTo("questionId", entity.getQuestionId())
         );
         UserCollectQuestion in = one(userCollectQuestionMapper, example);
         if (in != null){
@@ -133,31 +143,52 @@ public class UserCollectQuestionService extends AbstractService {
         }
         int result = insert(userCollectQuestionMapper, entity);
         questionService.accumulationCollect(entity, 1);
+        switch(QuestionModule.ValueOf(entity.getQuestionModule())){
+            case BASE:
+                questionNoService.accumulationCollect(in, 1);
+                break;
+            case SENTENCE:
+                sentenceQuestionService.accumulationCollect(in, 1);
+                break;
+            case TEXTBOOK:
+                textbookQuestionService.accumulationCollect(in, 1);
+                break;
+        }
         return entity;
     }
 
     /**
      * 取消收藏题目编号
      * @param userId
-     * @param questionNoId
+     * @param questionId
      * @return
      */
     @Transactional
-    public boolean deleteQuestion(Integer userId, QuestionModule module, Integer questionNoId){
+    public boolean deleteQuestion(Integer userId, Integer questionId){
         Example example = new Example(UserCollectQuestion.class);
         example.and(
                 example.createCriteria()
                         .andEqualTo("userId", userId)
-                        .andEqualTo("questionModule", module.key)
-                        .andEqualTo("questionNoId", questionNoId)
+                        .andEqualTo("questionId", questionId)
         );
         UserCollectQuestion in = one(userCollectQuestionMapper, example);
         if (in == null){
             return true;
         }
-        int result = delete(userCollectQuestionMapper, example);
+        boolean result = delete(in.getId());
         questionService.accumulationCollect(in, -1);
-        return result > 0;
+        switch(QuestionModule.ValueOf(in.getQuestionModule())){
+            case BASE:
+                questionNoService.accumulationCollect(in, -1);
+                break;
+            case SENTENCE:
+                sentenceQuestionService.accumulationCollect(in, -1);
+                break;
+            case TEXTBOOK:
+                textbookQuestionService.accumulationCollect(in, -1);
+                break;
+        }
+        return result;
     }
 
     public UserCollectQuestion add(UserCollectQuestion collect){

+ 10 - 2
server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java

@@ -20,6 +20,7 @@ import com.qxgmat.data.inline.UserToken;
 import com.qxgmat.data.relation.UserRelationMapper;
 import com.qxgmat.data.relation.entity.UserPrepareRelation;
 import com.qxgmat.help.WechatHelp;
+import com.qxgmat.service.extend.MessageExtendService;
 import com.qxgmat.service.extend.OrderFlowService;
 import com.qxgmat.service.inline.UserCourseService;
 import com.qxgmat.service.inline.UserMessageService;
@@ -59,6 +60,9 @@ public class UsersService extends AbstractService {
     @Resource
     private OrderFlowService orderFlowService;
 
+    @Resource
+    private MessageExtendService messageExtendService;
+
     /**
      * 生成有效期token
      * @param user
@@ -216,8 +220,12 @@ public class UsersService extends AbstractService {
         if (openUser != null){
             this.bind(user, openUser);
         }
-
-        user = n ? add(user) : edit(user);
+        if (n){
+            user = add(user);
+            messageExtendService.sendRegister(user);
+        }else{
+            user = edit(user);
+        }
         if(user == null)
             throw new SystemException("注册失败");
         return user;

+ 9 - 13
server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java

@@ -5,10 +5,7 @@ import com.nuliji.tools.exception.SystemException;
 import com.qxgmat.data.constants.enums.MessageCategory;
 import com.qxgmat.data.constants.enums.MessageMethod;
 import com.qxgmat.data.constants.enums.MessageType;
-import com.qxgmat.data.dao.entity.MessageTemplate;
-import com.qxgmat.data.dao.entity.TextbookLibrary;
-import com.qxgmat.data.dao.entity.User;
-import com.qxgmat.data.dao.entity.UserMessage;
+import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.help.MailHelp;
 import com.qxgmat.help.WechatHelp;
 import com.qxgmat.service.inline.MessageTemplateService;
@@ -70,7 +67,6 @@ public class MessageExtendService {
                 .link(link)
                 .type(MessageType.FromCategory(category).key)
                 .isRead(0)
-                .createTime(new Date())
                 .build());
     }
 
@@ -104,7 +100,7 @@ public class MessageExtendService {
     /**
      * 发送登录异常
      */
-    public void sendLoginAbnormal(User user){
+    public void sendLoginAbnormal(User user, UserAbnormal userAbnormal){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.LOGIN_ABNORMAL, map);
     }
@@ -114,7 +110,7 @@ public class MessageExtendService {
      * 课程名称:{courseTitle}
      * 作业名称:{assignTitle}
      */
-    public void sendPreviewNotice(User user){
+    public void sendPreviewNotice(User user, PreviewAssign previewAssign){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.PREVIEW_NOTICE, map);
     }
@@ -125,7 +121,7 @@ public class MessageExtendService {
      * 支付金额:{money}
      * 开通有效期:{expireTime}
      */
-    public void sendPayed(User user){
+    public void sendPayed(User user, UserOrder userOrder){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.PAYED, map);
     }
@@ -135,7 +131,7 @@ public class MessageExtendService {
      * 资料名称:{title}
      * 更新时间:{updateTime}
      */
-    public void sendDataUpdate(User user){
+    public void sendDataUpdate(User user, CourseData data, CourseDataHistory history){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.DATA_UPDATE, map);
     }
@@ -146,7 +142,7 @@ public class MessageExtendService {
      * 提问时间:{askTime}
      * 提问状态:{status}, 精选、隐藏
      */
-    public void sendAskQuestion(User user){
+    public void sendAskQuestion(User user,UserAskQuestion userAskQuestion){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.ASK_QUESTION, map);
     }
@@ -157,7 +153,7 @@ public class MessageExtendService {
      * 提问时间:{askTime}
      * 提问状态:{status}, 精选、隐藏
      */
-    public void sendAskCourse(User user){
+    public void sendAskCourse(User user, UserAskCourse userAskCourse){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.ASK_COURSE, map);
     }
@@ -167,7 +163,7 @@ public class MessageExtendService {
      * 咨询板块
      * 咨询简介
      */
-    public void sendFaqCallback(User user){
+    public void sendFaqCallback(User user, Faq faq){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.FAQ_CALLBACK, map);
     }
@@ -177,7 +173,7 @@ public class MessageExtendService {
      * 咨询板块
      * 咨询简介
      */
-    public void sendFeedbackAnswer(User user){
+    public void sendFeedbackAnswer(User user, UserFeedbackError feedbackError){
         Map<String, String> map = new HashMap<>();
         send(user, MessageCategory.FEEDBACK_CALLBACK, map);
     }

+ 7 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -64,6 +64,9 @@ public class OrderFlowService {
     @Resource
     private ExaminationService examinationService;
 
+    @Resource
+    private MessageExtendService messageExtendService;
+
     private TradeService tradeService;
 
     @Resource
@@ -785,6 +788,10 @@ public class OrderFlowService {
 
         // 累加用户支付信息
         usersService.accumulation(userOrder.getUserId(), userOrder.getMoney());
+
+        // 发送通知
+        User user = usersService.get(userId);
+        messageExtendService.sendPayed(user, userOrder);
         return true;
     }
 

+ 3 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java

@@ -90,6 +90,9 @@ public class QuestionFlowService {
     @Resource
     private ToolsService toolsService;
 
+    @Resource
+    private MessageExtendService messageExtendService;
+
     // 自由组卷初始化试卷callback
     private Map<QuestionModule, InitPaper> makePaperCallback = new HashMap<>();
 

+ 56 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java

@@ -8,9 +8,11 @@ import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.module.StructModule;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.QuestionNoMapper;
 import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.QuestionNo;
+import com.qxgmat.data.dao.entity.UserCollectQuestion;
 import com.qxgmat.data.dao.entity.UserQuestion;
 import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.relation.QuestionNoRelationMapper;
@@ -88,6 +90,52 @@ public class QuestionNoService extends AbstractService {
     }
 
     /**
+     * 根据题目编号搜索相似题目
+     * @param page
+     * @param size
+     * @param keyword
+     * @return
+     */
+    public Page<QuestionNoRelation> searchStemFulltext(int page, int size, String keyword, String[] questionTypes, String module, Integer[] structIds, String place, String difficult, Integer qxCatId, String order, DirectionStatus direction){
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<QuestionNoRelation> p = page(()->{
+            questionNoRelationMapper.searchStemFulltext(keyword, questionTypes, module, structIds, place, difficult, qxCatId, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, QuestionNo.class, "id");
+
+        // 获取详细数据
+        List<QuestionNo> list = select(ids);
+        List<QuestionNoRelation> relationList = relation(list);
+        Transform.replace(p, relationList, QuestionNoRelation.class, "id");
+        return p;
+    }
+
+    /**
+     * 根据题目编号搜索相似题目
+     * @param page
+     * @param size
+     * @param keyword
+     * @return
+     */
+    public Page<QuestionNo> searchNoFulltext(int page, int size, String keyword, Integer qxCatId){
+        Page<QuestionNo> p = page(()->{
+            questionNoRelationMapper.searchNoFulltext(keyword, qxCatId);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, QuestionNo.class, "id");
+
+        // 获取详细数据
+        List<QuestionNo> list = select(ids);
+        Transform.replace(p, list, QuestionNo.class, "id");
+        return p;
+    }
+
+    /**
      * 获取结构模块下的题目列表: 按序号排列
      * @param module
      * @param structId
@@ -345,6 +393,14 @@ public class QuestionNoService extends AbstractService {
     }
 
     /**
+     * 累加收藏记录到questionNo
+     * @param question
+     */
+    public void accumulationCollect(UserCollectQuestion question, int collect){
+        questionNoRelationMapper.accumulationCollect(question.getQuestionNoId(), collect);
+    }
+
+    /**
      * 根据试卷分组获取统计信息
      * @param questionNoIdsMap
      * @return

+ 9 - 4
server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java

@@ -8,10 +8,7 @@ import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.SentenceQuestionMapper;
-import com.qxgmat.data.dao.entity.Manager;
-import com.qxgmat.data.dao.entity.Question;
-import com.qxgmat.data.dao.entity.SentenceQuestion;
-import com.qxgmat.data.dao.entity.UserQuestion;
+import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.relation.SentenceQuestionRelationMapper;
 import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
@@ -101,6 +98,14 @@ public class SentenceQuestionService extends AbstractService {
     }
 
     /**
+     * 累加收藏记录到questionNo
+     * @param question
+     */
+    public void accumulationCollect(UserCollectQuestion question, int collect){
+        sentenceQuestionRelationMapper.accumulationCollect(question.getQuestionNoId(), collect);
+    }
+
+    /**
      * 根据题目获取总试卷统计信息
      * @param questionNoList
      * @return

+ 9 - 4
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookQuestionService.java

@@ -10,10 +10,7 @@ import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.TextbookQuestionMapper;
-import com.qxgmat.data.dao.entity.Question;
-import com.qxgmat.data.dao.entity.TextbookLibrary;
-import com.qxgmat.data.dao.entity.TextbookQuestion;
-import com.qxgmat.data.dao.entity.UserQuestion;
+import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.relation.TextbookQuestionRelationMapper;
 import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
@@ -226,6 +223,14 @@ public class TextbookQuestionService extends AbstractService {
     }
 
     /**
+     * 累加收藏记录到questionNo
+     * @param question
+     */
+    public void accumulationCollect(UserCollectQuestion question, int collect){
+        textbookQuestionRelationMapper.accumulationCollect(question.getQuestionNoId(), collect);
+    }
+
+    /**
      * 根据题目获取总试卷统计信息
      * @param questionNoList
      * @return

+ 30 - 7
server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java

@@ -11,11 +11,9 @@ import com.qxgmat.data.constants.enums.module.StructModule;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.service.extend.ExerciseService;
+import com.qxgmat.service.extend.MessageExtendService;
 import com.qxgmat.service.extend.SentenceService;
-import com.qxgmat.service.inline.ExerciseStructService;
-import com.qxgmat.service.inline.QuestionNoService;
-import com.qxgmat.service.inline.SentenceQuestionService;
-import com.qxgmat.service.inline.SettingService;
+import com.qxgmat.service.inline.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -47,6 +45,18 @@ public class AsyncTask {
     @Autowired
     private SettingService settingService;
 
+    @Autowired
+    private TextbookLibraryService textbookLibraryService;
+
+    @Autowired
+    private CourseDataService courseDataService;
+
+    @Autowired
+    private CourseDataHistoryService courseDataHistoryService;
+
+    @Autowired
+    private MessageExtendService messageExtendService;
+
     @Async
     public void autoExercisePaper() {
         logger.info("自动练习组卷:顺序,考点,难易度");
@@ -228,12 +238,25 @@ public class AsyncTask {
     }
 
     @Async
-    public void postTextbookToEmail(){
+    public void postTextbookUpdate(){
         logger.info("发布机经:发送到订阅用户邮箱");
         long start = System.currentTimeMillis();
-        // todo 获取订阅用户及其邮箱
-
+        TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+        // todo 获取订阅用户
+        // messageExtendService.sendTextbookUpdate(user, textbookLibrary);
         long end = System.currentTimeMillis();
         logger.info("发布机经,耗时:" + (end - start) + "毫秒");
     }
+
+    @Async
+    public void postDataUpdate(Integer dataHistoryId){
+        logger.info("资料更新");
+        long start = System.currentTimeMillis();
+        CourseDataHistory history = courseDataHistoryService.get(dataHistoryId);
+        CourseData courseData = courseDataService.get(history.getDataId());
+        // todo 获取订阅用户
+        // messageExtendService.sendDataUpdate(user, courseData, history);
+        long end = System.currentTimeMillis();
+        logger.info("资料更新,耗时:" + (end - start) + "毫秒");
+    }
 }

+ 6 - 0
server/gateway-api/src/main/java/com/qxgmat/task/ScheduledTask.java

@@ -12,6 +12,7 @@ import com.qxgmat.data.dao.entity.User;
 import com.qxgmat.data.relation.entity.UserPrepareRelation;
 import com.qxgmat.help.WechatHelp;
 import com.qxgmat.service.UsersService;
+import com.qxgmat.service.extend.MessageExtendService;
 import com.qxgmat.service.inline.MessageTemplateService;
 import com.qxgmat.service.inline.SettingService;
 import org.slf4j.Logger;
@@ -48,6 +49,9 @@ public class ScheduledTask {
     @Autowired
     private MessageTemplateService messageTemplateService;
 
+    @Autowired
+    private MessageExtendService messageExtendService;
+
     /**
      * cron表达式:* * * * * *(共6位,使用空格隔开,具体如下)
      * cron表达式:*(秒0-59) *(分钟0-59) *(小时0-23) *(日期1-31) *(月份1-12或是JAN-DEC) *(星期1-7或是SUN-SAT)
@@ -156,6 +160,8 @@ public class ScheduledTask {
     // 每小时判断发送预习作业消息
     @Scheduled(cron="0 0 * * * *")
     public void autoSendPreviewMessage(){
+
+        // messageExtendService.sendPreviewNotice(user, assign);
         logger.info("Start auto Send Preview message");
     }