Explorar o código

feat(server): 模考逻辑修改

Go %!s(int64=4) %!d(string=hai) anos
pai
achega
b8eec8122b
Modificáronse 40 ficheiros con 858 adicións e 81 borrados
  1. 0 1
      front/project/admin/routes/show/deploy/page.js
  2. 3 3
      front/project/www/routes/paper/question/page.js
  3. 33 2
      front/project/www/stores/my.js
  4. 3 2
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/PaperOrigin.java
  5. 17 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/QuestionNoModule.java
  6. 70 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/User.java
  7. 12 12
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserNoteCourse.java
  8. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java
  9. 5 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserMapper.xml
  10. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserNoteCourseMapper.xml
  11. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPaperMapper.xml
  12. 1 0
      server/data/src/main/java/com/qxgmat/data/relation/ExaminationPaperRelationMapper.java
  13. 4 0
      server/data/src/main/java/com/qxgmat/data/relation/UserReportRelationMapper.java
  14. 15 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExaminationPaperRelationMapper.xml
  15. 12 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExercisePaperRelationMapper.xml
  16. 36 6
      server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewAssignRelationMapper.xml
  17. 12 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookPaperRelationMapper.xml
  18. 25 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserReportRelationMapper.xml
  19. 80 3
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  20. 69 12
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  21. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserPaperBaseExtendDto.java
  22. 47 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskCourseDto.java
  23. 1 1
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskDto.java
  24. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserNoteCourseDto.java
  25. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserTextbookFeedbackDto.java
  26. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/MyDto.java
  27. 30 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExaminationPaperDto.java
  28. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionDetailDto.java
  29. 26 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteCourseService.java
  30. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  31. 19 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  32. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/annotation/InitPaper.java
  33. 40 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java
  34. 12 2
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java
  35. 28 5
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  36. 1 11
      server/gateway-api/src/main/java/com/qxgmat/service/extend/PreviewService.java
  37. 60 6
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  38. 10 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseService.java
  39. 29 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseService.java
  40. 13 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java

+ 0 - 1
front/project/admin/routes/show/deploy/page.js

@@ -11,7 +11,6 @@ import { System } from '../../../stores/system';
 export default class extends Page {
   constructor(props) {
     super(props);
-    this.state.tab = 'qx_cat';
     this.vipList = ServiceParamMap.vip;
   }
 

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

@@ -284,13 +284,13 @@ export default class extends Page {
         </div>
         <div className="center">
           <AnswerButton className="item" onClick={() => this.setState({ noteModal: true })}>笔记</AnswerButton>
-          <AnswerButton className="item" onClick={() => {
-            if (questionStatus) {
+          {questionStatus >= 0 && <AnswerButton className="item" onClick={() => {
+            if (questionStatus > 0) {
               this.setState({ askModal: true });
             } else {
               this.setState({ askFailModal: true });
             }
-          }}>提问</AnswerButton>
+          }}>提问</AnswerButton>}
           <AnswerButton className="item" onClick={() => this.setState({ feedbackModal: true })}>纠错</AnswerButton>
         </div>
         <div className="right">

+ 33 - 2
front/project/www/stores/my.js

@@ -170,7 +170,7 @@ export default class MyStore extends BaseStore {
   }
 
   /**
-   * 更新笔记
+   * 更新题目笔记
    * @param {*} questionModule
    * @param {*} questionNoId
    * @param {*} content
@@ -184,6 +184,16 @@ export default class MyStore extends BaseStore {
   }
 
   /**
+   * 更新课程笔记
+   * @param {*} courseId
+   * @param {*} courseNoId
+   * @param {*} content
+   */
+  updateCourseNote(courseId, courseNoId, content) {
+    return this.apiPut('/my/note/course', { courseId, courseNoId, content });
+  }
+
+  /**
    * 获取笔记列表
    * @param {*} questionModule
    * @param {*} questionType
@@ -214,7 +224,7 @@ export default class MyStore extends BaseStore {
   }
 
   /**
-   * 添加提问
+   * 添加题目提问
    * @param {*} target
    * @param {*} questionModule
    * @param {*} questionNoId
@@ -225,6 +235,17 @@ export default class MyStore extends BaseStore {
   }
 
   /**
+   * 添加课程提问
+   * @param {*} courseId
+   * @param {*} courseNoId
+   * @param {*} position
+   * @param {*} content
+   */
+  addCourseAsk(courseId, courseNoId, position, content) {
+    return this.apiPost('/my/ask/course', { courseId, courseNoId, position, content });
+  }
+
+  /**
    * 添加题目勘误
    * @param {*} moduleId
    * @param {*} title
@@ -247,6 +268,16 @@ export default class MyStore extends BaseStore {
   addErrorData(moduleId, title, position, originContent, content) {
     return this.apiPost('/my/feedback/error/question', { moduleId, title, position, originContent, content });
   }
+
+  /**
+   * 添加机经反馈
+   * @param {*} topicId
+   * @param {*} target
+   * @param {*} content
+   */
+  addTextbookFeedback(topicId, target, content) {
+    return this.apiPost('/my/feedback/textbook', { topicId, target, content });
+  }
 }
 
 export const My = new MyStore({ key: 'my' });

+ 3 - 2
server/data/src/main/java/com/qxgmat/data/constants/enums/module/PaperOrigin.java

@@ -4,11 +4,12 @@ package com.qxgmat.data.constants.enums.module;
 public enum PaperOrigin {
     EXERCISE("exercise"),
     EXAMINATION("examination"),
+    TEXTBOOK("textbook"),
+    SENTENCE("sentence"),
+
     COLLECT("collect"),
     ERROR("error"),
     PREVIEW("preview"),
-    TEXTBOOK("textbook"),
-    SENTENCE("sentence"),
     ;
     public String key;
     private PaperOrigin(String key){

+ 17 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/module/QuestionNoModule.java

@@ -0,0 +1,17 @@
+package com.qxgmat.data.constants.enums.module;
+
+public enum QuestionNoModule {
+    EXERCISE("exercise"),
+    EXAMINATION("examination"),
+    ;
+    public String key;
+    private QuestionNoModule(String key){
+        this.key = key;
+    }
+
+    public static QuestionNoModule ValueOf(String name){
+        if (name == null) return null;
+        return QuestionNoModule.valueOf(name.toUpperCase());
+    }
+
+}

+ 70 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/User.java

@@ -190,6 +190,18 @@ public class User implements Serializable {
     private Integer inviteNumber;
 
     /**
+     * 半价机经券
+     */
+    @Column(name = "`textbook_half`")
+    private Integer textbookHalf;
+
+    /**
+     * 千行cat次数
+     */
+    @Column(name = "`qx_cat`")
+    private Integer qxCat;
+
+    /**
      * 注册ip
      */
     @Column(name = "`register_ip`")
@@ -793,6 +805,42 @@ public class User implements Serializable {
     }
 
     /**
+     * 获取半价机经券
+     *
+     * @return textbook_half - 半价机经券
+     */
+    public Integer getTextbookHalf() {
+        return textbookHalf;
+    }
+
+    /**
+     * 设置半价机经券
+     *
+     * @param textbookHalf 半价机经券
+     */
+    public void setTextbookHalf(Integer textbookHalf) {
+        this.textbookHalf = textbookHalf;
+    }
+
+    /**
+     * 获取千行cat次数
+     *
+     * @return qx_cat - 千行cat次数
+     */
+    public Integer getQxCat() {
+        return qxCat;
+    }
+
+    /**
+     * 设置千行cat次数
+     *
+     * @param qxCat 千行cat次数
+     */
+    public void setQxCat(Integer qxCat) {
+        this.qxCat = qxCat;
+    }
+
+    /**
      * 获取注册ip
      *
      * @return register_ip - 注册ip
@@ -987,6 +1035,8 @@ public class User implements Serializable {
         sb.append(", inviteCode=").append(inviteCode);
         sb.append(", totalMoney=").append(totalMoney);
         sb.append(", inviteNumber=").append(inviteNumber);
+        sb.append(", textbookHalf=").append(textbookHalf);
+        sb.append(", qxCat=").append(qxCat);
         sb.append(", registerIp=").append(registerIp);
         sb.append(", registerCity=").append(registerCity);
         sb.append(", latestLoginIp=").append(latestLoginIp);
@@ -1318,6 +1368,26 @@ public class User implements Serializable {
         }
 
         /**
+         * 设置半价机经券
+         *
+         * @param textbookHalf 半价机经券
+         */
+        public Builder textbookHalf(Integer textbookHalf) {
+            obj.setTextbookHalf(textbookHalf);
+            return this;
+        }
+
+        /**
+         * 设置千行cat次数
+         *
+         * @param qxCat 千行cat次数
+         */
+        public Builder qxCat(Integer qxCat) {
+            obj.setQxCat(qxCat);
+            return this;
+        }
+
+        /**
          * 设置注册ip
          *
          * @param registerIp 注册ip

+ 12 - 12
server/data/src/main/java/com/qxgmat/data/dao/entity/UserNoteCourse.java

@@ -35,8 +35,8 @@ public class UserNoteCourse implements Serializable {
     @Column(name = "`update_time`")
     private Date updateTime;
 
-    @Column(name = "`conntent`")
-    private String conntent;
+    @Column(name = "`content`")
+    private String content;
 
     private static final long serialVersionUID = 1L;
 
@@ -137,17 +137,17 @@ public class UserNoteCourse implements Serializable {
     }
 
     /**
-     * @return conntent
+     * @return content
      */
-    public String getConntent() {
-        return conntent;
+    public String getContent() {
+        return content;
     }
 
     /**
-     * @param conntent
+     * @param content
      */
-    public void setConntent(String conntent) {
-        this.conntent = conntent;
+    public void setContent(String content) {
+        this.content = content;
     }
 
     @Override
@@ -162,7 +162,7 @@ public class UserNoteCourse implements Serializable {
         sb.append(", courseNoId=").append(courseNoId);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
-        sb.append(", conntent=").append(conntent);
+        sb.append(", content=").append(content);
         sb.append("]");
         return sb.toString();
     }
@@ -233,10 +233,10 @@ public class UserNoteCourse implements Serializable {
         }
 
         /**
-         * @param conntent
+         * @param content
          */
-        public Builder conntent(String conntent) {
-            obj.setConntent(conntent);
+        public Builder content(String content) {
+            obj.setContent(content);
             return this;
         }
 

+ 35 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java

@@ -54,6 +54,12 @@ public class UserPaper implements Serializable {
     private Integer recordId;
 
     /**
+     * 相同试卷不同编号:对应千行cat次数
+     */
+    @Column(name = "`paper_no`")
+    private Integer paperNo;
+
+    /**
      * 题目编号id列表:json
      */
     @Column(name = "`question_no_ids`")
@@ -256,6 +262,24 @@ public class UserPaper implements Serializable {
     }
 
     /**
+     * 获取相同试卷不同编号:对应千行cat次数
+     *
+     * @return paper_no - 相同试卷不同编号:对应千行cat次数
+     */
+    public Integer getPaperNo() {
+        return paperNo;
+    }
+
+    /**
+     * 设置相同试卷不同编号:对应千行cat次数
+     *
+     * @param paperNo 相同试卷不同编号:对应千行cat次数
+     */
+    public void setPaperNo(Integer paperNo) {
+        this.paperNo = paperNo;
+    }
+
+    /**
      * 获取题目编号id列表:json
      *
      * @return question_no_ids - 题目编号id列表:json
@@ -449,6 +473,7 @@ public class UserPaper implements Serializable {
         sb.append(", isAdapt=").append(isAdapt);
         sb.append(", originId=").append(originId);
         sb.append(", recordId=").append(recordId);
+        sb.append(", paperNo=").append(paperNo);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", times=").append(times);
@@ -553,6 +578,16 @@ public class UserPaper implements Serializable {
         }
 
         /**
+         * 设置相同试卷不同编号:对应千行cat次数
+         *
+         * @param paperNo 相同试卷不同编号:对应千行cat次数
+         */
+        public Builder paperNo(Integer paperNo) {
+            obj.setPaperNo(paperNo);
+            return this;
+        }
+
+        /**
          * 设置题目编号id列表:json
          *
          * @param questionNoIds 题目编号id列表:json

+ 5 - 3
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserMapper.xml

@@ -36,6 +36,8 @@
     <result column="invite_code" jdbcType="VARCHAR" property="inviteCode" />
     <result column="total_money" jdbcType="DECIMAL" property="totalMoney" />
     <result column="invite_number" jdbcType="INTEGER" property="inviteNumber" />
+    <result column="textbook_half" jdbcType="INTEGER" property="textbookHalf" />
+    <result column="qx_cat" jdbcType="INTEGER" property="qxCat" />
     <result column="register_ip" jdbcType="VARCHAR" property="registerIp" />
     <result column="register_city" jdbcType="VARCHAR" property="registerCity" />
     <result column="latest_login_ip" jdbcType="VARCHAR" property="latestLoginIp" />
@@ -55,8 +57,8 @@
     `wechat_expire_time`, `real_time`, `real_name`, `real_address`, `real_identity`, 
     `real_photo_front`, `real_photo_back`, `real_status`, `prepare_time`, `prepare_status`, 
     `prepare_goal`, `prepare_examination_time`, `prepare_score_time`, `latest_exercise`, 
-    `latest_error`, `origin_id`, `invite_code`, `total_money`, `invite_number`, `register_ip`, 
-    `register_city`, `latest_login_ip`, `latest_login_time`, `is_frozen`, `create_time`, 
-    `data_email_subscribe`, `textbook_email_subscribe`, `total_alert`
+    `latest_error`, `origin_id`, `invite_code`, `total_money`, `invite_number`, `textbook_half`, 
+    `qx_cat`, `register_ip`, `register_city`, `latest_login_ip`, `latest_login_time`, 
+    `is_frozen`, `create_time`, `data_email_subscribe`, `textbook_email_subscribe`, `total_alert`
   </sql>
 </mapper>

+ 2 - 2
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserNoteCourseMapper.xml

@@ -16,7 +16,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    <result column="conntent" jdbcType="LONGVARCHAR" property="conntent" />
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
@@ -28,6 +28,6 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `conntent`
+    `content`
   </sql>
 </mapper>

+ 2 - 1
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPaperMapper.xml

@@ -13,6 +13,7 @@
     <result column="is_adapt" jdbcType="INTEGER" property="isAdapt" />
     <result column="origin_id" jdbcType="INTEGER" property="originId" />
     <result column="record_id" jdbcType="INTEGER" property="recordId" />
+    <result column="paper_no" jdbcType="INTEGER" property="paperNo" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="times" jdbcType="INTEGER" property="times" />
@@ -29,7 +30,7 @@
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `title`, `paper_module`, `paper_origin`, `is_adapt`, `origin_id`, 
-    `record_id`, `question_no_ids`, `question_number`, `times`, `time`, `latest_time`, 
+    `record_id`, `paper_no`, `question_no_ids`, `question_number`, `times`, `time`, `latest_time`, 
     `total_time`, `total_number`, `total_correct`, `delete_time`, `is_reset`
   </sql>
 </mapper>

+ 1 - 0
server/data/src/main/java/com/qxgmat/data/relation/ExaminationPaperRelationMapper.java

@@ -13,6 +13,7 @@ public interface ExaminationPaperRelationMapper {
     List<ExercisePaper> listWithUser(
             @Param("structId") Number structId,
             @Param("userId") Number userId,
+            @Param("qxCatNo") Integer qxCatNo,
             @Param("times") Integer times
     );
 }

+ 4 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserReportRelationMapper.java

@@ -31,6 +31,10 @@ public interface UserReportRelationMapper {
             @Param("paperIds") Collection paperIds
     );
 
+    List<UserReport> listLastNoReset(
+            @Param("paperIds") Collection paperIds
+    );
+
     List<UserReportLimitRelation> statLimit(
             @Param("module") String module,
             @Param("moduleId") Integer moduleId

+ 15 - 2
server/data/src/main/java/com/qxgmat/data/relation/mapping/ExaminationPaperRelationMapper.xml

@@ -25,8 +25,16 @@
     left join `user_paper` up on ep.`id` = up.`origin_id`
       and up.`paper_origin` = 'examination'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      <if test="qxCatNo != null">
+        and up.`qx_cat_no` = #{qxCatNo,jdbcType=VARCHAR}
+      </if>
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -34,7 +42,12 @@
       and (ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR})
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
   </select>
 </mapper>

+ 12 - 2
server/data/src/main/java/com/qxgmat/data/relation/mapping/ExercisePaperRelationMapper.xml

@@ -38,7 +38,12 @@
       and up.`paper_origin` = 'exercise'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -46,7 +51,12 @@
       and (ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR})
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
     <if test="logic != null">
       and ep.`logic` = #{logic,jdbcType=VARCHAR}

+ 36 - 6
server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewAssignRelationMapper.xml

@@ -26,7 +26,12 @@
       and up.`paper_origin` = 'preview'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -34,7 +39,12 @@
       and pa.`course_id` = #{courseId,jdbcType=VARCHAR}
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
   </select>
 
@@ -50,7 +60,12 @@
       and up.`paper_origin` = 'preview'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -64,7 +79,12 @@
       </foreach>
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
   </select>
 
@@ -80,7 +100,12 @@
       and up.`paper_origin` = 'preview'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -91,7 +116,12 @@
       and pa.`course_time` = #{timeId,jdbcType=VARCHAR}
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
   </select>
 </mapper>

+ 12 - 2
server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookPaperRelationMapper.xml

@@ -26,7 +26,12 @@
       and up.`paper_origin` = 'textbook'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
       <if test="times != null">
-        and up.`times` >= #{times,jdbcType=VARCHAR}
+        <if test="times == 0">
+          and up.`times` = 0
+        </if>
+        <if test="times > 0">
+          and up.`times` >= #{times,jdbcType=VARCHAR}
+        </if>
       </if>
     </if>
     where 1
@@ -34,7 +39,12 @@
       and tp.`library_id` = #{libraryId,jdbcType=VARCHAR}
     </if>
     <if test="userId != null">
-      and up.`id` &gt; 0
+      <if test="times == 0">
+        and (up.`id` &gt; 0 or up.`id` is null)
+      </if>
+      <if test="times > 0">
+        and up.`id` &gt; 0
+      </if>
     </if>
   </select>
 </mapper>

+ 25 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserReportRelationMapper.xml

@@ -97,6 +97,31 @@
   </select>
 
   <!--
+    用户最后一次
+    https://blog.csdn.net/t_1007/article/details/52369261
+  -->
+  <select id="listLastNoReset" resultMap="IdMap">
+    select
+    SUBSTRING_INDEX(GROUP_CONCAT(ur.`id` ORDER BY ur.`create_time` desc),',',1) as `id`
+    from `user_report` ur
+    left join `user_paper` up on up.`id` = ur.`paper_id`
+    where
+    up.`id` &gt; 0
+    and ur.`paper_id` IN
+    <foreach collection="paperIds" item="item" index="index" open="(" close=")" separator=",">
+      #{item}
+    </foreach>
+
+    <!--<if test="startTime != null">-->
+    <!--and up.`createTime` &gt; #{startTime,jdbcType=VARCHAR}-->
+    <!--</if>-->
+    <!--<if test="endTime != null">-->
+    <!--and up.`createTime` &lt; #{endTime,jdbcType=VARCHAR}-->
+    <!--</if>-->
+    group by ur.`paper_id`
+  </select>
+
+  <!--
     用户限时完成的统计记录
   -->
   <select id="statLimit" resultMap="limitMap">

+ 80 - 3
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -101,6 +101,9 @@ public class MyController {
     private TextbookQuestionService textbookQuestionService;
 
     @Autowired
+    private TextbookTopicService textbookTopicService;
+
+    @Autowired
     private CourseDataService courseDataService;
 
     @Autowired
@@ -128,12 +131,21 @@ public class MyController {
     private UserNoteQuestionService userNoteQuestionService;
 
     @Autowired
+    private UserNoteCourseService userNoteCourseService;
+
+    @Autowired
     private UserAskQuestionService userAskQuestionService;
 
     @Autowired
+    private UserAskCourseService userAskCourseService;
+
+    @Autowired
     private UserFeedbackErrorService userFeedbackErrorService;
 
     @Autowired
+    private UserTextbookFeedbackService userTextbookFeedbackService;
+
+    @Autowired
     private UserQuestionService userQuestionService;
 
     @Autowired
@@ -782,7 +794,7 @@ public class MyController {
     }
 
     @RequestMapping(value = "/note/question", method = RequestMethod.PUT)
-    @ApiOperation(value = "更新笔记", notes = "更新笔记", httpMethod = "PUT")
+    @ApiOperation(value = "更新题目笔记", notes = "更新题目笔记", httpMethod = "PUT")
     public Response<Boolean> updateNoteQuestion(@RequestBody @Validated UserNoteQuestionDto dto)  {
         UserNoteQuestion entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
@@ -853,6 +865,17 @@ public class MyController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/note/course", method = RequestMethod.PUT)
+    @ApiOperation(value = "更新课程笔记", notes = "更新课程笔记", httpMethod = "PUT")
+    public Response<Boolean> updateNoteCourse(@RequestBody @Validated UserNoteQuestionDto dto)  {
+        UserNoteCourse entity = Transform.dtoToEntity(dto);
+        User user = (User) shiroHelp.getLoginUser();
+        entity.setUserId(user.getId());
+        userNoteCourseService.update(entity);
+
+        return ResponseHelp.success(true);
+    }
+
     @RequestMapping(value = "/report/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取报告列表", notes = "获取报告列表", httpMethod = "GET")
     public Response<PageMessage<UserPaperDto>> listReport(
@@ -881,36 +904,76 @@ public class MyController {
     }
 
     @RequestMapping(value = "/ask/question", method = RequestMethod.POST)
-    @ApiOperation(value = "添加提问", notes = "添加提问", httpMethod = "POST")
-    public Response<Boolean> addAskQuestion(@RequestBody @Validated UserAskDto dto)  {
+    @ApiOperation(value = "添加题目提问", notes = "添加题目提问", httpMethod = "POST")
+    public Response<Boolean> addAskQuestion(@RequestBody @Validated UserAskQuestionDto dto)  {
         UserAskQuestion entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());
+        Question question;
         switch (QuestionModule.ValueOf(dto.getQuestionModule())){
             case BASE:
                 entity.setQuestionModule(QuestionModule.BASE.key);
                 QuestionNo questionNo = questionNoService.get(dto.getQuestionNoId());
                 entity.setQuestionId(questionNo.getQuestionId());
                 entity.setQuestionNoId(questionNo.getId());
+
+                question = questionService.get(questionNo.getQuestionId());
                 break;
             case SENTENCE:
                 entity.setQuestionModule(QuestionModule.SENTENCE.key);
                 SentenceQuestion sentenceQuestion = sentenceQuestionService.get(dto.getQuestionNoId());
                 entity.setQuestionId(sentenceQuestion.getQuestionId());
                 entity.setQuestionNoId(sentenceQuestion.getId());
+
+                question = questionService.get(sentenceQuestion.getQuestionId());
                 break;
             case TEXTBOOK:
                 entity.setQuestionModule(QuestionModule.SENTENCE.key);
                 TextbookQuestion textbookQuestion = textbookQuestionService.get(dto.getQuestionNoId());
                 entity.setQuestionId(textbookQuestion.getQuestionId());
                 entity.setQuestionNoId(textbookQuestion.getId());
+
+                question = questionService.get(textbookQuestion.getQuestionId());
                 break;
+            default:
+                throw new ParameterException("题目模块错误");
+        }
+
+        UserQuestion userQuestion = userQuestionService.get(dto.getUserQuestionId());
+        UserReport userReport = userReportService.get(userQuestion.getReportId());
+        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){
+            // 绑定提问权限
+            entity.setRecordId(recordId);
+        }else{
+            // todo 判断题目是否有提问权限
         }
         userAskQuestionService.add(entity);
 
         return ResponseHelp.success(true);
     }
 
+    @RequestMapping(value = "/ask/course", method = RequestMethod.POST)
+    @ApiOperation(value = "添加课程提问", notes = "添加课程提问", httpMethod = "POST")
+    public Response<Boolean> addAskCourse(@RequestBody @Validated UserAskCourseDto dto)  {
+        UserAskCourse entity = Transform.dtoToEntity(dto);
+        User user = (User) shiroHelp.getLoginUser();
+        entity.setUserId(user.getId());
+
+        UserCourse userCourse = courseExtendService.userCourse(user.getId(), dto.getCourseId());
+        if (userCourse != null){
+            // 绑定提问权限
+            entity.setRecordId(userCourse.getRecordId());
+        }else{
+            throw new ParameterException("课程需开通后才能提问");
+        }
+        userAskCourseService.add(entity);
+
+        return ResponseHelp.success(true);
+    }
+
     @RequestMapping(value = "/feedback/error/question", method = RequestMethod.POST)
     @ApiOperation(value = "添加题目勘误", notes = "添加勘误", httpMethod = "POST")
     public Response<Boolean> addFeedbackErrorQuestion(@RequestBody @Validated UserFeedbackErrorDto dto)  {
@@ -937,6 +1000,20 @@ public class MyController {
         return ResponseHelp.success(true);
     }
 
+    @RequestMapping(value = "/feedback/textbook", method = RequestMethod.POST)
+    @ApiOperation(value = "添加机经反馈", notes = "添加机经反馈", httpMethod = "POST")
+    public Response<Boolean> addFeedbackTextbook(@RequestBody @Validated UserTextbookFeedbackDto dto)  {
+        UserTextbookFeedback entity = Transform.dtoToEntity(dto);
+        User user = (User) shiroHelp.getLoginUser();
+        TextbookTopic topic = textbookTopicService.get(dto.getTopicId());
+        entity.setUserId(user.getId());
+        entity.setStatus(0);
+        entity.setLibraryId(topic.getLibraryId());
+        userTextbookFeedbackService.add(entity);
+
+        return ResponseHelp.success(true);
+    }
+
     @RequestMapping(value = "/data/history", method = RequestMethod.GET)
     @ApiOperation(value = "资料更新记录", httpMethod = "GET")
     public Response<PageMessage<CourseDataHistoryInfoDto>> listDataHistory(

+ 69 - 12
server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java

@@ -4,11 +4,10 @@ package com.qxgmat.controller.api;
 import com.alibaba.fastjson.JSONObject;
 import com.nuliji.tools.*;
 import com.nuliji.tools.exception.ParameterException;
+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.PaperOrigin;
-import com.qxgmat.data.constants.enums.module.QuestionModule;
-import com.qxgmat.data.constants.enums.module.StructModule;
+import com.qxgmat.data.constants.enums.module.*;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
@@ -18,10 +17,7 @@ import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.*;
-import com.qxgmat.service.extend.ExaminationService;
-import com.qxgmat.service.extend.ExerciseService;
-import com.qxgmat.service.extend.PreviewService;
-import com.qxgmat.service.extend.QuestionFlowService;
+import com.qxgmat.service.extend.*;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -81,6 +77,9 @@ public class QuestionController {
     private TextbookPaperService textbookPaperService;
 
     @Autowired
+    private TextbookLibraryService textbookLibraryService;
+
+    @Autowired
     private UserQuestionService userQuestionService;
 
     @Autowired
@@ -113,6 +112,8 @@ public class QuestionController {
     @Autowired
     private QuestionFlowService questionFlowService;
 
+    @Autowired
+    private CourseExtendService courseExtendService;
 
     @RequestMapping(value = "/exercise/progress", method = RequestMethod.GET)
     @ApiOperation(value = "练习进度", httpMethod = "GET")
@@ -283,7 +284,7 @@ public class QuestionController {
             Transform.combine(pr, paperList, UserExercisePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
-            Transform.combine(pr, userPaperMap, UserExercisePaperDto.class, "id", "paperId");
+            Transform.combine(pr, userPaperMap, UserExercisePaperDto.class, "id", "userPaperId");
 
             // 获取最后一次作业结果
             Collection paperIds = Transform.getIds(paperList, UserPaper.class, "id");
@@ -354,23 +355,48 @@ public class QuestionController {
             @RequestParam(required = false)  Integer times,
             HttpSession session) {
         User user = (User) shiroHelp.getLoginUser();
-        PageResult<ExaminationPaper> p = examinationService.list(page, size, structId, user != null ? user.getId():null, times);
+        ExaminationStruct struct = examinationStructService.get(structId);
+        ServiceKey serviceKey = ServiceKey.ValueOf(struct.getExtend());
+        PageResult<ExaminationPaper> p = examinationService.list(page, size, structId, user != null ? user.getId():null, serviceKey == ServiceKey.QX_CAT && user != null ? user.getQxCat() : null, times);
 
         List<UserExaminationPaperDto> pr = Transform.convert(p, UserExaminationPaperDto.class);
 
         if (user != null){
             // 获取做题记录
             Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
-            List<UserPaper> paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXAMINATION, ids, null);
+            List<UserPaper> paperList;
+            if (serviceKey == ServiceKey.QX_CAT){
+                // cat模考,根据情况获取对应试题列表
+                paperList = userPaperService.listWithCat(user.getId(), ids, user.getQxCat());
+            }else{
+                paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXAMINATION, ids, null);
+            }
             Transform.combine(pr, paperList, UserExaminationPaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
-            Transform.combine(pr, userPaperMap, UserExaminationPaperDto.class, "id", "paperId");
+            Transform.combine(pr, userPaperMap, UserExaminationPaperDto.class, "id", "userPaperId");
 
-            // 获取最后一次作业结果
+            // 获取最后一次结果
             Collection paperIds = Transform.getIds(paperList, UserPaper.class, "id");
             List<UserReport> reportList = userReportService.listWithLater(paperIds);
             Transform.combine(pr, reportList, UserExaminationPaperDto.class, "id", "report", UserReport.class, "paperId", UserReportExtendDto.class);
+
+            if (serviceKey == ServiceKey.QX_CAT && user.getQxCat() > 0){
+                // 获取上一遍模考成绩
+                UserService userService = userServiceService.getService(user.getId(), serviceKey);
+                if (userService.getIsReset() > 0){
+                    List<UserPaper> prevPaperList = userPaperService.listWithCat(user.getId(), ids, user.getQxCat() - 1);
+                    Transform.combine(pr, prevPaperList, UserExaminationPaperDto.class, "id", "prevPaper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
+                    // 绑定userPaperId,用于关联report
+                    Map prevUserPaperMap = Transform.getMap(prevPaperList, UserPaper.class, "originId", "id");
+                    Transform.combine(pr, prevUserPaperMap, UserExaminationPaperDto.class, "id", "prevUserPaperId");
+
+                    // 获取最后一次结果
+                    Collection prevPaperIds = Transform.getIds(prevPaperList, UserPaper.class, "id");
+                    List<UserReport> prevReportList = userReportService.listWithLaterNoReset(prevPaperIds);
+                    Transform.combine(pr, prevReportList, UserExaminationPaperDto.class, "id", "prevReport", UserReport.class, "paperId", UserReportExtendDto.class);
+                }
+            }
         }
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
@@ -440,6 +466,37 @@ public class QuestionController {
                 dto.setQuestionNo(Transform.convert(textbookQuestion, QuestionNoExtendDto.class));
                 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{
+            // 获取基本当前权限
+            switch(origin){
+                case EXAMINATION:
+                    ExaminationPaper examinationPaper = examinationPaperService.get(userReport.getOriginId());
+                    ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree());
+                    dto.setQuestionStatus(examinationStruct.getQuestionStatus());
+                    break;
+                case EXERCISE:
+                    ExercisePaper exercisePaper = exercisePaperService.get(userReport.getOriginId());
+                    ExerciseStruct exerciseStruct = exerciseStructService.get(exercisePaper.getStructFour());
+                    dto.setQuestionStatus(exerciseStruct.getQuestionStatus());
+                    break;
+                case TEXTBOOK:
+                    TextbookQuestion textbookQuestion = textbookQuestionService.get(userQuestion.getQuestionNoId());
+                    TextbookLibrary textbookLibrary = textbookLibraryService.get(textbookQuestion.getLibraryId());
+                    dto.setQuestionStatus(textbookLibrary.getQuestionStatus());
+                    break;
+                case PREVIEW:
+                    // 上面questionRelationCourse包括了,不会执行到
+                default:
+                    // 自由组卷,不提供提问显示
+                    dto.setQuestionStatus(-1);
+            }
+        }
+
 
         return ResponseHelp.success(dto);
     }

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserPaperBaseExtendDto.java

@@ -13,6 +13,8 @@ public class UserPaperBaseExtendDto {
 
     private Integer times;
 
+    private Integer paperNo;
+
     private Integer questionNumber;
 
     private Date latestTime;
@@ -48,4 +50,12 @@ public class UserPaperBaseExtendDto {
     public void setLatestTime(Date latestTime) {
         this.latestTime = latestTime;
     }
+
+    public Integer getPaperNo() {
+        return paperNo;
+    }
+
+    public void setPaperNo(Integer paperNo) {
+        this.paperNo = paperNo;
+    }
 }

+ 47 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskCourseDto.java

@@ -0,0 +1,47 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserAskCourse;
+
+@Dto(entity = UserAskCourse.class)
+public class UserAskCourseDto {
+    private Integer courseId;
+
+    private Integer courseNoId;
+
+    private String position;
+
+    private String content;
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public Integer getCourseNoId() {
+        return courseNoId;
+    }
+
+    public void setCourseNoId(Integer courseNoId) {
+        this.courseNoId = courseNoId;
+    }
+
+    public String getPosition() {
+        return position;
+    }
+
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskDto.java

@@ -5,7 +5,7 @@ import com.qxgmat.data.dao.entity.UserAskQuestion;
 import com.qxgmat.data.dao.entity.UserNoteQuestion;
 
 @Dto(entity = UserAskQuestion.class)
-public class UserAskDto {
+public class UserAskQuestionDto {
     private Integer userQuestionId;
 
     private String target;

+ 37 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserNoteCourseDto.java

@@ -0,0 +1,37 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserNoteCourse;
+
+@Dto(entity = UserNoteCourse.class)
+public class UserNoteCourseDto {
+    private Integer courseId;
+
+    private Integer courseNoId;
+
+    private String content;
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public Integer getCourseNoId() {
+        return courseNoId;
+    }
+
+    public void setCourseNoId(Integer courseNoId) {
+        this.courseNoId = courseNoId;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

+ 37 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserTextbookFeedbackDto.java

@@ -0,0 +1,37 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserTextbookFeedback;
+
+@Dto(entity = UserTextbookFeedback.class)
+public class UserTextbookFeedbackDto {
+    private Integer topicId;
+
+    private String target;
+
+    private String content;
+
+    public Integer getTopicId() {
+        return topicId;
+    }
+
+    public void setTopicId(Integer topicId) {
+        this.topicId = topicId;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/MyDto.java

@@ -17,6 +17,8 @@ public class MyDto extends UserDto {
 
     private String inviteCode;
 
+    private Integer qxCat;
+
     private Boolean bindWechat;
 
     private Boolean bindReal;
@@ -140,4 +142,12 @@ public class MyDto extends UserDto {
     public void setId(Integer id) {
         this.id = id;
     }
+
+    public Integer getQxCat() {
+        return qxCat;
+    }
+
+    public void setQxCat(Integer qxCat) {
+        this.qxCat = qxCat;
+    }
 }

+ 30 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExaminationPaperDto.java

@@ -20,6 +20,12 @@ public class UserExaminationPaperDto {
 
     private Integer userPaperId;
 
+    private UserPaperBaseExtendDto prevPaper;
+
+    private UserReportExtendDto prevReport;
+
+    private Integer prevUserPaperId;
+
     public PaperStat getStat() {
         return stat;
     }
@@ -67,4 +73,28 @@ public class UserExaminationPaperDto {
     public void setTitle(Integer title) {
         this.title = title;
     }
+
+    public UserPaperBaseExtendDto getPrevPaper() {
+        return prevPaper;
+    }
+
+    public void setPrevPaper(UserPaperBaseExtendDto prevPaper) {
+        this.prevPaper = prevPaper;
+    }
+
+    public UserReportExtendDto getPrevReport() {
+        return prevReport;
+    }
+
+    public void setPrevReport(UserReportExtendDto prevReport) {
+        this.prevReport = prevReport;
+    }
+
+    public Integer getPrevUserPaperId() {
+        return prevUserPaperId;
+    }
+
+    public void setPrevUserPaperId(Integer prevUserPaperId) {
+        this.prevUserPaperId = prevUserPaperId;
+    }
 }

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionDetailDto.java

@@ -45,6 +45,8 @@ public class UserQuestionDetailDto {
 
     private List<QuestionBaseExtendDto> associations;
 
+    private Integer questionStatus;
+
     public Integer getId() {
         return id;
     }
@@ -188,4 +190,12 @@ public class UserQuestionDetailDto {
     public void setStageNo(Integer stageNo) {
         this.stageNo = stageNo;
     }
+
+    public Integer getQuestionStatus() {
+        return questionStatus;
+    }
+
+    public void setQuestionStatus(Integer questionStatus) {
+        this.questionStatus = questionStatus;
+    }
 }

+ 26 - 0
server/gateway-api/src/main/java/com/qxgmat/service/UserNoteCourseService.java

@@ -22,6 +22,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 import java.util.Map;
 
@@ -32,6 +33,31 @@ public class UserNoteCourseService extends AbstractService {
     @Resource
     private UserNoteCourseMapper userNoteCourseMapper;
 
+    /**
+     * 更新用户笔记:没有则添加
+     * @param note
+     * @return
+     */
+    @Transactional
+    public UserNoteCourse update(UserNoteCourse note){
+        Example example = new Example(UserNoteCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", note.getUserId())
+                        .andEqualTo("courseId", note.getCourseId())
+                        .andEqualTo("courseNoId", note.getCourseNoId())
+        );
+        UserNoteCourse in = one(userNoteCourseMapper, example);
+        Date now = new Date();
+        if(in == null){
+            // 按实际更新更改更新时间
+            return add(note);
+        }else{
+            note.setId(in.getId());
+            return edit(note);
+        }
+    }
+
     public UserNoteCourse add(UserNoteCourse message){
         int result = insert(userNoteCourseMapper, message);
         message = one(userNoteCourseMapper, message.getId());

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java

@@ -111,7 +111,7 @@ public class UserNoteQuestionService extends AbstractService {
     @Transactional
     public UserNoteQuestion update(UserNoteQuestion note){
 
-        Example example = new Example(UserCollectQuestion.class);
+        Example example = new Example(UserNoteQuestion.class);
         example.and(
                 example.createCriteria()
                         .andEqualTo("userId", note.getUserId())

+ 19 - 0
server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java

@@ -96,6 +96,25 @@ public class UserPaperService extends AbstractService {
     }
 
     /**
+     * 获取用户cat做题记录
+     * @param userId
+     * @param ids
+     * @param no
+     * @return
+     */
+    public List<UserPaper> listWithCat(Integer userId, Collection ids, Integer no){
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("paperOrigin", PaperOrigin.EXAMINATION.key)
+                        .andIn("originId", ids)
+                        .andEqualTo("qxCatNo", no)
+        );
+        return select(userPaperMapper, example);
+    }
+
+    /**
      * 获取用户做题组卷
      * @param userId
      * @param origin

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/service/annotation/InitPaper.java

@@ -8,5 +8,5 @@ import com.qxgmat.data.dao.entity.UserPaper;
  */
 @FunctionalInterface
 public interface InitPaper {
-    void callback(UserPaper userPaper, Integer originId);
+    UserPaper callback(UserPaper userPaper, Integer originId);
 }

+ 40 - 1
server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java

@@ -1,17 +1,22 @@
 package com.qxgmat.service.extend;
 
 import com.nuliji.tools.Tools;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.module.ProductType;
 import com.qxgmat.data.dao.entity.Course;
+import com.qxgmat.data.dao.entity.UserCourse;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import com.qxgmat.service.inline.CourseService;
 import com.qxgmat.service.inline.UserCourseRecordService;
+import com.qxgmat.service.inline.UserCourseService;
 import com.qxgmat.service.inline.UserOrderRecordService;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 
-import java.util.Date;
+import java.util.*;
 
 @Service
 public class CourseExtendService {
@@ -20,6 +25,9 @@ public class CourseExtendService {
     private CourseService courseService;
 
     @Autowired
+    private UserCourseService userCourseService;
+
+    @Autowired
     private UserOrderRecordService userOrderRecordService;
 
     @Autowired
@@ -71,4 +79,35 @@ public class CourseExtendService {
         UserRecordStatRelation record = userCourseRecordService.statAvg(startTime.toString(), endTime.toString());
         return record == null ? record.getUserTime() : 0;
     }
+
+    public UserCourse userCourse(Integer userId, Integer courseId){
+        return userCourseService.getCourse(userId, courseId);
+    }
+
+    /**
+     * 根据题目类型获取课程信息
+     * @param questionType
+     * @return
+     */
+    public Integer questionRelationCourse(Integer userId, QuestionType questionType){
+        QuestionSubject subject = QuestionSubject.FromType(questionType);
+        List<Course> courseList = courseService.listByExtend(questionType.key, subject.key);
+        if (courseList.size()==0)return null;
+        Collection ids = Transform.getIds(courseList, Course.class, "id");
+        List<UserCourse> userCourseList = userCourseService.listByCourse(userId, ids);
+        if (userCourseList.size() == 0) return null;
+        if (userCourseList.size() == 1) return userCourseList.get(0).getRecordId();
+        // 获取回答时间最小的记录
+        Collection recordIds = Transform.getIds(userCourseList, UserCourse.class, "recordId");
+        List<UserOrderRecord> userOrderRecordList =  userOrderRecordService.select(recordIds);
+        int min = 0;
+        Integer minId = null;
+        for(UserOrderRecord userOrderRecord : userOrderRecordList){
+            if (minId == null || min > userOrderRecord.getAskTime()){
+                min = userOrderRecord.getAskTime();
+                minId = userOrderRecord.getId();
+            }
+        }
+        return minId;
+    }
 }

+ 12 - 2
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java

@@ -21,6 +21,7 @@ import com.qxgmat.data.relation.UserReportRelationMapper;
 import com.qxgmat.data.relation.entity.QuestionDifficultRelation;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.service.UserPaperService;
+import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.*;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -60,6 +61,9 @@ public class ExaminationService extends AbstractService {
     private UserReportService userReportService;
 
     @Resource
+    private UsersService usersService;
+
+    @Resource
     private ExaminationPaperRelationMapper examinationPaperRelationMapper;
 
     /**
@@ -96,6 +100,7 @@ public class ExaminationService extends AbstractService {
     public ExaminationStruct addPaper(ExaminationStruct entity){
         entity = examinationStructService.add(entity);
         if (entity.getLevel() == 3){
+            // 添加2份paper
             ExaminationPaper paper = examinationPaperService.add(ExaminationPaper.builder()
                     .isAdapt(entity.getIsAdapt())
                     .structTwo(entity.getParentId())
@@ -188,9 +193,9 @@ public class ExaminationService extends AbstractService {
      * @param times
      * @return
      */
-    public PageResult<ExaminationPaper> list(int page, int size, Number structId, Number userId, Integer times){
+    public PageResult<ExaminationPaper> list(int page, int size, Number structId, Number userId, Integer qxCatNo, Integer times){
         Page<ExaminationPaper> p = page(()->{
-            examinationPaperRelationMapper.listWithUser(structId, userId, times);
+            examinationPaperRelationMapper.listWithUser(structId, userId, qxCatNo, times);
         },page, size);
 
         Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
@@ -200,6 +205,8 @@ public class ExaminationService extends AbstractService {
         return new PageResult<>(list, p.getTotal());
     }
 
+
+
     /**
      * cat模考是否已经完成
      * @param userId
@@ -246,6 +253,9 @@ public class ExaminationService extends AbstractService {
                 }
             }
         }
+        // 增加用户cat计数
+        User user = usersService.get(userId);
+        usersService.edit(User.builder().id(userId).qxCat(user.getQxCat() + 1).build());
         return userPaperService.reset(paperIds, userId);
     }
 

+ 28 - 5
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -229,8 +229,15 @@ public class OrderFlowService {
                 }
             }
             BigDecimal money = BigDecimal.valueOf(toolsService.getServicePrice(checkout.getService(), checkout.getParam()));
-            checkout.setMoney(money);
             checkout.setOriginMoney(money);
+            ServiceKey serviceKey = ServiceKey.ValueOf(checkout.getService());
+            if (serviceKey == ServiceKey.TEXTBOOK){
+                // 是否存在半价机经券
+                User user = usersService.get(checkout.getId());
+                checkout.setMoney(user.getTextbookHalf() > 0 ? money.divide(BigDecimal.valueOf(2), BigDecimal.ROUND_HALF_UP):money);
+            }else{
+                checkout.setMoney(money);
+            }
             return checkout;
         }));
 
@@ -252,6 +259,15 @@ public class OrderFlowService {
             BigDecimal money = order.getMoney();
             BigDecimal originMoney = order.getOriginMoney();
             for(UserOrderCheckout checkout:userOrderCheckoutList){
+                ServiceKey serviceKey = ServiceKey.ValueOf(checkout.getService());
+
+                if (serviceKey == ServiceKey.TEXTBOOK){
+                    // 是否存在半价机经券
+                    if (!checkout.getMoney().equals(checkout.getOriginMoney())){
+                        JSONObject promote = order.getPromote();
+                        promote.put("textbook", "half");
+                    }
+                }
                 money = money.add(checkout.getMoney());
                 originMoney = originMoney.add(checkout.getMoney());
             }
@@ -296,9 +312,8 @@ public class OrderFlowService {
                 money = money.add(promoteVideoMoney);
 
                 // 添加视频优惠记录
-                JSONObject promoteVideo = new JSONObject();
                 JSONObject promote = order.getPromote();
-                promote.put("video", promoteVideo);
+                promote.put("video", percent);
             }else{
                 courseMoney = courseMoney.add(videoMoney);
                 money = money.add(videoMoney);
@@ -370,6 +385,14 @@ public class OrderFlowService {
                 Date endTime = Tools.addMonth(startTime, serviceKey.expireDay);
                 record.setStartTime(startTime);
                 record.setEndTime(endTime);
+                // 如果使用半价优惠券,则扣除
+                if (serviceKey == ServiceKey.TEXTBOOK){
+                    User user = usersService.get(record.getUserId());
+                    if (user.getTextbookHalf() == 0) {
+                        // todo 支付存在问题
+                    }
+                    usersService.edit(User.builder().id(user.getId()).textbookHalf(user.getTextbookHalf() - 1).build());
+                }
             }
             return record;
         }));
@@ -390,7 +413,7 @@ public class OrderFlowService {
             }
             Date startTime = time;
             Date endTime = Tools.addDate(startTime, expireDay);
-            UserCourse userCourse = userCourseService.getCourse(record.getUserId(), record.getProductId());
+            UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
             if(userCourse == null){
                 userCourse = UserCourse.builder()
                         .userId(record.getUserId())
@@ -499,7 +522,7 @@ public class OrderFlowService {
             }
             Date startTime = time;
             Date endTime = Tools.addDate(startTime, expireDay);
-            UserCourse userCourse = userCourseService.getCourse(record.getUserId(), record.getProductId());
+            UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
             if(userCourse == null){
                 userCourse = UserCourse.builder()
                         .userId(record.getUserId())

+ 1 - 11
server/gateway-api/src/main/java/com/qxgmat/service/extend/PreviewService.java

@@ -1,26 +1,16 @@
 package com.qxgmat.service.extend;
 
-import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.PageResult;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
-import com.nuliji.tools.exception.SystemException;
-import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.module.*;
-import com.qxgmat.data.constants.enums.status.PreviewStatus;
-import com.qxgmat.data.dao.PreviewPaperMapper;
 import com.qxgmat.data.dao.entity.*;
-import com.qxgmat.data.relation.UserPaperRelationMapper;
-import com.qxgmat.data.relation.UserReportRelationMapper;
 import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
 import com.qxgmat.service.UserPaperService;
 import com.qxgmat.service.inline.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.*;
@@ -180,7 +170,7 @@ public class PreviewService extends AbstractService {
                 return timeRecord.getId();
             case VIDEO:
                 // 获取当前该课程记录
-                UserCourse record = userCourseService.getCourse(userId, assign.getCourseId());
+                UserCourse record = userCourseService.getCourseBase(userId, assign.getCourseId());
                 return record != null ? record.getRecordId() : 0;
             default:
                 return 0;

+ 60 - 6
server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java

@@ -31,6 +31,9 @@ public class QuestionFlowService {
     private ExaminationPaperService examinationPaperService;
 
     @Resource
+    private ExaminationStructService examinationStructService;
+
+    @Resource
     private QuestionNoService questionNoService;
 
     @Resource
@@ -79,6 +82,9 @@ public class QuestionFlowService {
     private ExaminationService examinationService;
 
     @Resource
+    private CourseExtendService courseExtendService;
+
+    @Resource
     private ToolsService toolsService;
 
     // 自由组卷初始化试卷callback
@@ -114,18 +120,21 @@ public class QuestionFlowService {
             List<QuestionNoRelation> relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
         makePaperCallback.put(QuestionModule.SENTENCE, (userPaper, id)->{
             // 获取考题时间
             List<SentenceQuestionRelation> relationList = sentenceQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
         makePaperCallback.put(QuestionModule.TEXTBOOK, (userPaper, id)->{
             // 获取考题时间
             List<TextbookQuestionRelation> relationList = textbookQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
 
         initOriginPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{
@@ -152,7 +161,7 @@ public class QuestionFlowService {
             // 根据papermodule得到考试时长
             QuestionModule module = QuestionModule.WithPaper(PaperModule.ValueOf(paper.getPaperModule()));
             InitPaper callback = makePaperCallback.get(module);
-            callback.callback(userPaper, id);
+            return callback.callback(userPaper, id);
         });
 
         initPaperCallback.put(PaperModule.EXERCISE, (userPaper, id)->{
@@ -163,6 +172,7 @@ public class QuestionFlowService {
             List<QuestionNoRelation> relationList = questionNoService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new QuestionNoRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
         initPaperCallback.put(PaperModule.SENTENCE, (userPaper, id)->{
             SentencePaper paper = sentencePaperService.get(id);
@@ -173,6 +183,7 @@ public class QuestionFlowService {
             List<SentenceQuestionRelation> relationList = sentenceQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new SentenceQuestionRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
         initPaperCallback.put(PaperModule.TEXTBOOK, (userPaper, id)->{
             TextbookPaper paper = textbookPaperService.get(id);
@@ -183,11 +194,20 @@ public class QuestionFlowService {
             List<TextbookQuestionRelation> relationList = textbookQuestionService.listWithRelationByIds(userPaper.getQuestionNoIds());
             Integer time = toolsService.computerTime(relationList.toArray(new TextbookQuestionRelation[0]));
             userPaper.setTime(time);
+            return userPaper;
         });
         initPaperCallback.put(PaperModule.EXAMINATION, (userPaper, id)->{
             ExaminationPaper paper = examinationPaperService.get(id);
             userPaper.setTitle(paper.getTitle());
             userPaper.setIsAdapt(paper.getIsAdapt());
+            ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId());
+            ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree());
+            ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend());
+            if (serviceKey == ServiceKey.QX_CAT) {
+                User user = usersService.get(userPaper.getUserId());
+                userPaper.setPaperNo(user.getQxCat());
+            }
+            return userPaper;
         });
 
         initReportCallback.put(PaperModule.EXERCISE, (report, paper)->{
@@ -227,7 +247,23 @@ public class QuestionFlowService {
         resetPaperCallback.put(PaperOrigin.PREVIEW, (userPaper, id)->{
             // 重新初始化
             InitPaper callback = initOriginPaperCallback.get(PaperOrigin.PREVIEW);
-            callback.callback(userPaper, id);
+            return callback.callback(userPaper, id);
+        });
+        resetPaperCallback.put(PaperOrigin.EXAMINATION, (userPaper, id)->{
+            // 如果是cat模考
+            ExaminationPaper examinationPaper = examinationPaperService.get(userPaper.getOriginId());
+            ExaminationStruct examinationStruct = examinationStructService.get(examinationPaper.getStructThree());
+            ServiceKey serviceKey = ServiceKey.ValueOf(examinationStruct.getExtend());
+            if (serviceKey == ServiceKey.QX_CAT){
+                User user = usersService.get(userPaper.getUserId());
+
+                // 创建新的paper
+                userPaper = userPaperService.newByPaper(userPaper.getUserId(), PaperOrigin.ValueOf(userPaper.getPaperOrigin()), PaperModule.ValueOf(userPaper.getPaperModule()), userPaper.getOriginId());
+                userPaper.setIsAdapt(userPaper.getIsAdapt());
+                userPaper.setTitle(userPaper.getTitle());
+                userPaper.setPaperNo(user.getQxCat());
+            }
+            return userPaper;
         });
 
         nextCallback.put(PaperModule.EXERCISE, (question, report, lastQuestion)->{
@@ -392,7 +428,7 @@ public class QuestionFlowService {
         paper.setQuestionNoIds(questionNoIds.toArray(new Integer[0]));
 
         InitPaper callback = makePaperCallback.get(module);
-        callback.callback(paper, 0);
+        paper = callback.callback(paper, 0);
         paper = userPaperService.add(paper);
 
         // 绑定关系,用于下次处理过滤
@@ -418,7 +454,7 @@ public class QuestionFlowService {
             if (callback == null) {
                 callback  = initPaperCallback.get(module);
             }
-            callback.callback(paper, paperId);
+            paper = callback.callback(paper, paperId);
             paper = userPaperService.add(paper);
         }
         return paper;
@@ -443,9 +479,13 @@ public class QuestionFlowService {
             // 是否对重置有特殊处理
             InitPaper callback = resetPaperCallback.get(origin);
             if (callback != null){
-                callback.callback(paper, paperId);
+                paper = callback.callback(paper, paperId);
+            }
+            if (paper.getId() != null){
+                userPaperService.edit(paper);
+            }else{
+                paper = userPaperService.add(paper);
             }
-            userPaperService.edit(paper);
         }else if(setting == null){
             // 对于长难句这种没有设置开始页的,读取最后一次
             userReport = userReportService.getLastByPaper(userId, paper.getId());
@@ -680,6 +720,19 @@ public class QuestionFlowService {
     }
 
     /**
+     * 根据题目类型获取课程信息
+     * @param questionType
+     * @return
+     */
+    public Integer questionRelationCourse(Integer userId, Integer assignId, QuestionType questionType){
+        if (assignId != null){
+            Integer assignRecordId = previewService.getRecord(userId, assignId);
+            if (assignRecordId != null) return assignRecordId;
+        }
+        return courseExtendService.questionRelationCourse(userId, questionType);
+    }
+
+    /**
      * 累计考试学习时间
      * @param userId
      * @return
@@ -762,6 +815,7 @@ public class QuestionFlowService {
         number.put(stage, subnumber + 1);
         return true;
     }
+
     /**
      * 语文出题计算
      * @param setting

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseService.java

@@ -118,6 +118,16 @@ public class CourseService extends AbstractService {
         return select(courseMapper, example);
     }
 
+    public List<Course> listByExtend(String questionType, String questionSubject){
+        Example example = new Example(Course.class);
+        example.and(
+                example.createCriteria()
+                        .orEqualTo("extend", questionType)
+                        .orEqualTo("extend", questionSubject)
+        );
+        return select(courseMapper, example);
+    }
+
     /**
      * 累加购买记录,访问记录
      * @param sale

+ 29 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseService.java

@@ -27,16 +27,45 @@ public class UserCourseService extends AbstractService {
      * @param courseId
      * @return
      */
+    public UserCourse getCourseBase(Integer userId, Integer courseId){
+        Example example = new Example(UserCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("courseId", courseId)
+        );
+        return one(userCourseMapper, example);
+    }
+    /**
+     * 获取单个课程有效记录
+     * @param userId
+     * @param courseId
+     * @return
+     */
     public UserCourse getCourse(Integer userId, Integer courseId){
         Example example = new Example(UserCourse.class);
         example.and(
                 example.createCriteria()
                         .andEqualTo("userId", userId)
                         .andEqualTo("courseId", courseId)
+                        .andGreaterThanOrEqualTo("startTime", new Date())
+                        .andLessThan("expireTime", new Date())
         );
         return one(userCourseMapper, example);
     }
 
+    public List<UserCourse> listByCourse(Integer userId, Collection ids){
+        Example example = new Example(UserCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andIn("courseId", ids)
+                        .andGreaterThanOrEqualTo("startTime", new Date())
+                        .andLessThan("expireTime", new Date())
+        );
+        return select(userCourseMapper, example);
+    }
+
     /**
      * 合并用户信息,将old转移至new
      * @param oldUserId

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java

@@ -47,6 +47,19 @@ public class UserReportService extends AbstractService {
     }
 
     /**
+     * 查找userPaper最后一次做题记录: 不在意reset标志
+     * @param paperIds
+     */
+    public List<UserReport> listWithLaterNoReset(Collection paperIds){
+        if(paperIds == null || paperIds.size() == 0) return new ArrayList<>();
+        List<UserReport> list = userReportRelationMapper.listLastNoReset(paperIds);
+
+        Collection reportIds = Transform.getIds(list, UserReport.class, "id");
+        Transform.replace(list, select(reportIds), UserReport.class, "id");
+        return list;
+    }
+
+    /**
      * 获取所属组卷的所有报告
      * @param paperIds
      * @return