Преглед изворни кода

feat(server): 数据统计

Go пре 5 година
родитељ
комит
250cd3cdb3
55 измењених фајлова са 1927 додато и 310 уклоњено
  1. 9 8
      front/project/admin/routes/course/preview/page.js
  2. 10 1
      front/project/admin/routes/course/previewDetail/page.js
  3. 1 3
      front/project/admin/routes/subject/textbookQuestion/page.js
  4. 11 9
      front/project/h5/stores/my.js
  5. 10 10
      front/project/www/routes/paper/question/page.js
  6. 19 0
      front/project/www/stores/main.js
  7. 25 11
      front/project/www/stores/my.js
  8. 70 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/PreviewPaper.java
  9. 61 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/Question.java
  10. 75 49
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserNoteQuestion.java
  11. 7 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserQuestion.java
  12. 4 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PreviewPaperMapper.xml
  13. 6 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/QuestionMapper.xml
  14. 6 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserNoteQuestionMapper.xml
  15. 1 0
      server/data/src/main/java/com/qxgmat/data/relation/PreviewPaperRelationMapper.java
  16. 23 0
      server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java
  17. 17 5
      server/data/src/main/java/com/qxgmat/data/relation/UserCollectQuestionRelationMapper.java
  18. 16 5
      server/data/src/main/java/com/qxgmat/data/relation/UserNoteQuestionRelationMapper.java
  19. 32 0
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java
  20. 24 0
      server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java
  21. 3 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewPaperRelationMapper.xml
  22. 36 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml
  23. 27 22
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCollectQuestionRelationMapper.xml
  24. 25 20
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserNoteQuestionRelationMapper.xml
  25. 53 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml
  26. 36 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml
  27. 5 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java
  28. 2 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  29. 3 3
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  30. 10 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java
  31. 400 96
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  32. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  33. 9 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  34. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/PreviewPaperDto.java
  35. 12 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/QuestionExtendDto.java
  36. 131 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserAskQuestionExtendDto.java
  37. 14 14
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskQuestionDto.java
  38. 6 6
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorDto.java
  39. 67 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorQuestionDto.java
  40. 161 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserAskQuestionInfoDto.java
  41. 30 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCollectQuestionDto.java
  42. 105 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserDataDto.java
  43. 1 1
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserNoteQuestionDto.java
  44. 61 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserPaperDto.java
  45. 11 1
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionErrorListDto.java
  46. 34 7
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java
  47. 41 8
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  48. 77 4
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  49. 69 5
      server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java
  50. 2 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/SentenceService.java
  51. 2 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java
  52. 2 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewPaperService.java
  53. 21 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java
  54. 32 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java
  55. 1 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java

+ 9 - 8
front/project/admin/routes/course/preview/page.js

@@ -9,12 +9,13 @@ import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { getMap, formatTreeData, bindSearch } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { CourseModule } from '../../../../Constant';
+import { CourseModule, QuestionType } from '../../../../Constant';
 import { Exercise } from '../../../stores/exercise';
 import { Course } from '../../../stores/course';
 import { Preview } from '../../../stores/preview';
 
 const CourseModuleMap = getMap(CourseModule, 'value', 'label');
+const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 
 export default class extends Page {
   init() {
@@ -50,12 +51,12 @@ export default class extends Page {
       placeholder: '请选择',
       select: CourseModule,
     }, {
-      key: 'structId',
-      type: 'tree',
+      key: 'questionType',
+      type: 'select',
       allowClear: true,
-      name: '单项',
+      name: '题型',
       placeholder: '请选择',
-      select: [],
+      select: QuestionType,
     }, {
       key: 'courseId',
       type: 'select',
@@ -74,10 +75,10 @@ export default class extends Page {
       title: '课程名称',
       dataIndex: 'course.title',
     }, {
-      title: '单项',
-      dataIndex: 'course.structId',
+      title: '题型',
+      dataIndex: 'questionType',
       render: (text) => {
-        return this.exerciseMap[text] || '';
+        return QuestionTypeMap[text] || '';
       },
     }, {
       title: '作业标题',

+ 10 - 1
front/project/admin/routes/course/previewDetail/page.js

@@ -6,7 +6,7 @@ import Block from '@src/components/Block';
 import Select from '@src/components/Select';
 import { formatFormError, bindSearch, formatDate, generateSearch } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
-// import { PreviewMode } from '../../../../Constant';
+import { QuestionType } from '../../../../Constant';
 import Association from '../../../components/Association';
 import { Preview } from '../../../stores/preview';
 import { Course } from '../../../stores/course';
@@ -221,6 +221,15 @@ export default class extends Page {
             <Select select={this.state.courseNo} disabled={data.id || !data.courseId} placeholder='请选择课时' />,
           )}
         </Form.Item>}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
+          {getFieldDecorator('questionType', {
+            rules: [
+              { required: true, message: '请选择题型' },
+            ],
+          })(
+            <Select select={QuestionType} placeholder='请选择题型' />,
+          )}
+        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='作业标题'>
           {getFieldDecorator('title', {
             rules: [

+ 1 - 3
front/project/admin/routes/subject/textbookQuestion/page.js

@@ -228,9 +228,7 @@ export default class extends Page {
               { required: true, message: '请选择考点' },
             ],
           })(
-            <Select select={this.state.placeList} placeholder='请选择考点' onChange={(v) => {
-              this.refreshPart(v);
-            }} />,
+            <Select select={this.state.placeList} placeholder='请选择考点' />,
           )}
         </Form.Item>
       </Form>

+ 11 - 9
front/project/h5/stores/my.js

@@ -246,38 +246,40 @@ export default class MyStore extends BaseStore {
   }
 
   /**
-   * 添加提问
+   * 添加题目提问
+   * @param {*} userPaperId : 用于获取预习作业,判断权限
    * @param {*} target
    * @param {*} questionModule
    * @param {*} questionNoId
    * @param {*} content
    */
-  addQuestionAsk(userQuestionId, target, questionModule, questionNoId, originContent, content) {
-    return this.apiPost('/my/ask/question', { userQuestionId, target, questionModule, questionNoId, originContent, content });
+  addQuestionAsk(userPaperId, target, questionModule, questionNoId, originContent, content) {
+    return this.apiPost('/my/ask/question', { userPaperId, target, questionModule, questionNoId, originContent, content });
   }
 
   /**
    * 添加题目勘误
-   * @param {*} moduleId
+   * @param {*} questionModule
+   * @param {*} questionNoId
    * @param {*} title
    * @param {*} position
    * @param {*} originContent
    * @param {*} content
    */
-  addFeedbackErrorQuestion(moduleId, title, position, originContent, content) {
-    return this.apiPost('/my/feedback/error/question', { moduleId, title, position, originContent, content });
+  addFeedbackErrorQuestion(questionModule, questionNoId, title, position, originContent, content) {
+    return this.apiPost('/my/feedback/error/question', { questionModule, questionNoId, title, position, originContent, content });
   }
 
   /**
    * 添加数据勘误
-   * @param {*} moduleId
+   * @param {*} dataId
    * @param {*} title
    * @param {*} position
    * @param {*} originContent
    * @param {*} content
    */
-  addErrorData(moduleId, title, position, originContent, content) {
-    return this.apiPost('/my/feedback/error/question', { moduleId, title, position, originContent, content });
+  addErrorData(dataId, title, position, originContent, content) {
+    return this.apiPost('/my/feedback/error/question', { dataId, title, position, originContent, content });
   }
 
   /**

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

@@ -113,9 +113,9 @@ export default class extends Page {
   }
 
   submitAsk() {
-    const { userQuestion = {}, ask = {} } = this.state;
+    const { question = {}, questionNo = {}, paper = {}, ask = {} } = this.state;
     if (ask.originContent === '' || ask.content === '' || ask.target === '') return;
-    My.addQuestionAsk(userQuestion.id, ask.target, userQuestion.questionModule, ask.originContent, ask.content).then(() => {
+    My.addQuestionAsk(paper.id, ask.target, question.questionModule, questionNo.id, ask.originContent, ask.content).then(() => {
       this.setState({ askModal: false, askOkModal: true });
     }).catch(err => {
       this.setState({ askError: err.message });
@@ -123,9 +123,9 @@ export default class extends Page {
   }
 
   submitFeedbackError() {
-    const { feedback = {}, userQuestion = {}, questionNo = {} } = this.state;
+    const { feedback = {}, question = {}, questionNo = {} } = this.state;
     if (feedback.originContent === '' || feedback.content === '' || feedback.target === '') return;
-    My.addFeedbackErrorQuestion(userQuestion.id, questionNo.title, feedback.target, feedback.originContent, feedback.content).then(() => {
+    My.addFeedbackErrorQuestion(question.questionModule, questionNo.id, questionNo.title, feedback.target, feedback.originContent, feedback.content).then(() => {
       this.setState({ feedbackModal: false, feedbackOkModal: true });
     }).catch(err => {
       this.setState({ feedbackError: err.message });
@@ -133,8 +133,8 @@ export default class extends Page {
   }
 
   submitNote(close) {
-    const { userQuestion = {}, note = {} } = this.state;
-    My.updateQuestionNote(userQuestion.questionModule, userQuestion.questionNoId, note).then(() => {
+    const { question = {}, questionNo = {}, note = {} } = this.state;
+    My.updateQuestionNote(question.questionModule, questionNo.id, note).then(() => {
       if (close) this.setState({ noteModal: false });
     }).catch(err => {
       this.setState({ noteError: err.message });
@@ -147,14 +147,14 @@ export default class extends Page {
   }
 
   toggleCollect() {
-    const { userQuestion = {} } = this.state;
+    const { userQuestion = {}, question = {}, questionNo = {} } = this.state;
     if (!userQuestion.collect) {
-      My.addQuestionCollect(userQuestion.questionModule, userQuestion.questionNoId).then(() => {
+      My.addQuestionCollect(question.questionModule, questionNo.id).then(() => {
         userQuestion.collect = true;
         this.setState({ userQuestion });
       });
     } else {
-      My.delQuestionCollect(userQuestion.questionModule, userQuestion.questionNoId).then(() => {
+      My.delQuestionCollect(question.questionModule, questionNo.id).then(() => {
         userQuestion.collect = false;
         this.setState({ userQuestion });
       });
@@ -250,7 +250,7 @@ export default class extends Page {
         </div>
       </div>
       <div className="right" hidden={question.questionType === 'awa'}>
-        <span className="b">
+        <span className="b" hidden={!userQuestion.id}>
           用时:<span dangerouslySetInnerHTML={{ __html: formatSeconds(userQuestion.userTime).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2') }} />
           {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
         </span>

+ 19 - 0
front/project/www/stores/main.js

@@ -44,6 +44,25 @@ export default class MainStore extends BaseStore {
     return this.apiGet('/base/score', { total, quant });
   }
 
+  courseStruct() {
+    return this.getExercise().then((result) => {
+      return result.filter(row => row.isCourse);
+    });
+  }
+
+  dataStruct() {
+    return this.getExercise().then((result) => {
+      return result.filter(row => row.isData);
+    });
+  }
+
+  /**
+   * 单个科目下的范围
+   */
+  rangeExercise() {
+    return this.apiGet('/base/exercise/range');
+  }
+
   /**
    * 所有练习头2层
    */

+ 25 - 11
front/project/www/stores/my.js

@@ -137,7 +137,7 @@ export default class MyStore extends BaseStore {
    * @param {*} order
    * @param {*} direction
    */
-  listQuestionCollect(questionModule, questionType, page, size, startTime, endTime, order, direction) {
+  listQuestionCollect({ questionModule, questionType, page, size, startTime, endTime, order, direction }) {
     return this.apiGet('/my/collect/question/list', { questionModule, questionType, page, size, startTime, endTime, order, direction });
   }
 
@@ -147,7 +147,7 @@ export default class MyStore extends BaseStore {
    * @param {*} page
    * @param {*} size
    */
-  listError(questionModule, page, size) {
+  listError({ questionModule, page, size }) {
     return this.apiGet('/my/error/list', { questionModule, page, size });
   }
 
@@ -212,7 +212,7 @@ export default class MyStore extends BaseStore {
    * @param {*} order
    * @param {*} direction
    */
-  questionNoteList(questionModule, questionType, page, size, startTime, endTime, order, direction) {
+  questionNoteList({ questionModule, questionType, page, size, startTime, endTime, order, direction }) {
     return this.apiGet('/my/note/question/list', { questionModule, questionType, page, size, startTime, endTime, order, direction });
   }
 
@@ -233,13 +233,26 @@ export default class MyStore extends BaseStore {
 
   /**
    * 添加题目提问
+   * @param {*} userPaperId : 用于获取预习作业,判断权限
    * @param {*} target
    * @param {*} questionModule
    * @param {*} questionNoId
    * @param {*} content
    */
-  addQuestionAsk(userQuestionId, target, questionModule, questionNoId, originContent, content) {
-    return this.apiPost('/my/ask/question', { userQuestionId, target, questionModule, questionNoId, originContent, content });
+  addQuestionAsk(userPaperId, target, questionModule, questionNoId, originContent, content) {
+    return this.apiPost('/my/ask/question', { userPaperId, target, questionModule, questionNoId, originContent, content });
+  }
+
+  /**
+   * 删除题目提问
+   * @param {*} id
+   */
+  delQuestionAsk(id) {
+    return this.apiDel('/my/ask/question/delete', { id });
+  }
+
+  listQuestionAsk({ page, size }) {
+    return this.apiGet('/my/ask/question/list', { page, size });
   }
 
   /**
@@ -255,26 +268,27 @@ export default class MyStore extends BaseStore {
 
   /**
    * 添加题目勘误
-   * @param {*} userQuestionId
+   * @param {*} questionModule
+   * @param {*} questionNoId
    * @param {*} title
    * @param {*} position
    * @param {*} originContent
    * @param {*} content
    */
-  addFeedbackErrorQuestion(userQuestionId, title, position, originContent, content) {
-    return this.apiPost('/my/feedback/error/question', { userQuestionId, title, position, originContent, content });
+  addFeedbackErrorQuestion(questionModule, questionNoId, title, position, originContent, content) {
+    return this.apiPost('/my/feedback/error/question', { questionModule, questionNoId, title, position, originContent, content });
   }
 
   /**
    * 添加数据勘误
-   * @param {*} moduleId
+   * @param {*} dataId
    * @param {*} title
    * @param {*} position
    * @param {*} originContent
    * @param {*} content
    */
-  addErrorData(moduleId, title, position, originContent, content) {
-    return this.apiPost('/my/feedback/error/question', { moduleId, title, position, originContent, content });
+  addErrorData(dataId, title, position, originContent, content) {
+    return this.apiPost('/my/feedback/error/question', { dataId, title, position, originContent, content });
   }
 
   /**

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

@@ -36,6 +36,18 @@ public class PreviewPaper implements Serializable {
     private Integer courseNo;
 
     /**
+     * 作业学科
+     */
+    @Column(name = "`question_subject`")
+    private String questionSubject;
+
+    /**
+     * 作业题型
+     */
+    @Column(name = "`question_type`")
+    private String questionType;
+
+    /**
      * 题目编号id:json
      */
     @Column(name = "`question_no_ids`")
@@ -142,6 +154,42 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
+     * 获取作业学科
+     *
+     * @return question_subject - 作业学科
+     */
+    public String getQuestionSubject() {
+        return questionSubject;
+    }
+
+    /**
+     * 设置作业学科
+     *
+     * @param questionSubject 作业学科
+     */
+    public void setQuestionSubject(String questionSubject) {
+        this.questionSubject = questionSubject;
+    }
+
+    /**
+     * 获取作业题型
+     *
+     * @return question_type - 作业题型
+     */
+    public String getQuestionType() {
+        return questionType;
+    }
+
+    /**
+     * 设置作业题型
+     *
+     * @param questionType 作业题型
+     */
+    public void setQuestionType(String questionType) {
+        this.questionType = questionType;
+    }
+
+    /**
      * 获取题目编号id:json
      *
      * @return question_no_ids - 题目编号id:json
@@ -216,6 +264,8 @@ public class PreviewPaper implements Serializable {
         sb.append(", courseId=").append(courseId);
         sb.append(", courseModule=").append(courseModule);
         sb.append(", courseNo=").append(courseNo);
+        sb.append(", questionSubject=").append(questionSubject);
+        sb.append(", questionType=").append(questionType);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", paperModule=").append(paperModule);
         sb.append(", createTime=").append(createTime);
@@ -284,6 +334,26 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
+         * 设置作业学科
+         *
+         * @param questionSubject 作业学科
+         */
+        public Builder questionSubject(String questionSubject) {
+            obj.setQuestionSubject(questionSubject);
+            return this;
+        }
+
+        /**
+         * 设置作业题型
+         *
+         * @param questionType 作业题型
+         */
+        public Builder questionType(String questionType) {
+            obj.setQuestionType(questionType);
+            return this;
+        }
+
+        /**
          * 设置题目编号id:json
          *
          * @param questionNoIds 题目编号id:json

+ 61 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/Question.java

@@ -18,6 +18,9 @@ public class Question implements Serializable {
     @Column(name = "`keyword`")
     private String[] keyword;
 
+    @Column(name = "`question_module`")
+    private String questionModule;
+
     /**
      * 题型
      */
@@ -96,6 +99,12 @@ public class Question implements Serializable {
     @Column(name = "`total_correct`")
     private Integer totalCorrect;
 
+    /**
+     * 收藏数
+     */
+    @Column(name = "`collect_number`")
+    private Integer collectNumber;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -155,6 +164,20 @@ public class Question implements Serializable {
     }
 
     /**
+     * @return question_module
+     */
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    /**
+     * @param questionModule
+     */
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    /**
      * 获取题型
      *
      * @return question_type - 题型
@@ -409,6 +432,24 @@ public class Question implements Serializable {
     }
 
     /**
+     * 获取收藏数
+     *
+     * @return collect_number - 收藏数
+     */
+    public Integer getCollectNumber() {
+        return collectNumber;
+    }
+
+    /**
+     * 设置收藏数
+     *
+     * @param collectNumber 收藏数
+     */
+    public void setCollectNumber(Integer collectNumber) {
+        this.collectNumber = collectNumber;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -508,6 +549,7 @@ public class Question implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", keyword=").append(keyword);
+        sb.append(", questionModule=").append(questionModule);
         sb.append(", questionType=").append(questionType);
         sb.append(", place=").append(place);
         sb.append(", difficult=").append(difficult);
@@ -523,6 +565,7 @@ public class Question implements Serializable {
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalNumber=").append(totalNumber);
         sb.append(", totalCorrect=").append(totalCorrect);
+        sb.append(", collectNumber=").append(collectNumber);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
         sb.append(", answerDistributed=").append(answerDistributed);
@@ -563,6 +606,14 @@ public class Question implements Serializable {
         }
 
         /**
+         * @param questionModule
+         */
+        public Builder questionModule(String questionModule) {
+            obj.setQuestionModule(questionModule);
+            return this;
+        }
+
+        /**
          * 设置题型
          *
          * @param questionType 题型
@@ -715,6 +766,16 @@ public class Question implements Serializable {
         }
 
         /**
+         * 设置收藏数
+         *
+         * @param collectNumber 收藏数
+         */
+        public Builder collectNumber(Integer collectNumber) {
+            obj.setCollectNumber(collectNumber);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

+ 75 - 49
server/data/src/main/java/com/qxgmat/data/dao/entity/UserNoteQuestion.java

@@ -38,6 +38,12 @@ public class UserNoteQuestion implements Serializable {
     @Column(name = "`question_time`")
     private Date questionTime;
 
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
     @Column(name = "`official_time`")
     private Date officialTime;
 
@@ -50,17 +56,14 @@ public class UserNoteQuestion implements Serializable {
     @Column(name = "`qa_time`")
     private Date qaTime;
 
-    @Column(name = "`create_time`")
-    private Date createTime;
-
-    @Column(name = "`update_time`")
-    private Date updateTime;
+    @Column(name = "`question_content`")
+    private String questionContent;
 
     /**
      * 笔记内容
      */
-    @Column(name = "`question_content`")
-    private String questionContent;
+    @Column(name = "`content`")
+    private String content;
 
     @Column(name = "`official_content`")
     private String officialContent;
@@ -177,6 +180,34 @@ public class UserNoteQuestion implements Serializable {
     }
 
     /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
      * @return official_time
      */
     public Date getOfficialTime() {
@@ -233,49 +264,35 @@ public class UserNoteQuestion implements Serializable {
     }
 
     /**
-     * @return create_time
-     */
-    public Date getCreateTime() {
-        return createTime;
-    }
-
-    /**
-     * @param createTime
-     */
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
-
-    /**
-     * @return update_time
+     * @return question_content
      */
-    public Date getUpdateTime() {
-        return updateTime;
+    public String getQuestionContent() {
+        return questionContent;
     }
 
     /**
-     * @param updateTime
+     * @param questionContent
      */
-    public void setUpdateTime(Date updateTime) {
-        this.updateTime = updateTime;
+    public void setQuestionContent(String questionContent) {
+        this.questionContent = questionContent;
     }
 
     /**
      * 获取笔记内容
      *
-     * @return question_content - 笔记内容
+     * @return content - 笔记内容
      */
-    public String getQuestionContent() {
-        return questionContent;
+    public String getContent() {
+        return content;
     }
 
     /**
      * 设置笔记内容
      *
-     * @param questionContent 笔记内容
+     * @param content 笔记内容
      */
-    public void setQuestionContent(String questionContent) {
-        this.questionContent = questionContent;
+    public void setContent(String content) {
+        this.content = content;
     }
 
     /**
@@ -346,13 +363,14 @@ public class UserNoteQuestion implements Serializable {
         sb.append(", questionId=").append(questionId);
         sb.append(", questionNoId=").append(questionNoId);
         sb.append(", questionTime=").append(questionTime);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
         sb.append(", officialTime=").append(officialTime);
         sb.append(", qxTime=").append(qxTime);
         sb.append(", associationTime=").append(associationTime);
         sb.append(", qaTime=").append(qaTime);
-        sb.append(", createTime=").append(createTime);
-        sb.append(", updateTime=").append(updateTime);
         sb.append(", questionContent=").append(questionContent);
+        sb.append(", content=").append(content);
         sb.append(", officialContent=").append(officialContent);
         sb.append(", qxContent=").append(qxContent);
         sb.append(", associationContent=").append(associationContent);
@@ -429,6 +447,22 @@ public class UserNoteQuestion implements Serializable {
         }
 
         /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
          * @param officialTime
          */
         public Builder officialTime(Date officialTime) {
@@ -461,28 +495,20 @@ public class UserNoteQuestion implements Serializable {
         }
 
         /**
-         * @param createTime
-         */
-        public Builder createTime(Date createTime) {
-            obj.setCreateTime(createTime);
-            return this;
-        }
-
-        /**
-         * @param updateTime
+         * @param questionContent
          */
-        public Builder updateTime(Date updateTime) {
-            obj.setUpdateTime(updateTime);
+        public Builder questionContent(String questionContent) {
+            obj.setQuestionContent(questionContent);
             return this;
         }
 
         /**
          * 设置笔记内容
          *
-         * @param questionContent 笔记内容
+         * @param content 笔记内容
          */
-        public Builder questionContent(String questionContent) {
-            obj.setQuestionContent(questionContent);
+        public Builder content(String content) {
+            obj.setContent(content);
             return this;
         }
 

+ 7 - 7
server/data/src/main/java/com/qxgmat/data/dao/entity/UserQuestion.java

@@ -25,7 +25,7 @@ public class UserQuestion implements Serializable {
     private Integer reportId;
 
     /**
-     * 题目模块:exercise, examination, sentence, textbook
+     * 题目模块
      */
     @Column(name = "`question_module`")
     private String questionModule;
@@ -152,18 +152,18 @@ public class UserQuestion implements Serializable {
     }
 
     /**
-     * 获取题目模块:exercise, examination, sentence, textbook
+     * 获取题目模块
      *
-     * @return question_module - 题目模块:exercise, examination, sentence, textbook
+     * @return question_module - 题目模块
      */
     public String getQuestionModule() {
         return questionModule;
     }
 
     /**
-     * 设置题目模块:exercise, examination, sentence, textbook
+     * 设置题目模块
      *
-     * @param questionModule 题目模块:exercise, examination, sentence, textbook
+     * @param questionModule 题目模块
      */
     public void setQuestionModule(String questionModule) {
         this.questionModule = questionModule;
@@ -447,9 +447,9 @@ public class UserQuestion implements Serializable {
         }
 
         /**
-         * 设置题目模块:exercise, examination, sentence, textbook
+         * 设置题目模块
          *
-         * @param questionModule 题目模块:exercise, examination, sentence, textbook
+         * @param questionModule 题目模块
          */
         public Builder questionModule(String questionModule) {
             obj.setQuestionModule(questionModule);

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

@@ -10,6 +10,8 @@
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
     <result column="course_module" jdbcType="VARCHAR" property="courseModule" />
     <result column="course_no" jdbcType="INTEGER" property="courseNo" />
+    <result column="question_subject" jdbcType="VARCHAR" property="questionSubject" />
+    <result column="question_type" jdbcType="VARCHAR" property="questionType" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="paper_module" jdbcType="VARCHAR" property="paperModule" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
@@ -19,7 +21,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `course_id`, `course_module`, `course_no`, `question_no_ids`, `paper_module`, 
-    `create_time`, `update_time`
+    `id`, `title`, `course_id`, `course_module`, `course_no`, `question_subject`, `question_type`, 
+    `question_no_ids`, `paper_module`, `create_time`, `update_time`
   </sql>
 </mapper>

+ 6 - 4
server/data/src/main/java/com/qxgmat/data/dao/mapping/QuestionMapper.xml

@@ -7,6 +7,7 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="keyword" jdbcType="VARCHAR" property="keyword" typeHandler="com.nuliji.tools.mybatis.handler.StringArrayHandler" />
+    <result column="question_module" jdbcType="VARCHAR" property="questionModule" />
     <result column="question_type" jdbcType="VARCHAR" property="questionType" />
     <result column="place" jdbcType="VARCHAR" property="place" />
     <result column="difficult" jdbcType="VARCHAR" property="difficult" />
@@ -22,6 +23,7 @@
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
+    <result column="collect_number" jdbcType="INTEGER" property="collectNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
     <result column="answer_distributed" jdbcType="VARCHAR" property="answerDistributed" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
@@ -38,10 +40,10 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `keyword`, `question_type`, `place`, `difficult`, `difficult_score`, `description`, 
-    `content`, `answer`, `question_time`, `qx_time`, `official_time`, `association_time`, 
-    `association_content`, `total_time`, `total_number`, `total_correct`, `create_time`, 
-    `update_time`, `answer_distributed`
+    `id`, `keyword`, `question_module`, `question_type`, `place`, `difficult`, `difficult_score`, 
+    `description`, `content`, `answer`, `question_time`, `qx_time`, `official_time`, 
+    `association_time`, `association_content`, `total_time`, `total_number`, `total_correct`, 
+    `collect_number`, `create_time`, `update_time`, `answer_distributed`
   </sql>
   <sql id="Blob_Column_List">
     <!--

+ 6 - 4
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserNoteQuestionMapper.xml

@@ -11,18 +11,19 @@
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
     <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
     <result column="question_time" jdbcType="TIMESTAMP" property="questionTime" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
     <result column="official_time" jdbcType="TIMESTAMP" property="officialTime" />
     <result column="qx_time" jdbcType="TIMESTAMP" property="qxTime" />
     <result column="association_time" jdbcType="TIMESTAMP" property="associationTime" />
     <result column="qa_time" jdbcType="TIMESTAMP" property="qaTime" />
-    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
-    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserNoteQuestion">
     <!--
       WARNING - @mbg.generated
     -->
     <result column="question_content" jdbcType="LONGVARCHAR" property="questionContent" />
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
     <result column="official_content" jdbcType="LONGVARCHAR" property="officialContent" />
     <result column="qx_content" jdbcType="LONGVARCHAR" property="qxContent" />
     <result column="association_content" jdbcType="LONGVARCHAR" property="associationContent" />
@@ -33,12 +34,13 @@
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `question_module`, `question_id`, `question_no_id`, `question_time`, 
-    `official_time`, `qx_time`, `association_time`, `qa_time`, `create_time`, `update_time`
+    `create_time`, `update_time`, `official_time`, `qx_time`, `association_time`, `qa_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `question_content`, `official_content`, `qx_content`, `association_content`, `qa_content`
+    `question_content`, `content`, `official_content`, `qx_content`, `association_content`, 
+    `qa_content`
   </sql>
 </mapper>

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

@@ -11,6 +11,7 @@ import java.util.List;
 public interface PreviewPaperRelationMapper {
     List<PreviewPaper> listAdmin(
             @Param("courseModule") String courseModule,
+            @Param("questionType") String questionType,
             @Param("structId") Integer structId,
             @Param("order") String order,
             @Param("direction") String direction

+ 23 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java

@@ -9,6 +9,29 @@ import java.util.List;
  * Created by gaojie on 2017/11/9.
  */
 public interface UserAskQuestionRelationMapper {
+    List<UserAskQuestion> listExercise(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("answerStatus") Integer answerStatus,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+    List<UserAskQuestion> listExamination(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("libraryId") Integer libraryId,
+            @Param("year") String year,
+            @Param("answerStatus") Integer answerStatus,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+
     List<UserAskQuestion> listWithUser(
             @Param("askModule") String askModule,
             @Param("questionType") String questionType,

+ 17 - 5
server/data/src/main/java/com/qxgmat/data/relation/UserCollectQuestionRelationMapper.java

@@ -11,13 +11,25 @@ import java.util.List;
  */
 public interface UserCollectQuestionRelationMapper {
 
-    List<UserCollectQuestion> list(
+    List<UserCollectQuestion> listExercise(
             @Param("userId") Number userId,
-            @Param("module") String module,
-            @Param("questionType") String questionType,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            @Param("order") String order,
-            @Param("direction") String direction
+            String order,
+            String direction
+    );
+
+    List<UserCollectQuestion> listExamination(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("libraryId") Integer libraryId,
+            @Param("year") String year,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
     );
 }

+ 16 - 5
server/data/src/main/java/com/qxgmat/data/relation/UserNoteQuestionRelationMapper.java

@@ -9,14 +9,25 @@ import java.util.List;
  * Created by gaojie on 2017/11/9.
  */
 public interface UserNoteQuestionRelationMapper {
+    List<UserNoteQuestion> listExercise(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
 
-    List<UserNoteQuestion> list(
+    List<UserNoteQuestion> listExamination(
             @Param("userId") Number userId,
-            @Param("module") String module,
-            @Param("questionType") String questionType,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("libraryId") Integer libraryId,
+            @Param("year") String year,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            @Param("order") String order,
-            @Param("direction") String direction
+            String order,
+            String direction
     );
 }

+ 32 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java

@@ -21,4 +21,36 @@ public interface UserPaperRelationMapper {
             @Param("times") Integer times,
             @Param("latestTime") Date latestTime
     );
+
+    List<UserPaper> list(
+            @Param("userId") Number userId,
+            @Param("paperOrigin") String paperOrigin,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+
+    List<UserPaper> listExercise(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("courseModule") String courseModule,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+
+    List<UserPaper> listExamination(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("libraryId") Integer libraryId,
+            @Param("year") String year,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
 }

+ 24 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java

@@ -1,5 +1,6 @@
 package com.qxgmat.data.relation;
 
+import com.qxgmat.data.dao.entity.UserQuestion;
 import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import org.apache.ibatis.annotations.Param;
 
@@ -9,6 +10,29 @@ import java.util.List;
  * Created by gaojie on 2017/11/9.
  */
 public interface UserQuestionRelationMapper {
+
+    List<UserQuestion> listExerciseError(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+
+    List<UserQuestion> listExaminationError(
+            @Param("userId") Number userId,
+            @Param("questionTypes") String[] questionTypes,
+            @Param("structIds") Integer[] structIds,
+            @Param("libraryId") Integer libraryId,
+            @Param("year") String year,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            String order,
+            String direction
+    );
+
     List<UserRecordStatRelation> stat(
             @Param("userId") Integer userId,
             @Param("startTime") String startTime,

+ 3 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewPaperRelationMapper.xml

@@ -26,6 +26,9 @@
     <if test="courseModule != null">
       and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
     </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
     order by ${order} ${direction}
   </select>
 </mapper>

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml

@@ -23,6 +23,42 @@
     WHERE `question_id` = #{questionId,jdbcType=VARCHAR} and `order` #{direction} #{order,jdbcType=INTEGER}
   </update>
 
+  <select id="listExercise" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <select id="listExamination" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
   <!--用户提问列表-->
   <select id="listWithUser" resultMap="IdMap">
     select

+ 27 - 22
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCollectQuestionRelationMapper.xml

@@ -14,34 +14,39 @@
     ucq.`id`
   </sql>
 
-  <!--
-    用户收藏题目列表
-  -->
-  <select id="list" resultMap="IdMap">
+  <select id="listExercise" resultMap="IdMap">
     select
     <include refid="Id_Column_List" />
-    from `user_collect_question` ucq
-    left join `question_no` qn on qn.`id` = ucq.`question_no_id`
-      <if test="module != null">
-        and qn.`module` = #{module,jdbcType=VARCHAR}
-      </if>
-    left join `question` q on q.`id` = ucq.`question_id`
-      <if test="questionType != null">
-        and q.`question_type` = #{questionType,jdbcType=VARCHAR}
-      </if>
-    where
-    qn.`id` &gt; 0
-    and q.`id` &gt; 0
-    <if test="userId != null">
-      and ucq.`user_id` = #{userId,jdbcType=VARCHAR}
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
     </if>
-    <if test="startTime != null">
-      and ucq.`createTime` &gt; #{startTime,jdbcType=VARCHAR}
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
     </if>
-    <if test="endTime != null">
-      and ucq.`createTime` &lt; #{endTime,jdbcType=VARCHAR}
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
     </if>
+    order by ${order} ${direction}
+  </select>
 
+  <select id="listExamination" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
     order by ${order} ${direction}
   </select>
 

+ 25 - 20
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserNoteQuestionRelationMapper.xml

@@ -14,34 +14,39 @@
     up.`id`
   </sql>
 
-  <!--
-    用户笔记题目列表
-  -->
-  <select id="list" resultMap="IdMap">
+  <select id="listExercise" resultMap="IdMap">
     select
     <include refid="Id_Column_List" />
-    from `user_note_question` ucq
-    left join `question_no` qn on qn.`id` = ucq.`question_no_id`
-    <if test="module != null">
-      and qn.`module` = #{module,jdbcType=VARCHAR}
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
     </if>
-    left join `question` q on q.`id` = ucq.`question_id`
     <if test="questionType != null">
-      and q.`question_type` = #{questionType,jdbcType=VARCHAR}
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
     </if>
-    where
-    qn.`id` &gt; 0
-    and q.`id` &gt; 0
-    <if test="userId != null">
-      and ucq.`user_id` = #{userId,jdbcType=VARCHAR}
+    order by ${order} ${direction}
+  </select>
+
+  <select id="listExamination" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
     </if>
-    <if test="startTime != null">
-      and ucq.`createTime` &gt; #{startTime,jdbcType=VARCHAR}
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
     </if>
-    <if test="endTime != null">
-      and ucq.`createTime` &lt; #{endTime,jdbcType=VARCHAR}
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
     </if>
-
     order by ${order} ${direction}
   </select>
 

+ 53 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml

@@ -27,4 +27,57 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
 
+  <select id="list" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <select id="listExercise" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <select id="listExamination" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
 </mapper>

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml

@@ -20,6 +20,42 @@
     ur.`id`
   </sql>
 
+  <select id="listExerciseError" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <select id="listExaminationError" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_paper` pp
+    left join `course` c on c.`id` = pp.`course_id`
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId, jdbcType=VARCHAR} )
+    </if>
+    where c.`id` > 0
+    <if test="courseModule != null">
+      and pp.`course_module` = #{courseModule,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and pp.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
   <!--
     用户做题记录统计
   -->

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

@@ -6,6 +6,8 @@ import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.Course;
@@ -61,6 +63,7 @@ public class PreviewController {
     @ApiOperation(value = "添加预习作业", httpMethod = "POST")
     public Response<PreviewPaper> add(@RequestBody @Validated PreviewPaperDto dto, HttpServletRequest request) {
         PreviewPaper entity = Transform.dtoToEntity(dto);
+        entity.setQuestionSubject(QuestionSubject.FromType(QuestionType.ValueOf(entity.getQuestionType())).key);
         if (dto.getCourseNo() != null){
             PreviewAssign assign = previewAssignService.getByCourseNo(dto.getCourseId(), dto.getCourseNo());
             if (assign != null){
@@ -104,11 +107,12 @@ public class PreviewController {
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) String courseModule,
+            @RequestParam(required = false) String questionType,
             @RequestParam(required = false) Integer structId,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<PreviewPaper> p = previewPaperService.listAdmin(page, size, CourseModule.ValueOf(courseModule), structId, order, DirectionStatus.ValueOf(direction));
+        Page<PreviewPaper> p = previewPaperService.listAdmin(page, size, CourseModule.ValueOf(courseModule), QuestionType.ValueOf(questionType), structId, order, DirectionStatus.ValueOf(direction));
         List<PreviewPaperListDto> pr = Transform.convert(p, PreviewPaperListDto.class);
 
         // 绑定用户

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

@@ -4,6 +4,7 @@ package com.qxgmat.controller.admin;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.AskTarget;
@@ -74,6 +75,7 @@ public class QuestionController {
     @ApiOperation(value = "添加题目", httpMethod = "POST")
     public Response<Question> add(@RequestBody @Validated QuestionDto dto, HttpServletRequest request) {
         Question entity = Transform.dtoToEntity(dto);
+        entity.setQuestionModule(QuestionModule.BASE.key);
         entity = questionService.add(entity);
         // 更新编号绑定
         questionNoService.bindQuestion(dto.getQuestionNoIds(), entity.getId());

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

@@ -692,7 +692,7 @@ public class UserController {
 
     @RequestMapping(value = "/invoice/finish", method = RequestMethod.PUT)
     @ApiOperation(value = "开发票", httpMethod = "PUT")
-    public Response<Boolean> finishData(
+    public Response<Boolean> finishInvoice(
             @RequestParam(required = false) Integer[] ids,
             HttpServletRequest request) {
         userInvoiceService.finish(ids);
@@ -702,7 +702,7 @@ public class UserController {
 
     @RequestMapping(value = "/invoice/download", method = RequestMethod.PUT)
     @ApiOperation(value = "下载资料", httpMethod = "PUT")
-    public Response<Boolean> downloadData(
+    public Response<Boolean> downloadInvoice(
             @RequestParam(required = false) Integer[] ids,
             HttpServletRequest request, HttpServletResponse response) throws IOException {
         managerLogService.log(request);
@@ -767,7 +767,7 @@ public class UserController {
 
     @RequestMapping(value = "/invoice/list", method = RequestMethod.GET)
     @ApiOperation(value = "发票列表", httpMethod = "GET")
-    public Response<PageMessage<UserInvoiceListDto>> listData(
+    public Response<PageMessage<UserInvoiceListDto>> listInvoice(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) Integer userId,

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

@@ -148,6 +148,16 @@ public class BaseController {
         return ResponseHelp.success(p);
     }
 
+    @RequestMapping(value = "/exercise/range", method = RequestMethod.GET)
+    @ApiOperation(value = "练习层级范围", httpMethod = "GET")
+    public Response<List<ExerciseStruct>> exerciseRange(
+            @RequestParam(required = true) Integer id,
+            HttpSession session) {
+        List<ExerciseStruct> p = exerciseStructService.all();
+
+        return ResponseHelp.success(p);
+    }
+
     @RequestMapping(value = "/examination/main", method = RequestMethod.GET)
     @ApiOperation(value = "所有模考头2层", httpMethod = "GET")
     public Response<List<ExaminationStruct>> examinationMain(HttpSession session) {

+ 400 - 96
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -1,5 +1,6 @@
 package com.qxgmat.controller.api;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
@@ -9,9 +10,11 @@ import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.SettingKey;
 import com.qxgmat.data.constants.enums.module.*;
+import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.entity.*;
 import com.qxgmat.dto.extend.*;
@@ -101,6 +104,9 @@ public class MyController {
     private TextbookTopicService textbookTopicService;
 
     @Autowired
+    private TextbookLibraryService textbookLibraryService;
+
+    @Autowired
     private CourseDataService courseDataService;
 
     @Autowired
@@ -603,16 +609,103 @@ public class MyController {
 
     @RequestMapping(value = "/data", method = RequestMethod.GET)
     @ApiOperation(value = "获取做题数据", notes = "获取做题数据", httpMethod = "GET")
-    public Response<UserStudyDayDto> questionData(
+    public Response<Map<String, UserDataDto>> questionData(
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String subject,
+            @RequestParam(required = false) Integer[] structIds,
             @RequestParam(required = false) String startTime,
             @RequestParam(required = false) String endTime
     )  {
         User user = (User) shiroHelp.getLoginUser();
-        UserStudyDayDto dto = new UserStudyDayDto();
 
-        // todo
+        QuestionSubject questionSubject = QuestionSubject.ValueOf(subject);
+        StructModule structModule = StructModule.ValueOf(module);
+        List<QuestionNo> questionNoList = questionNoService.listByStruct(structModule, structIds);
+        List<QuestionNoRelation> relationList = questionNoService.relation(questionNoList);
+        Map<Number, QuestionNoRelation> relationMap = new HashMap<>();
+        for(QuestionNoRelation relation : relationList){
+            relationMap.put(relation.getId(), relation);
+        }
+        List<String> questionTypes = QuestionType.FromSubject(questionSubject);
+        Map<String, UserDataDto> dtoMap = new HashMap<>();
+        for(String questionType : questionTypes){
+            UserDataDto dto = new UserDataDto();
+            JSONObject placeMap = new JSONObject();
+            JSONObject difficultMap = new JSONObject();
+
+            Integer correctTime = 0;
+            Integer incorrectTime = 0;
+
+            List<QuestionNo> list = relationList.stream().filter((row)->row.getQuestion().getQuestionType().equals(questionType)).collect(Collectors.toList());
+            PaperStat stat = questionNoService.statPaper(list);
+            dto.setTotalCorrect(stat.getTotalCorrect());
+            dto.setTotalNumber(stat.getTotalNumber());
+            dto.setTotalTime(stat.getTotalTime());
+
+            Collection questionNoIds = Transform.getIds(list, QuestionNo.class, "id");
+            List<UserQuestion> userQuestionList = userQuestionService.listByQuestionWithTime(user.getId(), QuestionModule.BASE, questionNoIds, startTime, endTime);
+            UserQuestionStat userQuestionStat = userQuestionService.statQuestion(userQuestionList);
+
+            dto.setUserCorrect(userQuestionStat.getUserCorrect());
+            dto.setUserNumber(userQuestionStat.getUserNumber());
+            dto.setUserTime(userQuestionStat.getUserTime());
+
+            for (UserQuestion userQuestion:userQuestionList){
+                QuestionNoRelation relation = relationMap.get(userQuestion.getQuestionNoId());
+
+                // 考点用时,以及正确度
+                String placeKey = relation.getQuestion().getPlace();
+                JSONObject place = placeMap.getJSONObject(placeKey);
+                if (place == null){
+                    place = new JSONObject();
+                    place.put("key", placeKey);
+                    place.put("userNumber", 1);
+                    place.put("userCorrect", userQuestion.getIsCorrect());
+                    place.put("userTime", userQuestion.getUserTime());
+                    placeMap.put(placeKey, place);
+                }else{
+                    place.put("userNumber", place.getInteger("userNumber") + 1);
+                    place.put("userCorrect", place.getInteger("userCorrect") + userQuestion.getIsCorrect());
+                    place.put("userTime", place.getInteger("userTime") + userQuestion.getUserTime());
+                }
+
+                // 难度正确度
+                String difficultKey = relation.getQuestion().getDifficult();
+                JSONObject difficult = difficultMap.getJSONObject(difficultKey);
+                if (difficult == null){
+                    difficult = new JSONObject();
+                    difficult.put("key", difficultKey);
+                    difficult.put("userNumber", 1);
+                    difficult.put("userCorrect", userQuestion.getIsCorrect());
+                    difficult.put("totalNumber", relation.getTotalNumber());
+                    difficult.put("totalCorrect", relation.getTotalCorrect());
+                    difficultMap.put(difficultKey, difficult);
+                }else{
+                    difficult.put("userNumber", difficult.getInteger("userNumber") + 1);
+                    difficult.put("userCorrect", difficult.getInteger("userCorrect") + userQuestion.getIsCorrect());
+                    difficult.put("totalNumber", difficult.getInteger("totalNumber") + relation.getTotalNumber());
+                    difficult.put("totalCorrect", difficult.getInteger("totalCorrect") + relation.getTotalCorrect());
+                }
+
+                if (userQuestion.getIsCorrect() > 0){
+                    correctTime += userQuestion.getUserTime();
+                }else{
+                    incorrectTime += userQuestion.getUserTime();
+                }
+            }
+            JSONArray difficult = new JSONArray();
+            JSONArray place = new JSONArray();
+            difficult.addAll(difficultMap.values());
+            place.addAll(placeMap.values());
+            dto.setDifficult(difficult);
+            dto.setPlace(place);
+
+            dto.setCorrectTime(correctTime);
+            dto.setIncorrectTime(incorrectTime);
+            dtoMap.put(questionType, dto);
+        }
 
-        return ResponseHelp.success(dto);
+        return ResponseHelp.success(dtoMap);
     }
 
     @RequestMapping(value = "/collect/question/add", method = RequestMethod.PUT)
@@ -634,7 +727,7 @@ public class MyController {
                 entity.setQuestionNoId(sentenceQuestion.getId());
                 break;
             case TEXTBOOK:
-                entity.setQuestionModule(QuestionModule.SENTENCE.key);
+                entity.setQuestionModule(QuestionModule.TEXTBOOK.key);
                 TextbookQuestion textbookQuestion = textbookQuestionService.get(dto.getQuestionNoId());
                 entity.setQuestionId(textbookQuestion.getQuestionId());
                 entity.setQuestionNoId(textbookQuestion.getId());
@@ -657,10 +750,10 @@ public class MyController {
 
     @RequestMapping(value = "/collect/question/bind", method = RequestMethod.POST)
     @ApiOperation(value = "收藏组卷", notes = "收藏组卷", httpMethod = "POST")
-    public Response<Boolean> bindQuestionCollect(@RequestBody @Validated UserCustomBindDto dto)  {
+    public Response<UserPaper> bindQuestionCollect(@RequestBody @Validated UserCustomBindDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
 
-        questionFlowService.makePaper(
+        UserPaper userPaper = questionFlowService.makePaper(
                 user.getId(),
                 QuestionModule.ValueOf(dto.getQuestionModule()),
                 PaperOrigin.COLLECT,
@@ -668,7 +761,7 @@ public class MyController {
                 dto.getFilterTimes()
         );
 
-        return ResponseHelp.success(true);
+        return ResponseHelp.success(userPaper);
     }
 
     @RequestMapping(value = "/collect/question/list", method = RequestMethod.GET)
@@ -676,17 +769,34 @@ public class MyController {
     public Response<PageMessage<UserCollectQuestionDto>> listQuestionCollect(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String questionModule,
-            @RequestParam(required = false) String questionType,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) Integer[] structIds,
             @RequestParam(required = false) String startTime,
             @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Boolean latest,
+            @RequestParam(required = false) String year,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
-        QuestionModule qm = QuestionModule.ValueOf(questionModule);
-        PageResult<UserCollectQuestionRelation> p = userCollectQuestionService.listQuestion(page, size, user.getId(), qm, QuestionType.ValueOf(questionType), startTime, endTime, order, DirectionStatus.ValueOf(direction));
-
+        QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
+        Page<UserCollectQuestion> p = null;
+        if(questionNoModule == QuestionNoModule.EXERCISE){
+            p = userCollectQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if (questionNoModule == QuestionNoModule.EXAMINATION){
+            Integer libraryId = null;
+            if (latest != null){
+                if (latest) {
+                    TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+                    libraryId = textbookLibrary.getId();
+                    year = null;
+                }
+            }
+            p = userCollectQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+        }else{
+            throw new ParameterException("参数逻辑错误");
+        }
         List<UserCollectQuestionDto> pr = Transform.convert(p, UserCollectQuestionDto.class);
 
         // 获取题目信息
@@ -694,21 +804,20 @@ public class MyController {
         List<Question> questionList = questionService.select(questionIds);
         Transform.combine(pr, questionList, UserCollectQuestionDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
 
-        Collection questionNoIds = Transform.getIds(pr, UserCollectQuestionDto.class, "questionNoId");
-        switch(qm){
-            case BASE:
-                List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-                Transform.combine(pr, questionNoList, UserCollectQuestionDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
-                break;
-            case SENTENCE:
-                List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(questionNoIds);
-                Transform.combine(pr, sentenceQuestionList, UserCollectQuestionDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-            case TEXTBOOK:
-                List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(questionNoIds);
-                Transform.combine(pr, textbookQuestionList, UserCollectQuestionDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-        }
+        List<UserCollectQuestionDto> basePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.BASE.key)).collect(Collectors.toList());
+        Collection baseQuestionNoIds = Transform.getIds(basePr, UserCollectQuestionDto.class, "questionNoId");
+        List<QuestionNo> baseQuestionNoList = questionNoService.select(baseQuestionNoIds);
+        Transform.combine(basePr, baseQuestionNoList, UserCollectQuestionDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
+
+        List<UserCollectQuestionDto> sentencePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.SENTENCE.key)).collect(Collectors.toList());
+        Collection sentenceQuestionNoIds = Transform.getIds(sentencePr, UserCollectQuestionDto.class, "questionNoId");
+        List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(sentenceQuestionNoIds);
+        Transform.combine(sentencePr, sentenceQuestionList, UserCollectQuestionDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
+
+        List<UserCollectQuestionDto> textbookPr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.TEXTBOOK.key)).collect(Collectors.toList());
+        Collection textbookQuestionNoIds = Transform.getIds(textbookPr, UserCollectQuestionDto.class, "questionNoId");
+        List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(textbookQuestionNoIds);
+        Transform.combine(textbookPr, textbookQuestionList, UserCollectQuestionDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
 
         // 绑定题目统计
         List<UserQuestion> userQuestionList = userQuestionService.listByQuestion(user.getId(), questionIds);
@@ -720,46 +829,68 @@ public class MyController {
 
     @RequestMapping(value = "/error/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取错题列表", notes = "获取错题列表", httpMethod = "GET")
-    public Response<PageMessage<UserQuestionErrorListDto>> listError(
+    public Response<PageMessage<UserQuestionErrorInfoDto>> listError(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String questionModule
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) Integer[] structIds,
+            @RequestParam(required = false) String startTime,
+            @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Boolean latest,
+            @RequestParam(required = false) String year,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction
     )  {
         User user = (User) shiroHelp.getLoginUser();
-        QuestionModule qm = QuestionModule.ValueOf(questionModule);
-        PageResult<UserQuestion> p = userQuestionService.listError(page, size, user.getId());
-        List<UserQuestionErrorListDto> pr = Transform.convert(p, UserQuestionErrorListDto.class);
+        QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
+        Page<UserQuestion> p = null;
+        if(questionNoModule == QuestionNoModule.EXERCISE){
+            p = userQuestionService.listExerciseError(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if (questionNoModule == QuestionNoModule.EXAMINATION){
+            Integer libraryId = null;
+            if (latest != null){
+                if (latest) {
+                    TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+                    libraryId = textbookLibrary.getId();
+                    year = null;
+                }
+            }
+            p = userQuestionService.listExaminationError(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+        }else{
+            throw new ParameterException("参数逻辑错误");
+        }
+        List<UserQuestionErrorInfoDto> pr = Transform.convert(p, UserQuestionErrorInfoDto.class);
 
         // 获取题目信息
-        Collection questionIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionId");
+        Collection questionIds = Transform.getIds(pr, UserQuestionErrorInfoDto.class, "questionId");
         List<Question> questionList = questionService.select(questionIds);
-        Transform.combine(pr, questionList, UserQuestionErrorListDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+        Transform.combine(pr, questionList, UserQuestionErrorInfoDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
 
-        Collection questionNoIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionNoId");
-        switch(qm){
-            case BASE:
-                List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-                Transform.combine(pr, questionNoList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
-                break;
-            case SENTENCE:
-                List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(questionNoIds);
-                Transform.combine(pr, sentenceQuestionList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-            case TEXTBOOK:
-                List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(questionNoIds);
-                Transform.combine(pr, textbookQuestionList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-        }
+        List<UserQuestionErrorInfoDto> basePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.BASE.key)).collect(Collectors.toList());
+        Collection baseQuestionNoIds = Transform.getIds(basePr, UserQuestionErrorInfoDto.class, "questionNoId");
+        List<QuestionNo> baseQuestionNoList = questionNoService.select(baseQuestionNoIds);
+        Transform.combine(basePr, baseQuestionNoList, UserQuestionErrorInfoDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
+
+        List<UserQuestionErrorInfoDto> sentencePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.SENTENCE.key)).collect(Collectors.toList());
+        Collection sentenceQuestionNoIds = Transform.getIds(sentencePr, UserQuestionErrorInfoDto.class, "questionNoId");
+        List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(sentenceQuestionNoIds);
+        Transform.combine(sentencePr, sentenceQuestionList, UserQuestionErrorInfoDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
+
+        List<UserQuestionErrorInfoDto> textbookPr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.TEXTBOOK.key)).collect(Collectors.toList());
+        Collection textbookQuestionNoIds = Transform.getIds(textbookPr, UserQuestionErrorInfoDto.class, "questionNoId");
+        List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(textbookQuestionNoIds);
+        Transform.combine(textbookPr, textbookQuestionList, UserQuestionErrorInfoDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
     @RequestMapping(value = "/error/bind", method = RequestMethod.POST)
     @ApiOperation(value = "错题组卷", notes = "错题组卷", httpMethod = "POST")
-    public Response<Boolean> bindError(@RequestBody @Validated UserCustomBindDto dto)  {
+    public Response<UserPaper> bindError(@RequestBody @Validated UserCustomBindDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
 
-        questionFlowService.makePaper(
+        UserPaper userPaper = questionFlowService.makePaper(
                 user.getId(),
                 QuestionModule.ValueOf(dto.getQuestionModule()),
                 PaperOrigin.ERROR,
@@ -767,7 +898,7 @@ public class MyController {
                 dto.getFilterTimes()
         );
 
-        return ResponseHelp.success(true);
+        return ResponseHelp.success(userPaper);
     }
 
     @RequestMapping(value = "/error/clear", method = RequestMethod.POST)
@@ -816,7 +947,7 @@ public class MyController {
                 entity.setQuestionNoId(sentenceQuestion.getId());
                 break;
             case TEXTBOOK:
-                entity.setQuestionModule(QuestionModule.SENTENCE.key);
+                entity.setQuestionModule(QuestionModule.TEXTBOOK.key);
                 TextbookQuestion textbookQuestion = textbookQuestionService.get(dto.getQuestionNoId());
                 entity.setQuestionId(textbookQuestion.getQuestionId());
                 entity.setQuestionNoId(textbookQuestion.getId());
@@ -830,41 +961,59 @@ public class MyController {
 
     @RequestMapping(value = "/note/question/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取题目笔记列表", notes = "获取笔记列表", httpMethod = "GET")
-    public Response<PageMessage<com.qxgmat.dto.response.UserNoteQuestionDto>> listNoteQuestion(
+    public Response<PageMessage<UserNoteQuestionInfoDto>> listNoteQuestion(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String questionModule,
-            @RequestParam(required = false) String questionType,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) Integer[] structIds,
             @RequestParam(required = false) String startTime,
             @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Boolean latest,
+            @RequestParam(required = false) String year,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
-        QuestionModule qm = QuestionModule.ValueOf(questionModule);
-        PageResult<UserNoteQuestionRelation> p = userNoteQuestionService.list(page, size, user.getId(), qm, QuestionType.ValueOf(questionType), startTime, endTime, order, DirectionStatus.ValueOf(direction));
-        List<com.qxgmat.dto.response.UserNoteQuestionDto> pr = Transform.convert(p, com.qxgmat.dto.response.UserNoteQuestionDto.class);
+        QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
+        Page<UserNoteQuestion> p = null;
+        if(questionNoModule == QuestionNoModule.EXERCISE){
+            p = userNoteQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if (questionNoModule == QuestionNoModule.EXAMINATION){
+            Integer libraryId = null;
+            if (latest != null){
+                if (latest) {
+                    TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+                    libraryId = textbookLibrary.getId();
+                    year = null;
+                }
+            }
+            p = userNoteQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+        }else{
+            throw new ParameterException("参数逻辑错误");
+        }
+        List<UserNoteQuestionInfoDto> pr = Transform.convert(p, UserNoteQuestionInfoDto.class);
 
         // 获取题目信息
-        Collection questionIds = Transform.getIds(pr, com.qxgmat.dto.response.UserNoteQuestionDto.class, "questionId");
+        Collection questionIds = Transform.getIds(pr, UserNoteQuestionInfoDto.class, "questionId");
         List<Question> questionList = questionService.select(questionIds);
-        Transform.combine(pr, questionList, com.qxgmat.dto.response.UserNoteQuestionDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+        Transform.combine(pr, questionList, UserNoteQuestionInfoDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+
+        List<UserNoteQuestionInfoDto> basePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.BASE.key)).collect(Collectors.toList());
+        Collection baseQuestionNoIds = Transform.getIds(basePr, UserNoteQuestionInfoDto.class, "questionNoId");
+        List<QuestionNo> baseQuestionNoList = questionNoService.select(baseQuestionNoIds);
+        Transform.combine(basePr, baseQuestionNoList, UserNoteQuestionInfoDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
+
+        List<UserNoteQuestionInfoDto> sentencePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.SENTENCE.key)).collect(Collectors.toList());
+        Collection sentenceQuestionNoIds = Transform.getIds(sentencePr, UserNoteQuestionInfoDto.class, "questionNoId");
+        List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(sentenceQuestionNoIds);
+        Transform.combine(sentencePr, sentenceQuestionList, UserNoteQuestionInfoDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
+
+        List<UserNoteQuestionInfoDto> textbookPr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.TEXTBOOK.key)).collect(Collectors.toList());
+        Collection textbookQuestionNoIds = Transform.getIds(textbookPr, UserNoteQuestionInfoDto.class, "questionNoId");
+        List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(textbookQuestionNoIds);
+        Transform.combine(textbookPr, textbookQuestionList, UserNoteQuestionInfoDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
 
-        Collection questionNoIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionNoId");
-        switch(qm){
-            case BASE:
-                List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-                Transform.combine(pr, questionNoList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
-                break;
-            case SENTENCE:
-                List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(questionNoIds);
-                Transform.combine(pr, sentenceQuestionList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-            case TEXTBOOK:
-                List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(questionNoIds);
-                Transform.combine(pr, textbookQuestionList, UserQuestionErrorListDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
-                break;
-        }
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
@@ -884,16 +1033,40 @@ public class MyController {
     public Response<PageMessage<UserPaperDto>> listReport(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String origin,
-            @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String origin,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) Integer[] structIds,
             @RequestParam(required = false) String startTime,
             @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Boolean latest,
+            @RequestParam(required = false) String year,
+            @RequestParam(required = false) String courseModule,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
         PaperOrigin paperOrigin = PaperOrigin.ValueOf(origin);
-        PageResult<UserPaper> p = userPaperService.list(page, size, user.getId(), paperOrigin, structId, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
+        Page<UserPaper> p = null;
+        if (questionNoModule != null && (paperOrigin == PaperOrigin.COLLECT || paperOrigin == PaperOrigin.ERROR)){
+            p = userPaperService.list(page, size, user.getId(), paperOrigin, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if(questionNoModule == QuestionNoModule.EXERCISE){
+            p = userPaperService.listExercise(page, size, user.getId(), questionTypes, structIds, courseModule, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if (questionNoModule == QuestionNoModule.EXAMINATION){
+            Integer libraryId = null;
+            if (latest != null){
+                paperOrigin = PaperOrigin.TEXTBOOK;
+                if (latest) {
+                    TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+                    libraryId = textbookLibrary.getId();
+                    year = null;
+                }
+            }
+            p = userPaperService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+        }else{
+            throw new ParameterException("参数逻辑错误");
+        }
         List<UserPaperDto> pr = Transform.convert(p, UserPaperDto.class);
 
         Collection paperIds = Transform.getIds(p, UserPaper.class, "id");
@@ -901,7 +1074,30 @@ public class MyController {
         Map<Object, Collection<UserReport>> reportByPaper = userReportService.mapByPaper(paperIds);
         Transform.combine(pr, reportByPaper, UserPaperDto.class, "id", "reports", UserReportExtendDto.class);
 
-        // 错题 -> 题型
+        // 获取试卷统计信息
+        List<UserPaperDto> basePr = pr.stream().filter((row)->QuestionModule.BASE == QuestionModule.WithPaper(PaperModule.ValueOf(row.getPaperModule()))).collect(Collectors.toList());
+        Map<Integer, Integer[]> baseIdsMap = new HashMap<>();
+        for(UserPaperDto paper : basePr){
+            baseIdsMap.put(paper.getId(), paper.getQuestionNoIds());
+        }
+        Map baseStatMap = questionNoService.statPaperMap(baseIdsMap);
+        Transform.combine(pr, baseStatMap, UserPaperDto.class, "id", "stat");
+
+        List<UserPaperDto> sentencePr = pr.stream().filter((row)->QuestionModule.SENTENCE == QuestionModule.WithPaper(PaperModule.ValueOf(row.getPaperModule()))).collect(Collectors.toList());
+        Map<Integer, Integer[]> sentenceIdsMap = new HashMap<>();
+        for(UserPaperDto paper : sentencePr){
+            sentenceIdsMap.put(paper.getId(), paper.getQuestionNoIds());
+        }
+        Map sentenceStatMap = sentenceQuestionService.statPaperMap(sentenceIdsMap);
+        Transform.combine(pr, sentenceStatMap, UserPaperDto.class, "id", "stat");
+
+        List<UserPaperDto> textbookPr = pr.stream().filter((row)->QuestionModule.TEXTBOOK == QuestionModule.WithPaper(PaperModule.ValueOf(row.getPaperModule()))).collect(Collectors.toList());
+        Map<Integer, Integer[]> textbookIdsMap = new HashMap<>();
+        for(UserPaperDto paper : textbookPr){
+            textbookIdsMap.put(paper.getId(), paper.getQuestionNoIds());
+        }
+        Map textbookStatMap = textbookQuestionService.statPaperMap(textbookIdsMap);
+        Transform.combine(pr, textbookStatMap, UserPaperDto.class, "id", "stat");
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
@@ -912,8 +1108,10 @@ public class MyController {
         UserAskQuestion entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());
+        PaperModule paperModule = PaperModule.ValueOf(dto.getPaperModule());
+        QuestionModule questionModule = QuestionModule.WithPaper(paperModule);
         Question question;
-        switch (QuestionModule.ValueOf(dto.getQuestionModule())){
+        switch (questionModule){
             case BASE:
                 entity.setQuestionModule(QuestionModule.BASE.key);
                 QuestionNo questionNo = questionNoService.get(dto.getQuestionNoId());
@@ -931,7 +1129,7 @@ public class MyController {
                 question = questionService.get(sentenceQuestion.getQuestionId());
                 break;
             case TEXTBOOK:
-                entity.setQuestionModule(QuestionModule.SENTENCE.key);
+                entity.setQuestionModule(QuestionModule.TEXTBOOK.key);
                 TextbookQuestion textbookQuestion = textbookQuestionService.get(dto.getQuestionNoId());
                 entity.setQuestionId(textbookQuestion.getQuestionId());
                 entity.setQuestionNoId(textbookQuestion.getId());
@@ -942,12 +1140,15 @@ public class MyController {
                 throw new ParameterException("题目模块错误");
         }
 
-        UserQuestion userQuestion = userQuestionService.get(dto.getUserQuestionId());
-        UserReport userReport = userReportService.get(userQuestion.getReportId());
-        entity.setAskModule(AskModule.ValueOf(userReport.getPaperModule()).key);
-
-        PaperOrigin origin = PaperOrigin.ValueOf(userReport.getPaperOrigin());
-        Integer recordId = questionFlowService.questionRelationCourse(user.getId(), origin == PaperOrigin.PREVIEW ? userReport.getOriginId() : null, QuestionType.ValueOf(question.getQuestionType()));
+        entity.setAskModule(AskModule.WithPaper(paperModule).key);
+        Integer assignId = null;
+        if (dto.getUserPaperId() != null && dto.getUserPaperId() > 0){
+            UserPaper userPaper = userPaperService.get(dto.getUserPaperId());
+            if(userPaper != null && userPaper.getPaperOrigin().equals(PaperOrigin.PREVIEW.key)){
+                assignId = userPaper.getOriginId();
+            }
+        }
+        Integer recordId = questionFlowService.questionRelationCourse(user.getId(), assignId, QuestionType.ValueOf(question.getQuestionType()));
 
         if (recordId != null){
             // 绑定提问权限
@@ -962,6 +1163,84 @@ public class MyController {
         return ResponseHelp.success(true);
     }
 
+    @RequestMapping(value = "/ask/question/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "提问删除", httpMethod = "DELETE")
+    public Response<Boolean> deleteAskQuestion(@RequestParam int id, HttpServletRequest request) {
+        UserAskQuestion in = userAskQuestionService.get(id);
+        User user = (User) shiroHelp.getLoginUser();
+        if(in == null){
+            throw new ParameterException("提问不存在");
+        }
+        if (!in.getUserId().equals(user.getId())){
+            throw new ParameterException("提问不存在");
+        }
+        if (in.getAnswerStatus()== AskStatus.ANSWER.index){
+            throw new ParameterException("提问已回答");
+        }
+        userAskQuestionService.delete(id);
+        // 如果
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/ask/question/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取题目提问列表", notes = "获取题目提问列表", httpMethod = "GET")
+    public Response<PageMessage<UserAskQuestionInfoDto>> listAskQuestion(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) String[] questionTypes,
+            @RequestParam(required = false) Integer[] structIds,
+            @RequestParam(required = false) String startTime,
+            @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Integer askStatus,
+            @RequestParam(required = false) Boolean latest,
+            @RequestParam(required = false) String year,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction,
+            HttpSession session)  {
+        User user = (User) shiroHelp.getLoginUser();
+        QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
+        Page<UserAskQuestion> p = null;
+        if(questionNoModule == QuestionNoModule.EXERCISE){
+            p = userAskQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, AskStatus.ValueOf(askStatus),startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else if (questionNoModule == QuestionNoModule.EXAMINATION){
+            Integer libraryId = null;
+            if (latest != null){
+                if (latest) {
+                    TextbookLibrary textbookLibrary = textbookLibraryService.getLatest();
+                    libraryId = textbookLibrary.getId();
+                    year = null;
+                }
+            }
+            p = userAskQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, AskStatus.ValueOf(askStatus), startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        }else{
+            throw new ParameterException("参数逻辑错误");
+        }
+        List<UserAskQuestionInfoDto> pr = Transform.convert(p, UserAskQuestionInfoDto.class);
+
+        // 获取题目信息
+        Collection questionIds = Transform.getIds(pr, UserNoteQuestionInfoDto.class, "questionId");
+        List<Question> questionList = questionService.select(questionIds);
+        Transform.combine(pr, questionList, UserNoteQuestionInfoDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+
+        List<UserAskQuestionInfoDto> basePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.BASE.key)).collect(Collectors.toList());
+        Collection baseQuestionNoIds = Transform.getIds(basePr, UserAskQuestionInfoDto.class, "questionNoId");
+        List<QuestionNo> baseQuestionNoList = questionNoService.select(baseQuestionNoIds);
+        Transform.combine(basePr, baseQuestionNoList, UserAskQuestionInfoDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
+
+        List<UserAskQuestionInfoDto> sentencePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.SENTENCE.key)).collect(Collectors.toList());
+        Collection sentenceQuestionNoIds = Transform.getIds(sentencePr, UserAskQuestionInfoDto.class, "questionNoId");
+        List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(sentenceQuestionNoIds);
+        Transform.combine(sentencePr, sentenceQuestionList, UserAskQuestionInfoDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
+
+        List<UserAskQuestionInfoDto> textbookPr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.TEXTBOOK.key)).collect(Collectors.toList());
+        Collection textbookQuestionNoIds = Transform.getIds(textbookPr, UserAskQuestionInfoDto.class, "questionNoId");
+        List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(textbookQuestionNoIds);
+        Transform.combine(textbookPr, textbookQuestionList, UserAskQuestionInfoDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/ask/course", method = RequestMethod.POST)
     @ApiOperation(value = "添加课程提问", notes = "添加课程提问", httpMethod = "POST")
     public Response<Boolean> addAskCourse(@RequestBody @Validated UserAskCourseDto dto)  {
@@ -985,19 +1264,43 @@ public class MyController {
 
     @RequestMapping(value = "/feedback/error/question", method = RequestMethod.POST)
     @ApiOperation(value = "添加题目勘误", notes = "添加勘误", httpMethod = "POST")
-    public Response<Boolean> addFeedbackErrorQuestion(@RequestBody @Validated UserFeedbackErrorDto dto)  {
+    public Response<Boolean> addFeedbackErrorQuestion(@RequestBody @Validated UserFeedbackErrorQuestionDto dto)  {
         UserFeedbackError entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());
         entity.setModule(FeedbackModule.QUESTION.key);
         entity.setStatus(0);
 
-        UserQuestion userQuestion = userQuestionService.get(dto.getUserQuestionId());
-        Question question = questionService.get(userQuestion.getQuestionId());
+        Question question;
+        switch (QuestionModule.ValueOf(dto.getQuestionModule())){
+            case BASE:
+                entity.setQuestionModule(QuestionModule.BASE.key);
+                QuestionNo questionNo = questionNoService.get(dto.getQuestionNoId());
+                entity.setModuleId(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.setModuleId(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.setModuleId(textbookQuestion.getQuestionId());
+                entity.setQuestionNoId(textbookQuestion.getId());
+
+                question = questionService.get(textbookQuestion.getQuestionId());
+                break;
+            default:
+                throw new ParameterException("题目模块错误");
+        }
         entity.setQuestionType(question.getQuestionType());
-        entity.setModuleId(userQuestion.getQuestionId());
-        entity.setQuestionModule(userQuestion.getQuestionModule());
-        entity.setQuestionNoId(userQuestion.getQuestionNoId());
         userFeedbackErrorService.add(entity);
 
         return ResponseHelp.success(true);
@@ -1005,11 +1308,12 @@ public class MyController {
 
     @RequestMapping(value = "/feedback/error/data", method = RequestMethod.POST)
     @ApiOperation(value = "添加资料勘误", notes = "添加勘误", httpMethod = "POST")
-    public Response<Boolean> addFeedbackError(@RequestBody @Validated UserFeedbackErrorDto dto)  {
+    public Response<Boolean> addFeedbackError(@RequestBody @Validated UserFeedbackErrorDataDto dto)  {
         UserFeedbackError entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());
         entity.setModule(FeedbackModule.DATA.key);
+        entity.setModuleId(dto.getDataId());
         entity.setStatus(0);
         userFeedbackErrorService.add(entity);
 

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

@@ -133,7 +133,7 @@ public class QuestionController {
             Map<Object, UserQuestionStat> userQuestionStatMap = null;
             if(user != null){
                 Collection questionNoIds = Transform.getIds(list, QuestionNo.class, "id");
-                List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), questionNoIds);
+                List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), QuestionModule.BASE, questionNoIds);
                 userQuestionStatMap = userQuestionService.statQuestionNoMap(userQuestionList);
 
                 dto.setUserStat(userQuestionService.statQuestion(userQuestionList));

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

@@ -9,6 +9,7 @@ import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
+import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.UserQuestionStat;
@@ -118,7 +119,7 @@ public class TextbookController
                     dto.setUnUseRecord(Transform.convert(record, UserServiceRecordExtendDto.class));
                 }
                 Collection questionNoIds = Transform.getIds(list, QuestionNo.class, "id");
-                List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), questionNoIds);
+                List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), QuestionModule.TEXTBOOK, questionNoIds);
                 userQuestionStatMap = userQuestionService.statQuestionNoMap(userQuestionList);
 
                 dto.setUserStat(userQuestionService.statQuestion(userQuestionList));
@@ -185,6 +186,7 @@ public class TextbookController
 
         TextbookLibrary latest = textbookLibraryService.getLatest();
         dto.setLatest(latest);
+        dto.setHasService(false);
         if (user != null){
             UserService userService = userServiceService.getService(user.getId(), ServiceKey.TEXTBOOK);
             dto.setHasService(userService != null);
@@ -194,6 +196,12 @@ public class TextbookController
             dto.setSubscribe(userService != null && userService.getIsSubscribe() > 0);
             dto.setExpireTime(userService != null ? userService.getExpireTime() : null);
         }
+        if (!dto.getHasService()){
+            // 移除数据
+            latest.setRc("");
+            latest.setIr("");
+            latest.setQuant("");
+        }
         TextbookLibrary second = textbookLibraryService.getSecond();
         dto.setSecond(second);
 

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/PreviewPaperDto.java

@@ -12,6 +12,8 @@ public class PreviewPaperDto {
 
     private String title;
 
+    private String questionType;
+
     private Integer courseId;
 
     private String courseModule;
@@ -77,4 +79,12 @@ public class PreviewPaperDto {
     public void setPaperModule(String paperModule) {
         this.paperModule = paperModule;
     }
+
+    public String getQuestionType() {
+        return questionType;
+    }
+
+    public void setQuestionType(String questionType) {
+        this.questionType = questionType;
+    }
 }

+ 12 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/QuestionExtendDto.java

@@ -11,9 +11,13 @@ public class QuestionExtendDto {
     private String description;
 
     private String type;
+
     private String difficult;
+
     private String place;
 
+    private Integer collectionNumber;
+
     public Integer getId() {
         return id;
     }
@@ -53,4 +57,12 @@ public class QuestionExtendDto {
     public void setDescription(String description) {
         this.description = description;
     }
+
+    public Integer getCollectionNumber() {
+        return collectionNumber;
+    }
+
+    public void setCollectionNumber(Integer collectionNumber) {
+        this.collectionNumber = collectionNumber;
+    }
 }

+ 131 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserAskQuestionExtendDto.java

@@ -3,6 +3,137 @@ package com.qxgmat.dto.extend;
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserAskQuestion;
 
+import java.util.Date;
+
 @Dto(entity = UserAskQuestion.class)
 public class UserAskQuestionExtendDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer userQuestionId;
+
+    private String questionModule;
+
+    private Integer questionId;
+
+    private Integer questionNoId;
+
+    private String target;
+
+    private Integer answerStatus;
+
+    private Date answerTime;
+
+    private Date createTime;
+
+    private Date updateTime;
+
+    private String content;
+
+    private String answer;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getUserQuestionId() {
+        return userQuestionId;
+    }
+
+    public void setUserQuestionId(Integer userQuestionId) {
+        this.userQuestionId = userQuestionId;
+    }
+
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    public Integer getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Integer questionId) {
+        this.questionId = questionId;
+    }
+
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+    public Integer getAnswerStatus() {
+        return answerStatus;
+    }
+
+    public void setAnswerStatus(Integer answerStatus) {
+        this.answerStatus = answerStatus;
+    }
+
+    public Date getAnswerTime() {
+        return answerTime;
+    }
+
+    public void setAnswerTime(Date answerTime) {
+        this.answerTime = answerTime;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
 }

+ 14 - 14
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskQuestionDto.java

@@ -6,11 +6,11 @@ import com.qxgmat.data.dao.entity.UserNoteQuestion;
 
 @Dto(entity = UserAskQuestion.class)
 public class UserAskQuestionDto {
-    private Integer userQuestionId;
+    private Integer userPaperId;
 
     private String target;
 
-    private String questionModule;
+    private String paperModule;
 
     private Integer questionNoId;
 
@@ -42,14 +42,6 @@ public class UserAskQuestionDto {
         this.target = target;
     }
 
-    public String getQuestionModule() {
-        return questionModule;
-    }
-
-    public void setQuestionModule(String questionModule) {
-        this.questionModule = questionModule;
-    }
-
     public String getOriginContent() {
         return originContent;
     }
@@ -58,11 +50,19 @@ public class UserAskQuestionDto {
         this.originContent = originContent;
     }
 
-    public Integer getUserQuestionId() {
-        return userQuestionId;
+    public String getPaperModule() {
+        return paperModule;
+    }
+
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
+    }
+
+    public Integer getUserPaperId() {
+        return userPaperId;
     }
 
-    public void setUserQuestionId(Integer userQuestionId) {
-        this.userQuestionId = userQuestionId;
+    public void setUserPaperId(Integer userPaperId) {
+        this.userPaperId = userPaperId;
     }
 }

+ 6 - 6
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorDto.java

@@ -4,8 +4,8 @@ import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserFeedbackError;
 
 @Dto(entity = UserFeedbackError.class)
-public class UserFeedbackErrorDto {
-    private Integer userQuestionId;
+public class UserFeedbackErrorDataDto {
+    private Integer dataId;
 
     private String title;
 
@@ -47,11 +47,11 @@ public class UserFeedbackErrorDto {
         this.title = title;
     }
 
-    public Integer getUserQuestionId() {
-        return userQuestionId;
+    public Integer getDataId() {
+        return dataId;
     }
 
-    public void setUserQuestionId(Integer userQuestionId) {
-        this.userQuestionId = userQuestionId;
+    public void setDataId(Integer dataId) {
+        this.dataId = dataId;
     }
 }

+ 67 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorQuestionDto.java

@@ -0,0 +1,67 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserFeedbackError;
+
+@Dto(entity = UserFeedbackError.class)
+public class UserFeedbackErrorQuestionDto {
+    private String questionModule;
+
+    private Integer questionNoId;
+
+    private String title;
+
+    private String position;
+
+    private String originContent;
+
+    private String content;
+
+    public String getPosition() {
+        return position;
+    }
+
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    public String getOriginContent() {
+        return originContent;
+    }
+
+    public void setOriginContent(String originContent) {
+        this.originContent = originContent;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
+}

+ 161 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserAskQuestionInfoDto.java

@@ -0,0 +1,161 @@
+package com.qxgmat.dto.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserAskQuestion;
+import com.qxgmat.dto.extend.QuestionExtendDto;
+import com.qxgmat.dto.extend.QuestionNoExtendDto;
+
+import java.util.Date;
+
+@Dto(entity = UserAskQuestion.class)
+public class UserAskQuestionInfoDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer userQuestionId;
+
+    private String questionModule;
+
+    private Integer questionId;
+
+    private Integer questionNoId;
+
+    private QuestionExtendDto question;
+
+    private QuestionNoExtendDto questionNo;
+
+    private String target;
+
+    private Integer answerStatus;
+
+    private Date answerTime;
+
+    private Date createTime;
+
+    private Date updateTime;
+
+    private String content;
+
+    private String answer;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getUserQuestionId() {
+        return userQuestionId;
+    }
+
+    public void setUserQuestionId(Integer userQuestionId) {
+        this.userQuestionId = userQuestionId;
+    }
+
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    public Integer getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Integer questionId) {
+        this.questionId = questionId;
+    }
+
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
+
+    public QuestionExtendDto getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(QuestionExtendDto question) {
+        this.question = question;
+    }
+
+    public QuestionNoExtendDto getQuestionNo() {
+        return questionNo;
+    }
+
+    public void setQuestionNo(QuestionNoExtendDto questionNo) {
+        this.questionNo = questionNo;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+    public Integer getAnswerStatus() {
+        return answerStatus;
+    }
+
+    public void setAnswerStatus(Integer answerStatus) {
+        this.answerStatus = answerStatus;
+    }
+
+    public Date getAnswerTime() {
+        return answerTime;
+    }
+
+    public void setAnswerTime(Date answerTime) {
+        this.answerTime = answerTime;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(String answer) {
+        this.answer = answer;
+    }
+}

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

@@ -12,6 +12,12 @@ import java.util.Date;
 public class UserCollectQuestionDto {
     private Integer id;
 
+    private String questionModule;
+
+    private Integer questionId;
+
+    private Integer questionNoId;
+
     private QuestionExtendDto question;
 
     private QuestionNoExtendDto questionNo;
@@ -59,4 +65,28 @@ public class UserCollectQuestionDto {
     public void setStat(UserQuestionStat stat) {
         this.stat = stat;
     }
+
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    public Integer getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Integer questionId) {
+        this.questionId = questionId;
+    }
+
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
 }

+ 105 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserDataDto.java

@@ -0,0 +1,105 @@
+package com.qxgmat.dto.response;
+
+import com.alibaba.fastjson.JSONArray;
+
+public class UserDataDto {
+    private Integer totalNumber;
+
+    private Integer totalTime;
+
+    private Integer totalCorrect;
+
+    private Integer userNumber;
+
+    private Integer userCorrect;
+
+    private Integer userTime;
+
+    private Integer correctTime;
+
+    private Integer incorrectTime;
+
+    private JSONArray difficult;
+
+    private JSONArray place;
+
+    public Integer getTotalNumber() {
+        return totalNumber;
+    }
+
+    public void setTotalNumber(Integer totalNumber) {
+        this.totalNumber = totalNumber;
+    }
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+    public Integer getTotalCorrect() {
+        return totalCorrect;
+    }
+
+    public void setTotalCorrect(Integer totalCorrect) {
+        this.totalCorrect = totalCorrect;
+    }
+
+    public Integer getUserNumber() {
+        return userNumber;
+    }
+
+    public void setUserNumber(Integer userNumber) {
+        this.userNumber = userNumber;
+    }
+
+    public Integer getUserCorrect() {
+        return userCorrect;
+    }
+
+    public void setUserCorrect(Integer userCorrect) {
+        this.userCorrect = userCorrect;
+    }
+
+    public Integer getUserTime() {
+        return userTime;
+    }
+
+    public void setUserTime(Integer userTime) {
+        this.userTime = userTime;
+    }
+
+    public Integer getCorrectTime() {
+        return correctTime;
+    }
+
+    public void setCorrectTime(Integer correctTime) {
+        this.correctTime = correctTime;
+    }
+
+    public Integer getIncorrectTime() {
+        return incorrectTime;
+    }
+
+    public void setIncorrectTime(Integer incorrectTime) {
+        this.incorrectTime = incorrectTime;
+    }
+
+    public JSONArray getDifficult() {
+        return difficult;
+    }
+
+    public void setDifficult(JSONArray difficult) {
+        this.difficult = difficult;
+    }
+
+    public JSONArray getPlace() {
+        return place;
+    }
+
+    public void setPlace(JSONArray place) {
+        this.place = place;
+    }
+}

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserNoteQuestionDto.java

@@ -7,7 +7,7 @@ import com.qxgmat.dto.extend.QuestionNoExtendDto;
 import java.util.Date;
 
 @Dto(entity = UserNoteQuestion.class)
-public class UserNoteQuestionDto {
+public class UserNoteQuestionInfoDto {
     private Integer id;
 
     private String questionModule;

+ 61 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserPaperDto.java

@@ -3,6 +3,7 @@ package com.qxgmat.dto.response;
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserPaper;
 import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.dto.extend.UserReportExtendDto;
 
 import java.util.Date;
@@ -15,8 +16,20 @@ public class UserPaperDto {
 
     private String title;
 
+    private String paperModule;
+
+    private Integer[] questionNoIds;
+
+    private PaperStat stat;
+
     private List<UserReportExtendDto> reports;
 
+    private Integer totalTime;
+
+    private Integer totalNumber;
+
+    private Integer totalCorrect;
+
     public Integer getId() {
         return id;
     }
@@ -40,4 +53,52 @@ public class UserPaperDto {
     public void setReports(List<UserReportExtendDto> reports) {
         this.reports = reports;
     }
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+    public Integer getTotalNumber() {
+        return totalNumber;
+    }
+
+    public void setTotalNumber(Integer totalNumber) {
+        this.totalNumber = totalNumber;
+    }
+
+    public Integer getTotalCorrect() {
+        return totalCorrect;
+    }
+
+    public void setTotalCorrect(Integer totalCorrect) {
+        this.totalCorrect = totalCorrect;
+    }
+
+    public PaperStat getStat() {
+        return stat;
+    }
+
+    public void setStat(PaperStat stat) {
+        this.stat = stat;
+    }
+
+    public String getPaperModule() {
+        return paperModule;
+    }
+
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
+    }
+
+    public Integer[] getQuestionNoIds() {
+        return questionNoIds;
+    }
+
+    public void setQuestionNoIds(Integer[] questionNoIds) {
+        this.questionNoIds = questionNoIds;
+    }
 }

+ 11 - 1
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionErrorListDto.java

@@ -8,13 +8,15 @@ import com.qxgmat.dto.extend.QuestionNoExtendDto;
 import java.util.Date;
 
 @Dto(entity = UserQuestion.class)
-public class UserQuestionErrorListDto {
+public class UserQuestionErrorInfoDto {
     private Integer id;
 
     private Integer questionId;
 
     private Integer questionNoId;
 
+    private String questionModule;
+
     private QuestionExtendDto question;
 
     private QuestionNoExtendDto questionNo;
@@ -68,4 +70,12 @@ public class UserQuestionErrorListDto {
     public void setQuestionNoId(Integer questionNoId) {
         this.questionNoId = questionNoId;
     }
+
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
 }

+ 34 - 7
server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java

@@ -42,24 +42,51 @@ public class UserCollectQuestionService extends AbstractService {
      * @param page
      * @param size
      * @param userId
-     * @param type
      * @return
      */
-    public PageResult<UserCollectQuestionRelation> listQuestion(int page, int size, Integer userId, QuestionModule module, QuestionType type, String startTime, String endTime, String order, DirectionStatus direction){
-        String moduleKey = module == null ? null : module.key;
-        String typeKey = type == null ? null : type.key;
+    public Page<UserCollectQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
         Page<UserCollectQuestion> p = page(()->{
-            userCollectQuestionRelationMapper.list(userId, moduleKey, typeKey, startTime, endTime, order, direction.key);
+            userCollectQuestionRelationMapper.listExercise(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserCollectQuestion.class, "id");
 
         // 获取详细数据
         List<UserCollectQuestion> list = select(ids);
+        Transform.replace(p, list, UserCollectQuestion.class, "id");
+        return p;
+    }
+
+    /**
+     * 获取用户题目收藏列表
+     * @param page
+     * @param size
+     * @param userId
+     * @return
+     */
+    public Page<UserCollectQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserCollectQuestion> p = page(()->{
+            userCollectQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
 
-        List<UserCollectQuestionRelation> pr = Transform.convert(list, UserCollectQuestionRelation.class);
+        Collection ids = Transform.getIds(p, UserCollectQuestion.class, "id");
 
-        return new PageResult<>(pr, p.getTotal());
+        // 获取详细数据
+        List<UserCollectQuestion> list = select(ids);
+        Transform.replace(p, list, UserCollectQuestion.class, "id");
+        return p;
     }
 
     /**

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

@@ -44,29 +44,62 @@ public class UserNoteQuestionService extends AbstractService {
      * @param page
      * @param size
      * @param userId
-     * @param module
-     * @param type
+     * @param questionTypes
+     * @param structIds
      * @param startTime
      * @param endTime
      * @param order
      * @param direction
      * @return
      */
-    public PageResult<UserNoteQuestionRelation> list(int page, int size, Integer userId, QuestionModule module, QuestionType type, String startTime, String endTime, String order, DirectionStatus direction){
-        String moduleKey = module == null ? null : module.key;
-        String typeKey = type == null ? null : type.key;
+    public Page<UserNoteQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
         Page<UserNoteQuestion> p = page(()->{
-            userNoteQuestionRelationMapper.list(userId, moduleKey, typeKey, startTime, endTime, order, direction.key);
+            userNoteQuestionRelationMapper.listExercise(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserNoteQuestion.class, "id");
 
         // 获取详细数据
         List<UserNoteQuestion> list = select(ids);
+        Transform.replace(p, list, UserNoteQuestion.class, "id");
+        return p;
+    }
+    /**
+     * 获取用户笔记列表
+     * @param page
+     * @param size
+     * @param userId
+     * @param questionTypes
+     * @param structIds
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<UserNoteQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserNoteQuestion> p = page(()->{
+            userNoteQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
 
-        List<UserNoteQuestionRelation> pr = Transform.convert(list, UserNoteQuestionRelation.class);
+        Collection ids = Transform.getIds(p, UserNoteQuestion.class, "id");
 
-        return new PageResult<>(pr, p.getTotal());
+        // 获取详细数据
+        List<UserNoteQuestion> list = select(ids);
+        Transform.replace(p, list, UserNoteQuestion.class, "id");
+        return p;
     }
 
     /**

+ 77 - 4
server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONObject;
 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;
@@ -55,19 +56,91 @@ public class UserPaperService extends AbstractService {
      * @param size
      * @param userId
      * @param origin
-     * @param structId
      * @param startTime
      * @param endTime
      * @param order
      * @param direction
      * @return
      */
-    public PageResult<UserPaper> list(int page, int size, Integer userId, PaperOrigin origin, Integer structId, String startTime, String endTime, String order, DirectionStatus direction){
-        // todo
-        return new PageResult<>(null, 0);
+    public Page<UserPaper> list(int page, int size, Integer userId, PaperOrigin origin, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserPaper> p = page(()->{
+            userPaperRelationMapper.list(userId, origin != null ? origin.key : null, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+
+        // 获取详细数据
+        List<UserPaper> list = select(ids);
+        Transform.replace(p, list, UserPaper.class, "id");
+        return p;
+    }
+
+    /**
+     * 获取报告列表:以paper进行分组
+     * @param page
+     * @param size
+     * @param userId
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<UserPaper> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String courseModule, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserPaper> p = page(()->{
+            userPaperRelationMapper.listExercise(userId, questionTypes, structIds, courseModule, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+
+        // 获取详细数据
+        List<UserPaper> list = select(ids);
+        Transform.replace(p, list, UserPaper.class, "id");
+        return p;
     }
 
     /**
+     * 获取报告列表:以paper进行分组
+     * @param page
+     * @param size
+     * @param userId
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<UserPaper> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserPaper> p = page(()->{
+            userPaperRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+
+        // 获取详细数据
+        List<UserPaper> list = select(ids);
+        Transform.replace(p, list, UserPaper.class, "id");
+        return p;
+    }
+    /**
      * 获取用户做题记录
      * @param userId
      * @param origin

+ 69 - 5
server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java

@@ -10,6 +10,7 @@ import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.module.PaperModule;
 import com.qxgmat.data.constants.enums.module.QuestionModule;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.UserQuestionMapper;
 import com.qxgmat.data.dao.entity.UserQuestion;
 import com.qxgmat.data.dao.entity.UserReport;
@@ -40,15 +41,63 @@ public class UserQuestionService extends AbstractService {
     private UserQuestionRelationMapper userQuestionRelationMapper;
 
     /**
-     * 用户错题记录:相同题目的最后一次做题记录及其编号
+     * 获取报告列表:以paper进行分组
      * @param page
      * @param size
      * @param userId
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<UserQuestion> listExerciseError(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserQuestion> p = page(()->{
+            userQuestionRelationMapper.listExerciseError(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, UserQuestion.class, "id");
+
+        // 获取详细数据
+        List<UserQuestion> list = select(ids);
+        Transform.replace(p, list, UserQuestion.class, "id");
+        return p;
+    }
+
+    /**
+     * 获取报告列表:以paper进行分组
+     * @param page
+     * @param size
+     * @param userId
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
      * @return
      */
-    public PageResult<UserQuestion> listError(int page, int size, Integer userId){
-        // todo 查询错题列表
-        return new PageResult<>(null, 0);
+    public Page<UserQuestion> listExaminationError(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserQuestion> p = page(()->{
+            userQuestionRelationMapper.listExaminationError(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, size);
+
+        Collection ids = Transform.getIds(p, UserQuestion.class, "id");
+
+        // 获取详细数据
+        List<UserQuestion> list = select(ids);
+        Transform.replace(p, list, UserQuestion.class, "id");
+        return p;
     }
 
     /**
@@ -83,13 +132,28 @@ public class UserQuestionService extends AbstractService {
         return select(userQuestionMapper, example);
     }
 
-    public List<UserQuestion> listByQuestionNo(Integer userId, Collection questionNoIds){
+    public List<UserQuestion> listByQuestionNo(Integer userId, QuestionModule questionModule, Collection questionNoIds){
+        if (questionNoIds == null || questionNoIds.size() == 0) return new ArrayList<>();
+        Example example = new Example(UserQuestion.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("questionModule", questionModule.key)
+                        .andIn("questionNoId", questionNoIds)
+        );
+        return select(userQuestionMapper, example);
+    }
+
+    public List<UserQuestion> listByQuestionWithTime(Integer userId, QuestionModule questionModule, Collection questionNoIds, String startTime, String endTime){
         if (questionNoIds == null || questionNoIds.size() == 0) return new ArrayList<>();
         Example example = new Example(UserQuestion.class);
         example.and(
                 example.createCriteria()
                         .andEqualTo("userId", userId)
+                        .andEqualTo("questionModule", questionModule.key)
                         .andIn("questionNoId", questionNoIds)
+                        .andGreaterThanOrEqualTo("createTime", startTime)
+                        .andLessThan("createTime", endTime)
         );
         return select(userQuestionMapper, example);
     }

+ 2 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/SentenceService.java

@@ -4,6 +4,7 @@ import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
+import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.UserReportRelationMapper;
 import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
@@ -62,6 +63,7 @@ public class SentenceService {
         }
         Question question = relation.getQuestion();
         question.setQuestionType(QuestionType.SENTENCE.key);
+        question.setQuestionModule(QuestionModule.SENTENCE.key);
         question = questionService.add(question);
         // 绑定关系
         relation.setQuestionId(question.getId());

+ 2 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java

@@ -3,6 +3,7 @@ package com.qxgmat.service.extend;
 import com.nuliji.tools.Tools;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
+import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.TextbookLibrary;
 import com.qxgmat.data.dao.entity.TextbookPaper;
@@ -75,6 +76,7 @@ public class TextbookService {
     @Transactional
     public TextbookQuestion addQuestion(TextbookQuestionRelation relation){
         Question question = relation.getQuestion();
+        question.setQuestionModule(QuestionModule.TEXTBOOK.key);
         question = questionService.add(question);
         // 绑定关系
         relation.setQuestionId(question.getId());

+ 2 - 2
server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewPaperService.java

@@ -43,9 +43,9 @@ public class PreviewPaperService extends AbstractService {
     @Resource
     private PreviewPaperRelationMapper previewPaperRelationMapper;
 
-    public Page<PreviewPaper> listAdmin(int page, int size, CourseModule courseModule, Integer structId, String order, DirectionStatus direction){
+    public Page<PreviewPaper> listAdmin(int page, int size, CourseModule courseModule, QuestionType questionType, Integer structId, String order, DirectionStatus direction){
         Page<PreviewPaper> p = page(() -> {
-            previewPaperRelationMapper.listAdmin(courseModule != null ? courseModule.key : null, structId, order, direction != null ? direction.key : null);
+            previewPaperRelationMapper.listAdmin(courseModule != null ? courseModule.key : null, questionType != null ? questionType.key : null, structId, order, direction != null ? direction.key : null);
         }, page, size);
 
         Collection ids = Transform.getIds(p, PreviewPaper.class, "id");

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

@@ -107,6 +107,27 @@ public class QuestionNoService extends AbstractService {
     /**
      * 获取结构模块下的题目列表: 按序号排列
      * @param module
+     * @param structIds
+     * @return
+     */
+    public List<QuestionNo> listByStruct(StructModule module, Integer[] structIds){
+        Example example = new Example(QuestionNo.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("module", module.key)
+        );
+        Example.Criteria criteria = example.createCriteria();
+        for(Integer structId : structIds){
+            criteria.orCondition(String.format(formatSet, structId, "module_struct"));
+        }
+        example.and(criteria);
+        example.orderBy("no").asc();
+        return select(questionNoMapper, example);
+    }
+
+    /**
+     * 获取结构模块下的题目列表: 按序号排列
+     * @param module
      * @param structId
      * @return
      */

+ 32 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java

@@ -34,6 +34,38 @@ public class UserAskQuestionService extends AbstractService {
     @Resource
     private UserAskQuestionRelationMapper userAskQuestionRelationMapper;
 
+    public Page<UserAskQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, AskStatus status, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserAskQuestion> p = page(
+            ()-> userAskQuestionRelationMapper.listExercise(userId, questionTypes, structIds, status != null ? status.index:null, startTime, endTime, finalOrder, finalDirection.key)
+        , page, size);
+
+        Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");
+        Transform.replace(p, select(ids), UserAskQuestion.class, "id");
+        return p;
+    }
+
+    public Page<UserAskQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, AskStatus status, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserAskQuestion> p = page(
+                ()-> userAskQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, status != null ? status.index:null, startTime, endTime, finalOrder, finalDirection.key)
+                , page, size);
+
+        Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");
+        Transform.replace(p, select(ids), UserAskQuestion.class, "id");
+        return p;
+    }
+
     public Page<UserAskQuestion> listWithUser(int page, int size, String askModule, String questionType, String questionModule, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, Boolean hasRecord,String order, DirectionStatus direction){
         String tk = target != null ? target.key : "";
         Integer statusIndex = status != null ? status.index : null;

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

@@ -72,6 +72,7 @@ public class UserReportService extends AbstractService {
                 example.createCriteria()
                         .andIn("paperId", paperIds)
         );
+        example.orderBy("id").asc();
         List<UserReport> userClassList = select(userReportMapper, example);
         if(userClassList.size() == 0) return relationMap;
         for(UserReport row: userClassList){