Pārlūkot izejas kodu

feat(server): 更新用户相关接口

Go 5 gadi atpakaļ
vecāks
revīzija
2ffb53367a
84 mainītis faili ar 2719 papildinājumiem un 832 dzēšanām
  1. 1 1
      front/project/Constant.js
  2. 1 1
      front/project/admin/routes/subject/exercise/page.js
  3. 18 4
      front/project/admin/routes/subject/question/page.js
  4. 11 0
      front/project/admin/routes/subject/sentenceArticle/index.less
  5. 30 1
      front/project/admin/routes/subject/sentenceArticle/page.js
  6. 18 0
      front/project/admin/routes/subject/sentenceQuestion/index.less
  7. 272 39
      front/project/admin/routes/subject/sentenceQuestion/page.js
  8. 2 2
      front/project/admin/routes/subject/textbookQuestion/page.js
  9. 4 2
      front/src/components/Editor/index.js
  10. 4 4
      front/src/services/Tools.js
  11. 4 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionDifficult.java
  12. 17 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/StructModule.java
  13. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/PreviewPaper.java
  14. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/SentenceArticle.java
  15. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/SentenceQuestion.java
  16. 210 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibrary.java
  17. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibraryHistory.java
  18. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PreviewPaperMapper.xml
  19. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/SentenceArticleMapper.xml
  20. 3 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/SentenceQuestionMapper.xml
  21. 5 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookLibraryHistoryMapper.xml
  22. 8 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookLibraryMapper.xml
  23. 36 0
      server/data/src/main/java/com/qxgmat/data/inline/UserQuestionStat.java
  24. 0 24
      server/data/src/main/java/com/qxgmat/data/relation/ExerciseQuestionRelationMapper.java
  25. 25 0
      server/data/src/main/java/com/qxgmat/data/relation/QuestionNoRelationMapper.java
  26. 1 0
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperQuestionRelationMapper.java
  27. 21 1
      server/data/src/main/java/com/qxgmat/data/relation/entity/UserCollectQuestionRelation.java
  28. 21 1
      server/data/src/main/java/com/qxgmat/data/relation/entity/UserNoteQuestionRelation.java
  29. 0 54
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExerciseQuestionRelationMapper.xml
  30. 73 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionNoRelationMapper.xml
  31. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookQuestionRelationMapper.xml
  32. 42 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperQuestionRelationMapper.xml
  33. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserReportRelationMapper.xml
  34. 2 2
      server/gateway-api/src/main/java/com/qxgmat/Application.java
  35. 30 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExaminationController.java
  36. 24 20
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExerciseController.java
  37. 12 6
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java
  38. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  39. 7 6
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SentenceController.java
  40. 1 14
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java
  41. 5 2
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  42. 5 2
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  43. 83 19
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  44. 6 2
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  45. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/SentenceController.java
  46. 27 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/ExaminationPaperExtendDto.java
  47. 51 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/ExaminationQuestionListDto.java
  48. 16 15
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/ExerciseQuestionListDto.java
  49. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/QuestionNoExtendDto.java
  50. 6 15
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCollectQuestionDto.java
  51. 160 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserNoteQuestionDetailDto.java
  52. 1 1
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserNoteDetailDto.java
  53. 29 9
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionErrorListDto.java
  54. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserSentenceArticleDto.java
  55. 0 282
      server/gateway-api/src/main/java/com/qxgmat/service/SentencePaperService.java
  56. 0 16
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java
  57. 0 16
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  58. 3 3
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  59. 52 4
      server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java
  60. 121 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java
  61. 200 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExerciseService.java
  62. 4 3
      server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageService.java
  63. 7 73
      server/gateway-api/src/main/java/com/qxgmat/service/PreviewService.java
  64. 33 4
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  65. 165 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/SentenceService.java
  66. 1 3
      server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java
  67. 10 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java
  68. 1 11
      server/gateway-api/src/main/java/com/qxgmat/service/ExaminationPaperService.java
  69. 0 3
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExaminationStructService.java
  70. 50 56
      server/gateway-api/src/main/java/com/qxgmat/service/ExercisePaperService.java
  71. 0 36
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExerciseQuestionService.java
  72. 92 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewPaperService.java
  73. 21 11
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java
  74. 6 6
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionService.java
  75. 154 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/SentencePaperService.java
  76. 16 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java
  77. 19 8
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryService.java
  78. 2 23
      server/gateway-api/src/main/java/com/qxgmat/service/TextbookPaperService.java
  79. 0 3
      server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookQuestionService.java
  80. 0 3
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserClassService.java
  81. 38 6
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserPaperQuestionService.java
  82. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java
  83. 189 1
      server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java
  84. 3 0
      server/gateway-api/src/main/resources/application.yml

+ 1 - 1
front/project/Constant.js

@@ -69,7 +69,7 @@ export const ExaminationOrder = [{ list: ['awa', 'ir', 'quant', 'verbal'] }, { l
 //   // aws作文内容
 //   aws: '',
 //   // sentence
-//   subject: [],
+//   subject: [[{ text: '', uuid: '' }, { text: '', uuid: '' }], [{ text: '', uuid: '' }]],
 //   predicate: [],
 //   object: [],
 //   options: [],

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

@@ -20,7 +20,7 @@ const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 
 const filterForm = [
   {
-    key: 'type',
+    key: 'questionType',
     type: 'select',
     allowClear: true,
     name: '题型',

+ 18 - 4
front/project/admin/routes/subject/question/page.js

@@ -1,5 +1,5 @@
 import React from 'react';
-import { Tabs, Form, Tag, InputNumber, Radio, Row, Col, Checkbox, Icon, Input, Button, List, Cascader } from 'antd';
+import { Tabs, Form, Tag, InputNumber, Radio, Row, Col, Checkbox, Icon, Input, Button, List, Cascader, Switch } from 'antd';
 import './index.less';
 import DragList from '@src/components/DragList';
 import Editor from '@src/components/Editor';
@@ -111,6 +111,8 @@ export default class extends Page {
           }).then(rr => {
             // 阅读关联题目: 只有一个id
             if (rr.length === 1 && rr[0].relationQuestion && rr[0].relationQuestion.length > 0) {
+              form.getFieldDecorator('rcType');
+              form.setFieldsValue({ rcType: true });
               this.bindRelationQuestion(rr[0].relationQuestion);
             } else {
               this.bindRelationQuestion();
@@ -551,8 +553,9 @@ export default class extends Page {
 
   renderAttr() {
     const { getFieldDecorator, getFieldValue, setFieldsValue } = this.props.form;
-    const { questionNos = [] } = this.state;
+    // const { questionNos = [] } = this.state;
     const isRc = getFieldValue('questionType') === 'rc';
+    const rcType = getFieldValue('rcType') || false;
     return <Block flex>
       <h1>题目属性</h1>
       <Form>
@@ -586,8 +589,19 @@ export default class extends Page {
           )}
         </Form.Item>
         {/* 阅读题,并且只有一个id才能关联 */}
-        {isRc && questionNos.length === 1 && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='关联题目'>
-          {getFieldDecorator('relationQuestion')(
+        {isRc && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='阅读题模式' >
+          {getFieldDecorator('rcType', {
+            valuePropName: 'checked',
+          })(
+            <Switch checkedChildren='on' unCheckedChildren='off' />,
+          )}
+        </Form.Item>}
+        {rcType && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='关联题目'>
+          {getFieldDecorator('relationQuestion', {
+            rules: [{
+              required: true, message: '请输入关联题目',
+            }],
+          })(
             <Select mode='multiple' maxTagCount={200} notFoundContent={null} placeholder='输入题目id, 逗号分隔' tokenSeparators={[',', ',']} {...this.state.relationQuestion} onChange={(values) => {
               this.listQuestion(values, 'ids', 'relationQuestionNos');
               // this.setState({ relationQuestion: values });

+ 11 - 0
front/project/admin/routes/subject/sentenceArticle/index.less

@@ -4,4 +4,15 @@
   .ql-editor {
     height: 200px;
   }
+
+  .simulation {
+    width: 940px;
+    line-height: 20px;
+
+    p {
+      line-height: 20px;
+      padding: 0;
+      margin: 0;
+    }
+  }
 }

+ 30 - 1
front/project/admin/routes/subject/sentenceArticle/page.js

@@ -14,8 +14,10 @@ import config from './index';
 export default class extends Page {
   constructor(props) {
     super(props);
+    this.preview = null;
     this.structMap = {};
     this.partList = [];
+    this.pageLine = 100;
 
     const { id } = this.params;
 
@@ -67,16 +69,26 @@ export default class extends Page {
     handler
       .then(result => {
         this.data = result;
+        this.content = result.content || '';
         form.setFieldsValue(result);
       });
   }
 
+  computePages() {
+    if (!this.preview) return 0;
+    this.preview.style.display = 'block';
+    const lines = this.preview.clientHeight / 20;
+    this.preview.style.display = 'none';
+    return Math.ceil(lines / this.pageLine);
+  }
+
   submit() {
     const { form } = this.props;
     form.validateFields((err) => {
       if (!err) {
         const data = form.getFieldsValue();
         data.isTrail = data.isTrail ? 1 : 0;
+        data.pages = this.computePages();
         let handler;
         if (!data.id) {
           handler = Sentence.editArticle(data);
@@ -93,6 +105,13 @@ export default class extends Page {
     });
   }
 
+  changeContent(content) {
+    this.content = content;
+    if (this.preview) {
+      this.preview.innerHTML = content;
+    }
+  }
+
   renderBase() {
     const { getFieldDecorator, getFieldValue } = this.props.form;
     return <Block>
@@ -170,10 +189,20 @@ export default class extends Page {
         <Form.Item label='文章录入'>
           {getFieldDecorator('content', {
           })(
-            <Editor placeholder='输入内容' />,
+            <Editor placeholder='输入内容'
+              onChange={(value) => {
+                this.changeContent(value);
+              }} />,
           )}
         </Form.Item>
       </Form>
+      <div ref={(ref) => {
+        if (ref) {
+          this.preview = ref;
+          this.preview.style.display = 'none';
+          this.changeContent(this.content);
+        }
+      }} className='simulation' />
     </Block>;
   }
 

+ 18 - 0
front/project/admin/routes/subject/sentenceQuestion/index.less

@@ -19,4 +19,22 @@
   .ant-checkbox-group-item {
     margin-right: 50px;
   }
+
+  .stem-content {
+    cursor: pointer;
+    margin: 10px;
+
+    p {
+      margin: 0;
+      padding: 0;
+    }
+
+    span:hover {
+      border-bottom: 1px solid burlywood;
+    }
+
+    i:hover {
+      border-bottom: 1px solid burlywood;
+    }
+  }
 }

Failā izmaiņas netiks attēlotas, jo tās ir par lielu
+ 272 - 39
front/project/admin/routes/subject/sentenceQuestion/page.js


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

@@ -170,9 +170,9 @@ export default class extends Page {
         // [data.startTime, data.endTime] = data.time;
         let handler;
         if (!data.id) {
-          handler = Textbook.editQuestion(data);
-        } else {
           handler = Textbook.addQuestion(data);
+        } else {
+          handler = Textbook.editQuestion(data);
         }
         handler.then((result) => {
           asyncSMessage('保存成功');

+ 4 - 2
front/src/components/Editor/index.js

@@ -1,7 +1,7 @@
 import React from 'react';
 import ReactQuill from 'react-quill';
 import 'react-quill/dist/quill.snow.css';
-import { uuid } from '../../services/Tools';
+import { generateUUID } from '../../services/Tools';
 
 const modules = {
   toolbar: {
@@ -85,7 +85,7 @@ class Editor extends React.Component {
           const range = quill.getSelection(true);
           const file = fileInput.files[0];
           const suffix = file.name.substring(file.name.lastIndexOf('.')).toLowerCase();
-          const name = uuid();
+          const name = generateUUID();
           self.props
             .onUpload(file, self.props.path, self.progress, `${self.props.path}/${name}${suffix}`)
             .then(data => {
@@ -104,6 +104,7 @@ class Editor extends React.Component {
   }
 
   render() {
+    // console.log(this.props.value);
     return (
       <div>
         <ReactQuill
@@ -115,6 +116,7 @@ class Editor extends React.Component {
           onChange={(content, delta, source, editor) => {
             if (this.props.onChange) this.props.onChange(content, delta, source, editor);
           }}
+          defaultValue={this.props.defaultValue || ''}
           value={this.props.value || ''}
           modules={this.modules}
           formats={this.formats}

+ 4 - 4
front/src/services/Tools.js

@@ -84,14 +84,14 @@ export function loadScript(url, callback) {
   script.async = true;
   script.defer = true;
   if (script.readyState) {
-    script.onreadystatechange = function() {
+    script.onreadystatechange = function () {
       if (script.readyState === 'loaded' || script.readyState === 'complete') {
         script.onreadystatechange = null;
         if (callback) callback();
       }
     };
   } else {
-    script.onload = function() {
+    script.onload = function () {
       if (callback) callback();
     };
   }
@@ -100,7 +100,7 @@ export function loadScript(url, callback) {
   head.appendChild(script);
 }
 
-export function uuid(len, radix) {
+export function generateUUID(len, radix) {
   const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('');
   const id = [];
   radix = radix || chars.length;
@@ -418,7 +418,7 @@ export function getHtmlText(text) {
   let html = '';
   text.split('\r').forEach(item => {
     item.split(' ').forEach(t => {
-      html += `<i uuid="${uuid(4)}">${t}</i>`;
+      html += `<i uuid="${generateUUID(4)}">${t}</i>`;
     });
     html += '<br/>';
   });

+ 4 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionDifficult.java

@@ -44,4 +44,8 @@ public enum QuestionDifficult {
                 return 0;
         }
     }
+
+    public static QuestionDifficult[] all(){
+        return new QuestionDifficult[]{EASY, MEDIUM, HARD};
+    }
 }

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

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

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

@@ -54,6 +54,12 @@ public class PreviewPaper implements Serializable {
     private Integer[] userIds;
 
     /**
+     * 做题时间
+     */
+    @Column(name = "`time`")
+    private Integer time;
+
+    /**
      * 作业开始时间
      */
     @Column(name = "`start_time`")
@@ -220,6 +226,24 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
+     * 获取做题时间
+     *
+     * @return time - 做题时间
+     */
+    public Integer getTime() {
+        return time;
+    }
+
+    /**
+     * 设置做题时间
+     *
+     * @param time 做题时间
+     */
+    public void setTime(Integer time) {
+        this.time = time;
+    }
+
+    /**
      * 获取作业开始时间
      *
      * @return start_time - 作业开始时间
@@ -315,6 +339,7 @@ public class PreviewPaper implements Serializable {
         sb.append(", mode=").append(mode);
         sb.append(", questionType=").append(questionType);
         sb.append(", userIds=").append(userIds);
+        sb.append(", time=").append(time);
         sb.append(", startTime=").append(startTime);
         sb.append(", endTime=").append(endTime);
         sb.append(", finish=").append(finish);
@@ -414,6 +439,16 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
+         * 设置做题时间
+         *
+         * @param time 做题时间
+         */
+        public Builder time(Integer time) {
+            obj.setTime(time);
+            return this;
+        }
+
+        /**
          * 设置作业开始时间
          *
          * @param startTime 作业开始时间

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

@@ -47,6 +47,12 @@ public class SentenceArticle implements Serializable {
     private Integer trailEnd;
 
     /**
+     * 页数
+     */
+    @Column(name = "`pages`")
+    private Integer pages;
+
+    /**
      * 内容
      */
     @Column(name = "`content`")
@@ -177,6 +183,24 @@ public class SentenceArticle implements Serializable {
     }
 
     /**
+     * 获取页数
+     *
+     * @return pages - 页数
+     */
+    public Integer getPages() {
+        return pages;
+    }
+
+    /**
+     * 设置页数
+     *
+     * @param pages 页数
+     */
+    public void setPages(Integer pages) {
+        this.pages = pages;
+    }
+
+    /**
      * 获取内容
      *
      * @return content - 内容
@@ -207,6 +231,7 @@ public class SentenceArticle implements Serializable {
         sb.append(", isTrail=").append(isTrail);
         sb.append(", trailStart=").append(trailStart);
         sb.append(", trailEnd=").append(trailEnd);
+        sb.append(", pages=").append(pages);
         sb.append(", content=").append(content);
         sb.append("]");
         return sb.toString();
@@ -292,6 +317,16 @@ public class SentenceArticle implements Serializable {
         }
 
         /**
+         * 设置页数
+         *
+         * @param pages 页数
+         */
+        public Builder pages(Integer pages) {
+            obj.setPages(pages);
+            return this;
+        }
+
+        /**
          * 设置内容
          *
          * @param content 内容

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

@@ -35,6 +35,12 @@ public class SentenceQuestion implements Serializable {
     private Integer no;
 
     /**
+     * 根据序号生成的固定标题
+     */
+    @Column(name = "`subject`")
+    private String subject;
+
+    /**
      * 题目id
      */
     @Column(name = "`question_id`")
@@ -150,6 +156,24 @@ public class SentenceQuestion implements Serializable {
     }
 
     /**
+     * 获取根据序号生成的固定标题
+     *
+     * @return subject - 根据序号生成的固定标题
+     */
+    public String getSubject() {
+        return subject;
+    }
+
+    /**
+     * 设置根据序号生成的固定标题
+     *
+     * @param subject 根据序号生成的固定标题
+     */
+    public void setSubject(String subject) {
+        this.subject = subject;
+    }
+
+    /**
      * 获取题目id
      *
      * @return question_id - 题目id
@@ -246,6 +270,7 @@ public class SentenceQuestion implements Serializable {
         sb.append(", isTrail=").append(isTrail);
         sb.append(", isPaper=").append(isPaper);
         sb.append(", no=").append(no);
+        sb.append(", subject=").append(subject);
         sb.append(", questionId=").append(questionId);
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalNumber=").append(totalNumber);
@@ -315,6 +340,16 @@ public class SentenceQuestion implements Serializable {
         }
 
         /**
+         * 设置根据序号生成的固定标题
+         *
+         * @param subject 根据序号生成的固定标题
+         */
+        public Builder subject(String subject) {
+            obj.setSubject(subject);
+            return this;
+        }
+
+        /**
          * 设置题目id
          *
          * @param questionId 题目id

+ 210 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibrary.java

@@ -30,18 +30,54 @@ public class TextbookLibrary implements Serializable {
     private String quant;
 
     /**
+     * 数学版本
+     */
+    @Column(name = "`quant_version`")
+    private Integer quantVersion;
+
+    /**
+     * 数学时间
+     */
+    @Column(name = "`quant_time`")
+    private Date quantTime;
+
+    /**
      * 综合逻辑
      */
     @Column(name = "`ir`")
     private String ir;
 
     /**
+     * 综合逻辑版本
+     */
+    @Column(name = "`ir_version`")
+    private Integer irVersion;
+
+    /**
+     * 综合逻辑时间
+     */
+    @Column(name = "`ir_time`")
+    private Date irTime;
+
+    /**
      * 阅读
      */
     @Column(name = "`rc`")
     private String rc;
 
     /**
+     * 阅读版本
+     */
+    @Column(name = "`rc_version`")
+    private Integer rcVersion;
+
+    /**
+     * 阅读时间
+     */
+    @Column(name = "`rc_time`")
+    private Date rcTime;
+
+    /**
      * 更新次数
      */
     @Column(name = "`history_number`")
@@ -124,6 +160,42 @@ public class TextbookLibrary implements Serializable {
     }
 
     /**
+     * 获取数学版本
+     *
+     * @return quant_version - 数学版本
+     */
+    public Integer getQuantVersion() {
+        return quantVersion;
+    }
+
+    /**
+     * 设置数学版本
+     *
+     * @param quantVersion 数学版本
+     */
+    public void setQuantVersion(Integer quantVersion) {
+        this.quantVersion = quantVersion;
+    }
+
+    /**
+     * 获取数学时间
+     *
+     * @return quant_time - 数学时间
+     */
+    public Date getQuantTime() {
+        return quantTime;
+    }
+
+    /**
+     * 设置数学时间
+     *
+     * @param quantTime 数学时间
+     */
+    public void setQuantTime(Date quantTime) {
+        this.quantTime = quantTime;
+    }
+
+    /**
      * 获取综合逻辑
      *
      * @return ir - 综合逻辑
@@ -142,6 +214,42 @@ public class TextbookLibrary implements Serializable {
     }
 
     /**
+     * 获取综合逻辑版本
+     *
+     * @return ir_version - 综合逻辑版本
+     */
+    public Integer getIrVersion() {
+        return irVersion;
+    }
+
+    /**
+     * 设置综合逻辑版本
+     *
+     * @param irVersion 综合逻辑版本
+     */
+    public void setIrVersion(Integer irVersion) {
+        this.irVersion = irVersion;
+    }
+
+    /**
+     * 获取综合逻辑时间
+     *
+     * @return ir_time - 综合逻辑时间
+     */
+    public Date getIrTime() {
+        return irTime;
+    }
+
+    /**
+     * 设置综合逻辑时间
+     *
+     * @param irTime 综合逻辑时间
+     */
+    public void setIrTime(Date irTime) {
+        this.irTime = irTime;
+    }
+
+    /**
      * 获取阅读
      *
      * @return rc - 阅读
@@ -160,6 +268,42 @@ public class TextbookLibrary implements Serializable {
     }
 
     /**
+     * 获取阅读版本
+     *
+     * @return rc_version - 阅读版本
+     */
+    public Integer getRcVersion() {
+        return rcVersion;
+    }
+
+    /**
+     * 设置阅读版本
+     *
+     * @param rcVersion 阅读版本
+     */
+    public void setRcVersion(Integer rcVersion) {
+        this.rcVersion = rcVersion;
+    }
+
+    /**
+     * 获取阅读时间
+     *
+     * @return rc_time - 阅读时间
+     */
+    public Date getRcTime() {
+        return rcTime;
+    }
+
+    /**
+     * 设置阅读时间
+     *
+     * @param rcTime 阅读时间
+     */
+    public void setRcTime(Date rcTime) {
+        this.rcTime = rcTime;
+    }
+
+    /**
      * 获取更新次数
      *
      * @return history_number - 更新次数
@@ -215,8 +359,14 @@ public class TextbookLibrary implements Serializable {
         sb.append(", startDate=").append(startDate);
         sb.append(", endDate=").append(endDate);
         sb.append(", quant=").append(quant);
+        sb.append(", quantVersion=").append(quantVersion);
+        sb.append(", quantTime=").append(quantTime);
         sb.append(", ir=").append(ir);
+        sb.append(", irVersion=").append(irVersion);
+        sb.append(", irTime=").append(irTime);
         sb.append(", rc=").append(rc);
+        sb.append(", rcVersion=").append(rcVersion);
+        sb.append(", rcTime=").append(rcTime);
         sb.append(", historyNumber=").append(historyNumber);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
@@ -274,6 +424,26 @@ public class TextbookLibrary implements Serializable {
         }
 
         /**
+         * 设置数学时间
+         *
+         * @param quantTime 数学时间
+         */
+        public Builder quantTime(Date quantTime) {
+            obj.setQuantTime(quantTime);
+            return this;
+        }
+
+        /**
+         * 设置数学版本
+         *
+         * @param quantVersion 数学版本
+         */
+        public Builder quantVersion(Integer quantVersion) {
+            obj.setQuantVersion(quantVersion);
+            return this;
+        }
+
+        /**
          * 设置综合逻辑
          *
          * @param ir 综合逻辑
@@ -284,6 +454,26 @@ public class TextbookLibrary implements Serializable {
         }
 
         /**
+         * 设置综合逻辑时间
+         *
+         * @param irTime 综合逻辑时间
+         */
+        public Builder irTime(Date irTime) {
+            obj.setIrTime(irTime);
+            return this;
+        }
+
+        /**
+         * 设置综合逻辑版本
+         *
+         * @param irVersion 综合逻辑版本
+         */
+        public Builder irVersion(Integer irVersion) {
+            obj.setIrVersion(irVersion);
+            return this;
+        }
+
+        /**
          * 设置阅读
          *
          * @param rc 阅读
@@ -294,6 +484,26 @@ public class TextbookLibrary implements Serializable {
         }
 
         /**
+         * 设置阅读时间
+         *
+         * @param rcTime 阅读时间
+         */
+        public Builder rcTime(Date rcTime) {
+            obj.setRcTime(rcTime);
+            return this;
+        }
+
+        /**
+         * 设置阅读版本
+         *
+         * @param rcVersion 阅读版本
+         */
+        public Builder rcVersion(Integer rcVersion) {
+            obj.setRcVersion(rcVersion);
+            return this;
+        }
+
+        /**
          * 设置更新次数
          *
          * @param historyNumber 更新次数

+ 105 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibraryHistory.java

@@ -24,17 +24,35 @@ public class TextbookLibraryHistory implements Serializable {
     private String quant;
 
     /**
+     * 数学版本
+     */
+    @Column(name = "`quant_version`")
+    private Integer quantVersion;
+
+    /**
      * 阅读
      */
     @Column(name = "`rc`")
     private String rc;
 
     /**
+     * 阅读版本
+     */
+    @Column(name = "`rc_version`")
+    private Integer rcVersion;
+
+    /**
      * 综合推理
      */
     @Column(name = "`ir`")
     private String ir;
 
+    /**
+     * 综合推理版本
+     */
+    @Column(name = "`ir_version`")
+    private Integer irVersion;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -97,6 +115,24 @@ public class TextbookLibraryHistory implements Serializable {
     }
 
     /**
+     * 获取数学版本
+     *
+     * @return quant_version - 数学版本
+     */
+    public Integer getQuantVersion() {
+        return quantVersion;
+    }
+
+    /**
+     * 设置数学版本
+     *
+     * @param quantVersion 数学版本
+     */
+    public void setQuantVersion(Integer quantVersion) {
+        this.quantVersion = quantVersion;
+    }
+
+    /**
      * 获取阅读
      *
      * @return rc - 阅读
@@ -115,6 +151,24 @@ public class TextbookLibraryHistory implements Serializable {
     }
 
     /**
+     * 获取阅读版本
+     *
+     * @return rc_version - 阅读版本
+     */
+    public Integer getRcVersion() {
+        return rcVersion;
+    }
+
+    /**
+     * 设置阅读版本
+     *
+     * @param rcVersion 阅读版本
+     */
+    public void setRcVersion(Integer rcVersion) {
+        this.rcVersion = rcVersion;
+    }
+
+    /**
      * 获取综合推理
      *
      * @return ir - 综合推理
@@ -133,6 +187,24 @@ public class TextbookLibraryHistory implements Serializable {
     }
 
     /**
+     * 获取综合推理版本
+     *
+     * @return ir_version - 综合推理版本
+     */
+    public Integer getIrVersion() {
+        return irVersion;
+    }
+
+    /**
+     * 设置综合推理版本
+     *
+     * @param irVersion 综合推理版本
+     */
+    public void setIrVersion(Integer irVersion) {
+        this.irVersion = irVersion;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -173,8 +245,11 @@ public class TextbookLibraryHistory implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", libraryId=").append(libraryId);
         sb.append(", quant=").append(quant);
+        sb.append(", quantVersion=").append(quantVersion);
         sb.append(", rc=").append(rc);
+        sb.append(", rcVersion=").append(rcVersion);
         sb.append(", ir=").append(ir);
+        sb.append(", irVersion=").append(irVersion);
         sb.append(", createTime=").append(createTime);
         sb.append(", content=").append(content);
         sb.append("]");
@@ -221,6 +296,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
 
         /**
+         * 设置数学版本
+         *
+         * @param quantVersion 数学版本
+         */
+        public Builder quantVersion(Integer quantVersion) {
+            obj.setQuantVersion(quantVersion);
+            return this;
+        }
+
+        /**
          * 设置阅读
          *
          * @param rc 阅读
@@ -231,6 +316,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
 
         /**
+         * 设置阅读版本
+         *
+         * @param rcVersion 阅读版本
+         */
+        public Builder rcVersion(Integer rcVersion) {
+            obj.setRcVersion(rcVersion);
+            return this;
+        }
+
+        /**
          * 设置综合推理
          *
          * @param ir 综合推理
@@ -241,6 +336,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
 
         /**
+         * 设置综合推理版本
+         *
+         * @param irVersion 综合推理版本
+         */
+        public Builder irVersion(Integer irVersion) {
+            obj.setIrVersion(irVersion);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

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

@@ -13,6 +13,7 @@
     <result column="mode" jdbcType="INTEGER" property="mode" />
     <result column="question_type" jdbcType="VARCHAR" property="questionType" />
     <result column="user_ids" jdbcType="VARCHAR" property="userIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
+    <result column="time" jdbcType="INTEGER" property="time" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
     <result column="finish" jdbcType="INTEGER" property="finish" />
@@ -24,6 +25,6 @@
       WARNING - @mbg.generated
     -->
     `id`, `title`, `course_id`, `course_no`, `question_no_ids`, `mode`, `question_type`, 
-    `user_ids`, `start_time`, `end_time`, `finish`, `create_time`, `update_time`
+    `user_ids`, `time`, `start_time`, `end_time`, `finish`, `create_time`, `update_time`
   </sql>
 </mapper>

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

@@ -12,6 +12,7 @@
     <result column="is_trail" jdbcType="INTEGER" property="isTrail" />
     <result column="trail_start" jdbcType="INTEGER" property="trailStart" />
     <result column="trail_end" jdbcType="INTEGER" property="trailEnd" />
+    <result column="pages" jdbcType="INTEGER" property="pages" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.SentenceArticle">
     <!--
@@ -23,7 +24,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `chapter`, `part`, `is_trail`, `trail_start`, `trail_end`
+    `id`, `title`, `chapter`, `part`, `is_trail`, `trail_start`, `trail_end`, `pages`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -10,6 +10,7 @@
     <result column="is_trail" jdbcType="INTEGER" property="isTrail" />
     <result column="is_paper" jdbcType="INTEGER" property="isPaper" />
     <result column="no" jdbcType="INTEGER" property="no" />
+    <result column="subject" jdbcType="VARCHAR" property="subject" />
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
@@ -25,8 +26,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `is_trail`, `is_paper`, `no`, `question_id`, `total_time`, `total_number`, 
-    `total_correct`
+    `id`, `title`, `is_trail`, `is_paper`, `no`, `subject`, `question_id`, `total_time`, 
+    `total_number`, `total_correct`
   </sql>
   <sql id="Blob_Column_List">
     <!--

+ 5 - 1
server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookLibraryHistoryMapper.xml

@@ -8,8 +8,11 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="library_id" jdbcType="INTEGER" property="libraryId" />
     <result column="quant" jdbcType="VARCHAR" property="quant" />
+    <result column="quant_version" jdbcType="INTEGER" property="quantVersion" />
     <result column="rc" jdbcType="VARCHAR" property="rc" />
+    <result column="rc_version" jdbcType="INTEGER" property="rcVersion" />
     <result column="ir" jdbcType="VARCHAR" property="ir" />
+    <result column="ir_version" jdbcType="INTEGER" property="irVersion" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.TextbookLibraryHistory">
@@ -22,7 +25,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `library_id`, `quant`, `rc`, `ir`, `create_time`
+    `id`, `library_id`, `quant`, `quant_version`, `rc`, `rc_version`, `ir`, `ir_version`, 
+    `create_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -9,8 +9,14 @@
     <result column="start_date" jdbcType="VARCHAR" property="startDate" />
     <result column="end_date" jdbcType="VARCHAR" property="endDate" />
     <result column="quant" jdbcType="VARCHAR" property="quant" />
+    <result column="quant_version" jdbcType="INTEGER" property="quantVersion" />
+    <result column="quant_time" jdbcType="TIMESTAMP" property="quantTime" />
     <result column="ir" jdbcType="VARCHAR" property="ir" />
+    <result column="ir_version" jdbcType="INTEGER" property="irVersion" />
+    <result column="ir_time" jdbcType="TIMESTAMP" property="irTime" />
     <result column="rc" jdbcType="VARCHAR" property="rc" />
+    <result column="rc_version" jdbcType="INTEGER" property="rcVersion" />
+    <result column="rc_time" jdbcType="TIMESTAMP" property="rcTime" />
     <result column="history_number" jdbcType="INTEGER" property="historyNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
@@ -19,7 +25,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `start_date`, `end_date`, `quant`, `ir`, `rc`, `history_number`, `create_time`, 
-    `update_time`
+    `id`, `start_date`, `end_date`, `quant`, `quant_version`, `quant_time`, `ir`, `ir_version`, 
+    `ir_time`, `rc`, `rc_version`, `rc_time`, `history_number`, `create_time`, `update_time`
   </sql>
 </mapper>

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/inline/UserQuestionStat.java

@@ -0,0 +1,36 @@
+package com.qxgmat.data.inline;
+
+public class UserQuestionStat {
+    // 总做题时间
+    private Integer userTime;
+
+    // 总做题数
+    private Integer userNumber;
+
+    // 总正确次数
+    private Integer userCorrect;
+
+    public Integer getUserTime() {
+        return userTime;
+    }
+
+    public void setUserTime(Integer userTime) {
+        this.userTime = userTime;
+    }
+
+    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;
+    }
+}

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

@@ -1,24 +0,0 @@
-package com.qxgmat.data.relation;
-
-import com.qxgmat.data.dao.entity.ExercisePaperQuestion;
-import org.apache.ibatis.annotations.Param;
-
-import java.util.List;
-
-/**
- * Created by gaojie on 2017/11/9.
- */
-public interface ExerciseQuestionRelationMapper {
-    List<ExercisePaperQuestion> listAdmin(
-            @Param("questionType") String questionType,
-            @Param("structId") Number structId,
-            @Param("questionNoId") Number questionNoId,
-            @Param("paperId") Number paperId,
-            @Param("place") String place,
-            @Param("difficult") String difficult,
-            @Param("startTime") String startTime,
-            @Param("endTime") String endTime,
-            @Param("order") String order,
-            @Param("direction") String direction
-    );
-}

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

@@ -2,6 +2,7 @@ package com.qxgmat.data.relation;
 
 import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.QuestionNo;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.List;
@@ -21,4 +22,28 @@ public interface QuestionNoRelationMapper {
     List<QuestionNo> searchStem(
             @Param("stem") String stem
     );
+
+    List<QuestionNoRelation> listExerciseAdmin(
+            @Param("questionType") String questionType,
+            @Param("structId") Number structId,
+            @Param("questionNoId") Number questionNoId,
+            @Param("paperId") Number paperId,
+            @Param("place") String place,
+            @Param("difficult") String difficult,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime,
+            @Param("order") String order,
+            @Param("direction") String direction
+    );
+
+    List<QuestionNoRelation> listExaminationAdmin(
+            @Param("questionType") String questionType,
+            @Param("structId") Number structId,
+            @Param("questionNoId") Number questionNoId,
+            @Param("paperId") Number paperId,
+            @Param("place") String place,
+            @Param("difficult") String difficult,
+            @Param("order") String order,
+            @Param("direction") String direction
+    );
 }

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

@@ -14,6 +14,7 @@ public interface UserPaperQuestionRelationMapper {
     List<UserPaperQuestion> filterTimes(
             @Param("userId") Number userId,
             @Param("questionOrigin") String origin,
+            @Param("questionModule") String module,
             @Param("questionNoIds") Collection questionNoIds,
             @Param("filterTimes") Number filterTimes
     );

+ 21 - 1
server/data/src/main/java/com/qxgmat/data/relation/entity/UserCollectQuestionRelation.java

@@ -9,9 +9,13 @@ public class UserCollectQuestionRelation extends UserCollectQuestion {
 
     private Question question;
 
+    private User user;
+
     private QuestionNo questionNo;
 
-    private User user;
+    private SentenceQuestion sentence;
+
+    private TextbookQuestion textbook;
 
     public User getUser() {
         return user;
@@ -36,4 +40,20 @@ public class UserCollectQuestionRelation extends UserCollectQuestion {
     public void setQuestionNo(QuestionNo questionNo) {
         this.questionNo = questionNo;
     }
+
+    public SentenceQuestion getSentence() {
+        return sentence;
+    }
+
+    public void setSentence(SentenceQuestion sentence) {
+        this.sentence = sentence;
+    }
+
+    public TextbookQuestion getTextbook() {
+        return textbook;
+    }
+
+    public void setTextbook(TextbookQuestion textbook) {
+        this.textbook = textbook;
+    }
 }

+ 21 - 1
server/data/src/main/java/com/qxgmat/data/relation/entity/UserNoteQuestionRelation.java

@@ -9,9 +9,13 @@ public class UserNoteQuestionRelation extends UserNoteQuestion {
 
     private Question question;
 
+    private User user;
+
     private QuestionNo questionNo;
 
-    private User user;
+    private SentenceQuestion sentence;
+
+    private TextbookQuestion textbook;
 
     public User getUser() {
         return user;
@@ -36,4 +40,20 @@ public class UserNoteQuestionRelation extends UserNoteQuestion {
     public void setQuestionNo(QuestionNo questionNo) {
         this.questionNo = questionNo;
     }
+
+    public SentenceQuestion getSentence() {
+        return sentence;
+    }
+
+    public void setSentence(SentenceQuestion sentence) {
+        this.sentence = sentence;
+    }
+
+    public TextbookQuestion getTextbook() {
+        return textbook;
+    }
+
+    public void setTextbook(TextbookQuestion textbook) {
+        this.textbook = textbook;
+    }
 }

+ 0 - 54
server/data/src/main/java/com/qxgmat/data/relation/mapping/ExerciseQuestionRelationMapper.xml

@@ -1,54 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.qxgmat.data.relation.ExerciseQuestionRelationMapper">
-  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.ExercisePaperQuestion">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    <id column="id" jdbcType="INTEGER" property="id" />
-  </resultMap>
-  <sql id="Id_Column_List">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    epq.`id`
-  </sql>
-
-  <select id="listAdmin" resultMap="IdMap">
-    select
-    <include refid="Id_Column_List" />
-    from `exercise_paper_question` epq
-    left join `question` q on q.`id` = epq.`question_id`
-    left join `question_no` qn on qn.`id` = epq.`question_no_id`
-    <if test="structId != null">
-    left join `exercise_paper` ep on ep.`id` = epg.`paper_id`
-        and ep.`id` = #{paperId,jdbcType=VARCHAR}
-    </if>
-    where qn.`module` = "exercise"
-    <if test="paperId != null">
-      and epq.`paper_id` != null
-    </if>
-    <if test="structId != null">
-      and find_in_set(#{structId,jdbcType=VARCHAR}, qn.`module_struct`)
-    </if>
-    <if test="questionNoId != null">
-      and qn.`id` =#{questionNoId,jdbcType=VARCHAR}
-    </if>
-    <if test="questionType != null">
-      and q.`question_type` =#{questionType,jdbcType=VARCHAR}
-    </if>
-    <if test="place != null">
-      and q.`place` =#{place,jdbcType=VARCHAR}
-    </if>
-    <if test="difficult != null">
-      and q.`difficult` =#{difficult,jdbcType=VARCHAR}
-    </if>
-    <if test="startTime != null">
-      and hp.`update_time` &gt; #{startTime,jdbcType=VARCHAR}
-    </if>
-    <if test="endTime != null">
-      and hp.`update_time` &lt; #{endTime,jdbcType=VARCHAR}
-    </if>
-    order by ${order} ${direction}
-  </select>
-</mapper>

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

@@ -38,4 +38,77 @@
       q.`id` != null
   </select>
 
+  <!--
+    后台练习题目搜索
+  -->
+  <select id="listExerciseAdmin" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    form `question_no` qn
+    left join `question` q on q.`id` = qn.`question_id`
+    <if test="paperId != null">
+      left join `exercise_paper` ep on find_in_set(qn.`id`, ep.`question_no_ids`)
+      and ep.`id` = #{paperId,jdbcType=VARCHAR}
+    </if>
+    where qn.`module` = "exercise"
+    <if test="paperId != null">
+      and ep.`id` != null
+    </if>
+    <if test="structId != null">
+      and find_in_set(#{structId,jdbcType=VARCHAR}, qn.`module_struct`)
+    </if>
+    <if test="questionNoId != null">
+      and qn.`id` =#{questionNoId,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and q.`question_type` =#{questionType,jdbcType=VARCHAR}
+    </if>
+    <if test="place != null">
+      and q.`place` =#{place,jdbcType=VARCHAR}
+    </if>
+    <if test="difficult != null">
+      and q.`difficult` =#{difficult,jdbcType=VARCHAR}
+    </if>
+    <if test="startTime != null">
+      and hp.`update_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and hp.`update_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <!--
+    后台模考题目搜索
+  -->
+  <select id="listExaminationAdmin" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    form `question_no` qn
+    left join `question` q on q.`id` = qn.`question_id`
+    <if test="paperId != null">
+      left join `examination_paper` ep on find_in_set(qn.`id`, ep.`question_no_ids`)
+      and ep.`id` = #{paperId,jdbcType=VARCHAR}
+    </if>
+    where qn.`module` = "examination"
+    <if test="paperId != null">
+      and ep.`id` != null
+    </if>
+    <if test="structId != null">
+      and find_in_set(#{structId,jdbcType=VARCHAR}, qn.`module_struct`)
+    </if>
+    <if test="questionNoId != null">
+      and qn.`id` =#{questionNoId,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and q.`question_type` =#{questionType,jdbcType=VARCHAR}
+    </if>
+    <if test="place != null">
+      and q.`place` =#{place,jdbcType=VARCHAR}
+    </if>
+    <if test="difficult != null">
+      and q.`difficult` =#{difficult,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
 </mapper>

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

@@ -30,7 +30,7 @@
     <include refid="Id_Column_List" />
     from `textbook_question` tq
     <if test="paperId != null">
-      left join `textbook_paper` tp on find_in_set(tq.`id`, qn.`question_no_ids`)
+      left join `textbook_paper` tp on find_in_set(tq.`id`, tp.`question_no_ids`)
       and tp.`id` = #{paperId,jdbcType=VARCHAR}
     </if>
     where 1

+ 42 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperQuestionRelationMapper.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.UserPaperQuestionRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.UserPaperQuestion">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <id column="question_id" jdbcType="INTEGER" property="questionId" />
+    <id column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    up.`id`
+  </sql>
+
+  <!--
+    过滤符合条件的题目
+  -->
+  <select id="filterTimes" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `user_paper_question` upq
+    where 1
+    <if test="userId != null">
+      and upq.`user_id` = #{userId,jdbcType=VARCHAR}
+    </if>
+    <if test="questionOrigin != null">
+      and upq.`question_origin` = #{questionOrigin,jdbcType=VARCHAR}
+    </if>
+    <if test="questionModule != null">
+      and upq.`question_module` = #{questionModule,jdbcType=VARCHAR}
+    </if>
+    and upq.`question_no_id` IN
+    <foreach collection="questionNoIds" item="item" index="index" open="(" separator="," close=")">
+      #{item}
+    </foreach>
+    group by upq.`question_no_id` having count(*) &gt; #{fiterTimes,jdbcType=VARCHAR}
+  </select>
+</mapper>

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

@@ -59,7 +59,7 @@
     where
     up.`paper_id` IN
     <foreach collection="paperIds" item="item" index="index" open="(" close=")" separator=",">
-      #{id}
+      #{item}
     </foreach>
 
     <!--<if test="startTime != null">-->
@@ -82,7 +82,7 @@
     where
     up.`paper_id` IN
     <foreach collection="paperIds" item="item" index="index" open="(" close=")" separator=",">
-      #{id}
+      #{item}
     </foreach>
 
     <!--<if test="startTime != null">-->

+ 2 - 2
server/gateway-api/src/main/java/com/qxgmat/Application.java

@@ -32,5 +32,5 @@ public class Application {
 // 模考做题次数,reset
 // 订单结构分析:服务、课程、数据都是商品
 // 购物车,订单
-// 自动组卷:练习,长难句,作文练习,单题成卷
-// 长难句:整体页数
+// 练习列表,进度
+// 模考出题

+ 30 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExaminationController.java

@@ -1,11 +1,17 @@
 package com.qxgmat.controller.admin;
 
 
+import com.github.pagehelper.Page;
+import com.nuliji.tools.PageMessage;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.ExaminationStruct;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.dto.admin.request.ExaminationStructDto;
+import com.qxgmat.dto.admin.response.ExaminationQuestionListDto;
+import com.qxgmat.service.extend.ExaminationService;
 import com.qxgmat.service.inline.ExaminationStructService;
 import com.qxgmat.service.inline.ManagerLogService;
 import io.swagger.annotations.Api;
@@ -17,6 +23,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
+import java.util.Collection;
 import java.util.List;
 
 @RestController("AdminExaminationController")
@@ -25,9 +32,13 @@ import java.util.List;
 public class ExaminationController {
     @Autowired
     private ManagerLogService managerLogService;
+
     @Autowired
     private ExaminationStructService examinationStructService;
 
+    @Autowired
+    private ExaminationService examinationService;
+
     @RequestMapping(value = "/struct/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加模考层级", httpMethod = "POST")
     public Response<ExaminationStruct> add(@RequestBody @Validated ExaminationStructDto dto, HttpServletRequest request) {
@@ -60,5 +71,24 @@ public class ExaminationController {
         return ResponseHelp.success(p);
     }
 
+    @RequestMapping(value = "/question/list", method = RequestMethod.GET)
+    @ApiOperation(value = "模考试题列表", httpMethod = "GET")
+    public Response<PageMessage<ExaminationQuestionListDto>> listQuestion(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String questionType,
+            @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) Integer questionNoId,
+            @RequestParam(required = false) Integer paperId,
+            @RequestParam(required = false) String place,
+            @RequestParam(required = false) String difficult,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction,
+            HttpSession session) {
+        Page<QuestionNoRelation> p = examinationService.listAdmin(page, size, questionType, structId, questionNoId, paperId, place, difficult, order, DirectionStatus.ValueOf(direction));
+        List<ExaminationQuestionListDto> pr = Transform.convert(p, ExaminationQuestionListDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
 
 }

+ 24 - 20
server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExerciseController.java

@@ -11,13 +11,13 @@ import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.SettingKey;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.dto.admin.extend.ExercisePaperExtendDto;
-import com.qxgmat.dto.admin.extend.QuestionExtendDto;
-import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
 import com.qxgmat.dto.admin.request.ExerciseStructDto;
 import com.qxgmat.dto.admin.response.ExercisePaperListDto;
 import com.qxgmat.dto.admin.response.ExerciseQuestionListDto;
-import com.qxgmat.service.ExercisePaperService;
+import com.qxgmat.service.inline.ExercisePaperService;
+import com.qxgmat.service.extend.ExerciseService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.task.AsyncTask;
 import io.swagger.annotations.Api;
@@ -29,8 +29,9 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
-import java.util.Collection;
+import java.util.Arrays;
 import java.util.List;
+import java.util.stream.Collectors;
 
 @RestController("AdminExerciseController")
 @RequestMapping("/admin/exercise")
@@ -47,7 +48,7 @@ public class ExerciseController {
     private ExercisePaperService exercisePaperService;
 
     @Autowired
-    private ExerciseQuestionService exerciseQuestionService;
+    private ExerciseService exerciseService;
 
     @Autowired
     private QuestionNoService questionNoService;
@@ -117,7 +118,7 @@ public class ExerciseController {
     public Response<PageMessage<ExerciseQuestionListDto>> listQuestion(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = false) String type,
+            @RequestParam(required = false) String questionType,
             @RequestParam(required = false) Integer structId,
             @RequestParam(required = false) Integer questionNoId,
             @RequestParam(required = false) Integer paperId,
@@ -128,23 +129,26 @@ public class ExerciseController {
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<ExercisePaperQuestion> p = exerciseQuestionService.listAdmin(page, size, type, structId, questionNoId, paperId, place, difficult, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        Page<QuestionNoRelation> p = exerciseService.listAdmin(page, size, questionType, structId, questionNoId, paperId, place, difficult, startTime, endTime, order, DirectionStatus.ValueOf(direction));
         List<ExerciseQuestionListDto> pr = Transform.convert(p, ExerciseQuestionListDto.class);
 
-        // 绑定题目
-        Collection questionIds = Transform.getIds(p, ExercisePaperQuestion.class, "questionId");
-        List<Question> questionList = questionService.select(questionIds);
-        Transform.combine(pr, questionList, ExerciseQuestionListDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
-
-        // 绑定题目编号
-        Collection questionNoIds = Transform.getIds(p, ExercisePaperQuestion.class, "questionNoId");
-        List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-        Transform.combine(pr, questionNoList, ExerciseQuestionListDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
-
         // 绑定练习册
-        Collection paperIds = Transform.getIds(p, ExercisePaperQuestion.class, "paperId");
-        List<ExercisePaper> paperList = exercisePaperService.select(paperIds);
-        Transform.combine(pr, paperList, ExerciseQuestionListDto.class, "paperId", "paper", ExercisePaper.class, "id", ExercisePaperExtendDto.class);
+        if (paperId != null && paperId > 0){
+            ExercisePaper paper = exercisePaperService.get(paperId);
+            if (paper != null){
+                ExercisePaperExtendDto paperDto = Transform.convert(paper, ExercisePaperExtendDto.class);
+                List<Integer> questionNoIds = Arrays.stream(paper.getQuestionNoIds()).collect(Collectors.toList());
+                for(ExerciseQuestionListDto dto : pr){
+                    dto.setPaper(paperDto);
+                    // 绑定题目序号
+                    int index = questionNoIds.indexOf(dto.getId());
+                    if (index >= 0){
+                        dto.setNo(index + 1);
+                    }
+                }
+            }
+
+        }
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }

+ 12 - 6
server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java

@@ -13,9 +13,10 @@ import com.qxgmat.data.dao.entity.UserPaper;
 import com.qxgmat.dto.admin.request.PreviewDto;
 import com.qxgmat.dto.admin.response.PreviewDetailDto;
 import com.qxgmat.dto.admin.response.PreviewListDto;
-import com.qxgmat.service.PreviewService;
+import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.inline.ManagerLogService;
+import com.qxgmat.service.inline.PreviewPaperService;
 import com.qxgmat.service.inline.QuestionNoService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -39,6 +40,9 @@ public class PreviewController {
     private PreviewService previewService;
 
     @Autowired
+    private PreviewPaperService previewPaperService;
+
+    @Autowired
     private QuestionNoService questionNoService;
 
     @Autowired
@@ -58,8 +62,9 @@ public class PreviewController {
                 .build();
         // 初始化paper:主要是计算做题时间
         questionFlowService.initPaper(tmpPaper, module);
+        entity.setTime(tmpPaper.getTime());
 
-        entity = previewService.edit(entity, tmpPaper.getTime());
+        entity = previewService.edit(entity);
         managerLogService.log(request);
         return ResponseHelp.success(entity);
     }
@@ -78,8 +83,9 @@ public class PreviewController {
                 .build();
         // 初始化paper:主要是计算做题时间
         questionFlowService.initPaper(tmpPaper, module);
+        entity.setTime(tmpPaper.getTime());
 
-        entity = previewService.edit(entity, tmpPaper.getTime());
+        entity = previewService.edit(entity);
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }
@@ -88,13 +94,13 @@ public class PreviewController {
     @ApiOperation(value = "删除预习作业", httpMethod = "DELETE")
     public Response<Boolean> delete(@RequestParam int id, HttpServletRequest request) {
         managerLogService.log(request);
-        return ResponseHelp.success(previewService.delete(id));
+        return ResponseHelp.success(previewPaperService.delete(id));
     }
 
     @RequestMapping(value = "/detail", method = RequestMethod.GET)
     @ApiOperation(value = "获取预习作业", httpMethod = "GET")
     public Response<PreviewDetailDto> detail(@RequestParam int id, HttpSession session) {
-        PreviewPaper entity = previewService.get(id);
+        PreviewPaper entity = previewPaperService.get(id);
         PreviewDetailDto dto = Transform.convert(entity, PreviewDetailDto.class);
 
 //        List<QuestionNoRelation> questionNos = questionNoService.listWithRelationByIds(entity.getQuestionNoIds());
@@ -113,7 +119,7 @@ public class PreviewController {
             @RequestParam(required = false) Integer category,
             @RequestParam(required = false) Integer status,
             HttpSession session) {
-        Page<PreviewPaper> p = previewService.select(page, size, category, PreviewStatus.ValueOf(status));
+        Page<PreviewPaper> p = previewPaperService.select(page, size, category, PreviewStatus.ValueOf(status));
         List<PreviewListDto> pr = Transform.convert(p, PreviewListDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());

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

@@ -16,7 +16,7 @@ import com.qxgmat.dto.admin.response.QuestionDetailDto;
 import com.qxgmat.dto.admin.response.UserAskQuestionDetailDto;
 import com.qxgmat.dto.admin.response.UserAskQuestionListDto;
 import com.qxgmat.help.ShiroHelp;
-import com.qxgmat.service.ExercisePaperService;
+import com.qxgmat.service.inline.ExercisePaperService;
 import com.qxgmat.service.ManagerService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.ManagerLogService;

+ 7 - 6
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SentenceController.java

@@ -8,16 +8,15 @@ import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.SettingKey;
-import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.SentenceArticle;
 import com.qxgmat.data.dao.entity.SentenceQuestion;
 import com.qxgmat.data.dao.entity.Setting;
 import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
 import com.qxgmat.dto.admin.request.ExerciseStructDto;
-import com.qxgmat.dto.admin.request.ManagerDto;
 import com.qxgmat.dto.admin.request.SentenceQuestionDto;
 import com.qxgmat.dto.admin.response.SentenceQuestionListDto;
-import com.qxgmat.service.SentencePaperService;
+import com.qxgmat.service.inline.SentencePaperService;
+import com.qxgmat.service.extend.SentenceService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.task.AsyncTask;
 import io.swagger.annotations.ApiOperation;
@@ -27,7 +26,6 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
-import java.util.Collection;
 import java.util.List;
 
 @RestController("AdminSentenceController")
@@ -46,6 +44,9 @@ public class SentenceController {
     private SentenceArticleService sentenceArticleService;
 
     @Autowired
+    private SentenceService sentenceService;
+
+    @Autowired
     private QuestionService questionService;
 
     @Autowired
@@ -102,7 +103,7 @@ public class SentenceController {
     @ApiOperation(value = "添加长难句题目", httpMethod = "POST")
     public Response<SentenceQuestion> addQuestion(@RequestBody @Validated SentenceQuestionDto dto, HttpServletRequest request) {
         SentenceQuestionRelation entity = Transform.dtoToEntity(dto);
-        SentenceQuestion entityNew = sentencePaperService.addQuestion(entity);
+        SentenceQuestion entityNew = sentenceService.addQuestion(entity);
         managerLogService.log(request);
         return ResponseHelp.success(entityNew);
     }
@@ -110,7 +111,7 @@ public class SentenceController {
     @ApiOperation(value = "修改长难句题目", httpMethod = "PUT")
     public Response<Boolean> editQuestion(@RequestBody @Validated SentenceQuestionDto dto, HttpServletRequest request) {
         SentenceQuestionRelation entity = Transform.dtoToEntity(dto);
-        sentencePaperService.editQuestion(entity);
+        sentenceService.editQuestion(entity);
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }

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

@@ -1,26 +1,14 @@
 package com.qxgmat.controller.admin;
 
 
-import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
-import com.nuliji.tools.exception.ParameterException;
-import com.qxgmat.data.constants.enums.QuestionType;
-import com.qxgmat.data.constants.enums.SettingKey;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
-import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
 import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
-import com.qxgmat.dto.admin.extend.ExercisePaperExtendDto;
-import com.qxgmat.dto.admin.extend.QuestionExtendDto;
-import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
 import com.qxgmat.dto.admin.request.*;
-import com.qxgmat.dto.admin.response.ExercisePaperListDto;
-import com.qxgmat.dto.admin.response.ExerciseQuestionListDto;
-import com.qxgmat.dto.admin.response.TextbookPaperListDto;
 import com.qxgmat.dto.admin.response.TextbookQuestionListDto;
-import com.qxgmat.service.ExercisePaperService;
-import com.qxgmat.service.TextbookPaperService;
+import com.qxgmat.service.inline.TextbookPaperService;
 import com.qxgmat.service.extend.TextbookService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.task.AsyncTask;
@@ -33,7 +21,6 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
-import java.util.Collection;
 import java.util.List;
 
 @RestController("AdminTextbookController")

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

@@ -10,7 +10,7 @@ import com.qxgmat.dto.admin.response.UserListDto;
 import com.qxgmat.dto.admin.response.UserPreviewListDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.ManagerService;
-import com.qxgmat.service.PreviewService;
+import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
@@ -58,6 +58,9 @@ public class UserController {
     @Autowired
     private PreviewService previewService;
 
+    @Autowired
+    private PreviewPaperService previewPaperService;
+
 //    @RequestMapping(value = "/add", method = RequestMethod.POST)
 //    @ApiOperation(value = "添加用户信息", httpMethod = "POST")
 //    public Response<User> add(@RequestBody @Validated UserDto dto, HttpServletRequest request) {
@@ -195,7 +198,7 @@ public class UserController {
 
         // 绑定预习作业
         Collection previewIds = Transform.getIds(p, UserPreviewPaperRelation.class, "moduleId");
-        List<PreviewPaper> previewPaperList = previewService.select(previewIds);
+        List<PreviewPaper> previewPaperList = previewPaperService.select(previewIds);
         Transform.combine(p, previewPaperList, UserPreviewPaperRelation.class, "moduleId", "preview", PreviewPaper.class, "id");
 
         List<UserPreviewListDto> pr = Transform.convert(p, UserPreviewListDto.class);

+ 5 - 2
server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java

@@ -8,7 +8,7 @@ import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
 import com.qxgmat.dto.extend.UserPreviewPaperExtendDto;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.help.ShiroHelp;
-import com.qxgmat.service.*;
+import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -32,6 +32,9 @@ public class CourseController {
     private PreviewService previewService;
 
     @Autowired
+    private PreviewPaperService previewPaperService;
+
+    @Autowired
     private QuestionNoService questionNoService;
 
     @Autowired
@@ -106,7 +109,7 @@ public class CourseController {
             @RequestParam(required = true, name="id") Integer paperId
     )  {
         User user = (User) shiroHelp.getLoginUser();
-        PreviewPaper preview = previewService.get(paperId);
+        PreviewPaper preview = previewPaperService.get(paperId);
         PaperBaseDto paperDto = Transform.convert(preview, PaperBaseDto.class);
 
         return ResponseHelp.success(paperDto);

+ 83 - 19
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -13,6 +13,7 @@ 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;
 import com.qxgmat.data.relation.entity.*;
 import com.qxgmat.dto.extend.*;
 import com.qxgmat.dto.request.*;
@@ -74,6 +75,9 @@ public class MyController {
     private ClassCourseNoService classCourseNoService;
 
     @Autowired
+    private QuestionService questionService;
+
+    @Autowired
     private QuestionNoService questionNoService;
 
     @Autowired
@@ -498,12 +502,35 @@ public class MyController {
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
-        PageResult<UserCollectQuestionRelation> p = userCollectQuestionService.listQuestion(page, size, user.getId(), QuestionModule.ValueOf(module), QuestionType.ValueOf(type), startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        QuestionModule questionModule = QuestionModule.ValueOf(module);
+        PageResult<UserCollectQuestionRelation> p = userCollectQuestionService.listQuestion(page, size, user.getId(), questionModule, QuestionType.ValueOf(type), startTime, endTime, order, DirectionStatus.ValueOf(direction));
 
         List<UserCollectQuestionDto> pr = Transform.convert(p, UserCollectQuestionDto.class);
 
-        // todo 绑定做题数据
+        // 获取题目信息
+        Collection questionIds = Transform.getIds(pr, UserCollectQuestionDto.class, "questionId");
+        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(questionModule){
+            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;
+        }
+
+        // 绑定题目统计
+        Map<Object, UserQuestionStat> stats = userQuestionService.statQuestionMap(questionIds);
+        Transform.combine(pr, stats, UserCollectQuestionDto.class, "questionId", "stat");
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
@@ -517,10 +544,30 @@ public class MyController {
             @RequestParam(required = false) Number category
     )  {
         User user = (User) shiroHelp.getLoginUser();
+        QuestionModule questionModule = QuestionModule.ValueOf(module);
         PageResult<UserQuestion> p = userQuestionService.listError(page, size, user.getId());
         List<UserQuestionErrorListDto> pr = Transform.convert(p, UserQuestionErrorListDto.class);
 
-        // todo 绑定数据
+        // 获取题目信息
+        Collection questionIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionId");
+        List<Question> questionList = questionService.select(questionIds);
+        Transform.combine(pr, questionList, UserQuestionErrorListDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+
+        Collection questionNoIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionNoId");
+        switch(questionModule){
+            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());
     }
@@ -567,9 +614,9 @@ public class MyController {
         return ResponseHelp.success(true);
     }
 
-    @RequestMapping(value = "/note", method = RequestMethod.PUT)
+    @RequestMapping(value = "/note/question", method = RequestMethod.PUT)
     @ApiOperation(value = "更新笔记", notes = "更新笔记", httpMethod = "PUT")
-    public Response<Boolean> updateNote(@RequestBody @Validated UserNoteDto dto)  {
+    public Response<Boolean> updateNoteQuestion(@RequestBody @Validated UserNoteDto dto)  {
         UserNoteQuestion entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());
@@ -599,9 +646,9 @@ public class MyController {
         return ResponseHelp.success(true);
     }
 
-    @RequestMapping(value = "/note/list", method = RequestMethod.GET)
-    @ApiOperation(value = "获取笔记列表", notes = "获取笔记列表", httpMethod = "GET")
-    public Response<PageMessage<UserNoteDetailDto>> listNote(
+    @RequestMapping(value = "/note/question/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取题目笔记列表", notes = "获取笔记列表", httpMethod = "GET")
+    public Response<PageMessage<UserNoteQuestionDto>> listNoteQuestion(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = true) String module,
@@ -612,11 +659,30 @@ public class MyController {
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
-        PageResult<UserNoteQuestionRelation> p = userNoteQuestionService.list(page, size, user.getId(), QuestionModule.ValueOf(module), QuestionType.ValueOf(type), startTime, endTime, order, DirectionStatus.ValueOf(direction));
-        List<UserNoteDetailDto> pr = Transform.convert(p, UserNoteDetailDto.class);
+        QuestionModule questionModule = QuestionModule.ValueOf(module);
+        PageResult<UserNoteQuestionRelation> p = userNoteQuestionService.list(page, size, user.getId(), questionModule, QuestionType.ValueOf(type), startTime, endTime, order, DirectionStatus.ValueOf(direction));
+        List<UserNoteQuestionDto> pr = Transform.convert(p, UserNoteQuestionDto.class);
 
-        // todo 绑定数据
+        // 获取题目信息
+        Collection questionIds = Transform.getIds(pr, UserNoteQuestionDto.class, "questionId");
+        List<Question> questionList = questionService.select(questionIds);
+        Transform.combine(pr, questionList, UserNoteQuestionDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
 
+        Collection questionNoIds = Transform.getIds(pr, UserQuestionErrorListDto.class, "questionNoId");
+        switch(questionModule){
+            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());
     }
 
@@ -625,16 +691,16 @@ public class MyController {
     public Response<PageMessage<UserPaperDto>> reportList(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String module,
-            @RequestParam(required = false) String type,
+            @RequestParam(required = true) String origin,
+            @RequestParam(required = false) Integer structId,
             @RequestParam(required = false) String startTime,
             @RequestParam(required = false) String endTime,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
-        PageResult<UserPaper> p = userPaperService.list(page, size, user.getId(), PaperModule.ValueOf(module), QuestionType.ValueOf(type), startTime, endTime, order, DirectionStatus.ValueOf(direction));
-
+        PaperOrigin paperOrigin = PaperOrigin.ValueOf(origin);
+        PageResult<UserPaper> p = userPaperService.list(page, size, user.getId(), paperOrigin, structId, startTime, endTime, order, DirectionStatus.ValueOf(direction));
         List<UserPaperDto> pr = Transform.convert(p, UserPaperDto.class);
 
         Collection paperIds = Transform.getIds(p, UserPaper.class, "id");
@@ -644,14 +710,12 @@ public class MyController {
 
         // 错题 -> 题型
 
-        // 模考 -> 分数
-
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
-    @RequestMapping(value = "/ask", method = RequestMethod.POST)
+    @RequestMapping(value = "/ask/question", method = RequestMethod.POST)
     @ApiOperation(value = "添加提问", notes = "添加提问", httpMethod = "POST")
-    public Response<Boolean> addAsk(@RequestBody @Validated UserAskDto dto)  {
+    public Response<Boolean> addAskQuestion(@RequestBody @Validated UserAskDto dto)  {
         UserAskQuestion entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
         entity.setUserId(user.getId());

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

@@ -6,7 +6,6 @@ import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
-import com.qxgmat.data.constants.enums.module.PaperModule;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.entity.UserExercisePaperRelation;
@@ -19,6 +18,8 @@ import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.*;
+import com.qxgmat.service.extend.ExerciseService;
+import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
@@ -47,6 +48,9 @@ public class QuestionController {
     private ExercisePaperService exercisePaperService;
 
     @Autowired
+    private ExerciseService exerciseService;
+
+    @Autowired
     private QuestionNoService questionNoService;
 
     @Autowired
@@ -103,7 +107,7 @@ public class QuestionController {
             @RequestParam(required = false)  Integer times,
             HttpSession session) {
         User user = (User) shiroHelp.getLoginUser();
-        PageResult<UserExercisePaperRelation> p = exercisePaperService.list(page, size, structId, user.getId(), ExerciseLogic.ValueOf(logic), logicExtend, times);
+        PageResult<UserExercisePaperRelation> p = exerciseService.list(page, size, structId, user.getId(), ExerciseLogic.ValueOf(logic), logicExtend, times);
 
         List<UserExercisePaperExtendDto> pr = Transform.convert(p, UserExercisePaperExtendDto.class);
 

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

@@ -11,7 +11,7 @@ import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.help.ShiroHelp;
-import com.qxgmat.service.SentencePaperService;
+import com.qxgmat.service.inline.SentencePaperService;
 import com.qxgmat.service.UserCollectQuestionService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.extend.QuestionFlowService;

+ 27 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/ExaminationPaperExtendDto.java

@@ -0,0 +1,27 @@
+package com.qxgmat.dto.admin.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.ExaminationPaper;
+
+@Dto(entity = ExaminationPaper.class)
+public class ExaminationPaperExtendDto {
+
+    private Integer id;
+    private String title;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}

+ 51 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/ExaminationQuestionListDto.java

@@ -0,0 +1,51 @@
+package com.qxgmat.dto.admin.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
+import com.qxgmat.dto.admin.extend.ExaminationPaperExtendDto;
+import com.qxgmat.dto.admin.extend.QuestionExtendDto;
+
+
+@Dto(entity = QuestionNoRelation.class)
+public class ExaminationQuestionListDto {
+
+    private Integer id;
+
+    private ExaminationPaperExtendDto paper;
+
+    private Integer questionId;
+
+    private QuestionExtendDto question;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public ExaminationPaperExtendDto getPaper() {
+        return paper;
+    }
+
+    public void setPaper(ExaminationPaperExtendDto paper) {
+        this.paper = paper;
+    }
+
+    public QuestionExtendDto getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(QuestionExtendDto question) {
+        this.question = question;
+    }
+
+    public Integer getQuestionId() {
+        return questionId;
+    }
+
+    public void setQuestionId(Integer questionId) {
+        this.questionId = questionId;
+    }
+}

+ 16 - 15
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/ExerciseQuestionListDto.java

@@ -3,12 +3,13 @@ package com.qxgmat.dto.admin.response;
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.ExercisePaperQuestion;
 import com.qxgmat.data.dao.entity.QuestionNo;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.dto.admin.extend.ExercisePaperExtendDto;
 import com.qxgmat.dto.admin.extend.QuestionExtendDto;
 import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
 
 
-@Dto(entity = ExercisePaperQuestion.class)
+@Dto(entity = QuestionNoRelation.class)
 public class ExerciseQuestionListDto {
 
     private Integer id;
@@ -19,9 +20,9 @@ public class ExerciseQuestionListDto {
 
     private QuestionExtendDto question;
 
-    private Integer questionNoId;
+    private String title;
 
-    private QuestionNoExtendDto questionNo;
+    private Integer no;
 
     public Integer getId() {
         return id;
@@ -47,14 +48,6 @@ public class ExerciseQuestionListDto {
         this.question = question;
     }
 
-    public QuestionNoExtendDto getQuestionNo() {
-        return questionNo;
-    }
-
-    public void setQuestionNo(QuestionNoExtendDto questionNo) {
-        this.questionNo = questionNo;
-    }
-
     public Integer getQuestionId() {
         return questionId;
     }
@@ -63,11 +56,19 @@ public class ExerciseQuestionListDto {
         this.questionId = questionId;
     }
 
-    public Integer getQuestionNoId() {
-        return questionNoId;
+    public Integer getNo() {
+        return no;
+    }
+
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    public String getTitle() {
+        return title;
     }
 
-    public void setQuestionNoId(Integer questionNoId) {
-        this.questionNoId = questionNoId;
+    public void setTitle(String title) {
+        this.title = title;
     }
 }

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

@@ -11,6 +11,8 @@ public class QuestionNoExtendDto {
 
     private String title;
 
+    private Integer no;
+
     private QuestionExtendDto question;
 
     public QuestionExtendDto getQuestion() {
@@ -36,4 +38,12 @@ public class QuestionNoExtendDto {
     public void setTitle(String title) {
         this.title = title;
     }
+
+    public Integer getNo() {
+        return no;
+    }
+
+    public void setNo(Integer no) {
+        this.no = no;
+    }
 }

+ 6 - 15
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCollectQuestionDto.java

@@ -2,6 +2,7 @@ package com.qxgmat.dto.response;
 
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserCollectQuestion;
+import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.dto.extend.QuestionExtendDto;
 import com.qxgmat.dto.extend.QuestionNoExtendDto;
 
@@ -17,9 +18,7 @@ public class UserCollectQuestionDto {
 
     private Date createTime;
 
-    private Integer userTime;
-
-    private Integer avgTime;
+    private UserQuestionStat stat;
 
     public Integer getId() {
         return id;
@@ -53,19 +52,11 @@ public class UserCollectQuestionDto {
         this.createTime = createTime;
     }
 
-    public Integer getAvgTime() {
-        return avgTime;
-    }
-
-    public void setAvgTime(Integer avgTime) {
-        this.avgTime = avgTime;
-    }
-
-    public Integer getUserTime() {
-        return userTime;
+    public UserQuestionStat getStat() {
+        return stat;
     }
 
-    public void setUserTime(Integer userTime) {
-        this.userTime = userTime;
+    public void setStat(UserQuestionStat stat) {
+        this.stat = stat;
     }
 }

+ 160 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserNoteQuestionDetailDto.java

@@ -0,0 +1,160 @@
+package com.qxgmat.dto.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserNoteQuestion;
+import com.qxgmat.dto.extend.QuestionNoExtendDto;
+
+import java.util.Date;
+
+@Dto(entity = UserNoteQuestion.class)
+public class UserNoteQuestionDetailDto {
+    private Integer id;
+
+    private String questionModule;
+
+    private Integer questionId;
+
+    private Integer questionNoId;
+
+    private QuestionNoExtendDto questionNo;
+
+    private String content;
+
+    private String officialContent;
+
+    private String qxContent;
+
+    private String associationContent;
+
+    private String qaContent;
+
+    private Date contentTime;
+
+    private Date officialTime;
+
+    private Date qxTime;
+
+    private Date associationTime;
+
+    private Date qaTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    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 QuestionNoExtendDto getQuestionNo() {
+        return questionNo;
+    }
+
+    public void setQuestionNo(QuestionNoExtendDto questionNo) {
+        this.questionNo = questionNo;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getOfficialContent() {
+        return officialContent;
+    }
+
+    public void setOfficialContent(String officialContent) {
+        this.officialContent = officialContent;
+    }
+
+    public String getQxContent() {
+        return qxContent;
+    }
+
+    public void setQxContent(String qxContent) {
+        this.qxContent = qxContent;
+    }
+
+    public String getAssociationContent() {
+        return associationContent;
+    }
+
+    public void setAssociationContent(String associationContent) {
+        this.associationContent = associationContent;
+    }
+
+    public Date getContentTime() {
+        return contentTime;
+    }
+
+    public void setContentTime(Date contentTime) {
+        this.contentTime = contentTime;
+    }
+
+    public Date getOfficialTime() {
+        return officialTime;
+    }
+
+    public void setOfficialTime(Date officialTime) {
+        this.officialTime = officialTime;
+    }
+
+    public Date getQxTime() {
+        return qxTime;
+    }
+
+    public void setQxTime(Date qxTime) {
+        this.qxTime = qxTime;
+    }
+
+    public Date getAssociationTime() {
+        return associationTime;
+    }
+
+    public void setAssociationTime(Date associationTime) {
+        this.associationTime = associationTime;
+    }
+
+    public String getQaContent() {
+        return qaContent;
+    }
+
+    public void setQaContent(String qaContent) {
+        this.qaContent = qaContent;
+    }
+
+    public Date getQaTime() {
+        return qaTime;
+    }
+
+    public void setQaTime(Date qaTime) {
+        this.qaTime = qaTime;
+    }
+}

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

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

+ 29 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionErrorListDto.java

@@ -11,9 +11,13 @@ import java.util.Date;
 public class UserQuestionErrorListDto {
     private Integer id;
 
+    private Integer questionId;
+
+    private Integer questionNoId;
+
     private QuestionExtendDto question;
 
-    private QuestionNoExtendDto questionNoExtendDto;
+    private QuestionNoExtendDto questionNo;
 
     private Date createTime;
 
@@ -33,14 +37,6 @@ public class UserQuestionErrorListDto {
         this.question = question;
     }
 
-    public QuestionNoExtendDto getQuestionNoExtendDto() {
-        return questionNoExtendDto;
-    }
-
-    public void setQuestionNoExtendDto(QuestionNoExtendDto questionNoExtendDto) {
-        this.questionNoExtendDto = questionNoExtendDto;
-    }
-
     public Date getCreateTime() {
         return createTime;
     }
@@ -48,4 +44,28 @@ public class UserQuestionErrorListDto {
     public void setCreateTime(Date createTime) {
         this.createTime = createTime;
     }
+
+    public QuestionNoExtendDto getQuestionNo() {
+        return questionNo;
+    }
+
+    public void setQuestionNo(QuestionNoExtendDto questionNo) {
+        this.questionNo = questionNo;
+    }
+
+    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;
+    }
 }

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

@@ -14,6 +14,8 @@ public class UserSentenceArticleDto {
 
     private Integer part;
 
+    private Integer pages;
+
     public Integer getProcess() {
         return process;
     }
@@ -53,4 +55,12 @@ public class UserSentenceArticleDto {
     public void setId(Integer id) {
         this.id = id;
     }
+
+    public Integer getPages() {
+        return pages;
+    }
+
+    public void setPages(Integer pages) {
+        this.pages = pages;
+    }
 }

+ 0 - 282
server/gateway-api/src/main/java/com/qxgmat/service/SentencePaperService.java

@@ -1,282 +0,0 @@
-package com.qxgmat.service;
-
-import com.github.pagehelper.Page;
-import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.Transform;
-import com.nuliji.tools.exception.ParameterException;
-import com.nuliji.tools.exception.SystemException;
-import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.logic.SentenceLogic;
-import com.qxgmat.data.dao.SentencePaperMapper;
-import com.qxgmat.data.dao.entity.Question;
-import com.qxgmat.data.dao.entity.SentencePaper;
-import com.qxgmat.data.dao.entity.SentenceQuestion;
-import com.qxgmat.data.dao.entity.UserPaper;
-import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
-import com.qxgmat.service.inline.QuestionService;
-import com.qxgmat.service.inline.SentenceQuestionService;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-
-import javax.annotation.Resource;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
-
-@Service
-public class SentencePaperService extends AbstractService {
-    private static final Logger logger = LoggerFactory.getLogger(SentencePaperService.class);
-
-    final static String formatSet = "FIND_IN_SET('%d', question_no_ids)";
-    final static String formatTitle = "";
-
-    @Value("${paper.sentenceLength}")
-    private Integer paperLength;
-
-    @Resource
-    private SentencePaperMapper sentencePaperMapper;
-
-    @Resource
-    private QuestionService questionService;
-
-    @Resource
-    private SentenceQuestionService sentenceQuestionService;
-
-    /**
-     * 添加长难句题目:加入题库,关联题目,并关联长难句paper
-     * @param relation
-     * @return
-     */
-    @Transactional
-    public SentenceQuestion addQuestion(SentenceQuestionRelation relation){
-        SentenceQuestion in = sentenceQuestionService.getByNo(relation.getNo());
-        if (in != null){
-            throw new ParameterException("序号已经存在");
-        }
-        Question question = relation.getQuestion();
-        question = questionService.add(question);
-        // 绑定关系
-        relation.setQuestionId(question.getId());
-
-        // 生成title
-        relation.setTitle("CNJ-"+relation.getNo());
-
-        SentenceQuestion sentenceQuestion =  sentenceQuestionService.add(relation);
-
-        // 绑定关系
-        addQuestionToPaperWithNo(sentenceQuestion);
-
-        if (sentenceQuestion.getIsTrail() > 0){
-            addQuestionToPaperWithTrail(sentenceQuestion);
-        }
-        return sentenceQuestion;
-    }
-
-    /**
-     * 更新长难句题目:更新题库,,变更长难句paper
-     * @param relation
-     * @return
-     */
-    @Transactional
-    public SentenceQuestion editQuestion(SentenceQuestionRelation relation){
-        SentenceQuestion in = sentenceQuestionService.getByNo(relation.getNo());
-        if (in != null && !in.getId().equals(relation.getId())){
-            throw new ParameterException("序号已经存在");
-        }
-
-        Question question = relation.getQuestion();
-        question = questionService.edit(question);
-
-        if(in == null){
-            in = sentenceQuestionService.get(relation.getId());
-        }
-
-        // 根据序号调整分组
-        if (!in.getNo().equals(relation.getNo())){
-            // 移出原有关系
-            removeQuestionFromPaper(in, SentenceLogic.NO);
-
-            // 绑定关系
-            addQuestionToPaperWithNo(relation);
-        }
-
-        // 根据试用调整
-        if (!in.getIsTrail().equals(relation.getIsTrail())){
-            if (relation.getIsTrail() > 0){
-                addQuestionToPaperWithTrail(relation);
-            }else{
-                removeQuestionFromPaper(in, SentenceLogic.TRAIL);
-            }
-        }
-        SentenceQuestion sentenceQuestion = sentenceQuestionService.edit(relation);
-
-        return sentenceQuestion;
-    }
-
-    /**
-     * 获取可用的试卷列表:单个分组逻辑
-     * @param logic
-     * @return
-     */
-    public List<SentencePaper> listByLogic(SentenceLogic logic){
-        Example example = new Example(SentencePaper.class);
-        example.and(
-                example.createCriteria()
-                        .andEqualTo("logic", logic.key)
-                        .andEqualTo("status", 1)
-        );
-        example.orderBy("no").asc();
-        return select(sentencePaperMapper, example);
-    }
-
-    private void addQuestionToPaperWithNo(SentenceQuestion question){
-        if (question.getIsPaper() == 0) return;
-        // 根据序号创建
-        Integer paperNo = question.getNo() / paperLength + 1;
-        SentencePaper paper = getByNo(paperNo, SentenceLogic.NO);
-        Integer no = 0;
-        if (paper == null || paper.getQuestionNumber().equals(paperLength)){
-            if (paper != null){
-                no = paper.getNo();
-            }
-            paper = add(SentencePaper.builder()
-                    .title(String.format(formatTitle, no))
-                    .logic(SentenceLogic.NO.key)
-                    .no(no + 1)
-                    .questionNumber(1)
-                    .status(1)
-                    .questionNoIds(new Integer[]{question.getId()}).build()
-            );
-        }else{
-            // 加入
-            List<Integer> list = Arrays.stream(paper.getQuestionNoIds()).collect(Collectors.toList());
-            list.add(question.getId());
-            paper.setQuestionNumber(paper.getQuestionNumber() + 1);
-            paper.setQuestionNoIds(list.toArray(new Integer[0]));
-            paper = edit(paper);
-        }
-    }
-
-    private void addQuestionToPaperWithTrail(SentenceQuestion question){
-        if (question.getIsPaper() == 0) return;
-        if (question.getIsTrail() <= 0) return;
-        // 加入trail的paper
-        Integer paperNo = question.getNo() / paperLength + 1;
-        SentencePaper paper = getLast(SentenceLogic.TRAIL);
-        Integer no = 0;
-        if (paper == null || paper.getQuestionNumber().equals(paperLength)){
-            if (paper != null){
-                no = paper.getNo();
-            }
-            paper = add(SentencePaper.builder()
-                    .logic(SentenceLogic.TRAIL.key)
-                    .no(no + 1)
-                    .questionNumber(1)
-                    .status(1)
-                    .questionNoIds(new Integer[]{question.getId()}).build()
-            );
-        }else{
-            // 加入
-            List<Integer> list = Arrays.stream(paper.getQuestionNoIds()).collect(Collectors.toList());
-            list.add(question.getId());
-            paper.setQuestionNumber(paper.getQuestionNumber() + 1);
-            paper.setQuestionNoIds(list.toArray(new Integer[0]));
-            paper = edit(paper);
-        }
-    }
-
-    private void removeQuestionFromPaper(SentenceQuestion question, SentenceLogic logic){
-        List<SentencePaper> paperList = listByQuestion(question, logic);
-        for(SentencePaper paper : paperList){
-            paper.setQuestionNumber(paper.getQuestionNumber() - 1);
-            List<Integer> list = Arrays.stream(paper.getQuestionNoIds()).collect(Collectors.toList());
-            list.remove(question.getId());
-            paper.setQuestionNoIds(list.toArray(new Integer[0]));
-            edit(paper);
-        }
-    }
-
-    private SentencePaper getByNo(Integer no, SentenceLogic logic){
-        Example example = new Example(SentencePaper.class);
-        example.and(
-                example.createCriteria()
-                        .andEqualTo("no", no)
-                        .andEqualTo("logic", logic.key)
-        );
-        return one(sentencePaperMapper, example);
-    }
-
-
-    private SentencePaper getLast(SentenceLogic logic){
-        Example example = new Example(SentencePaper.class);
-        example.and(
-                example.createCriteria()
-                        .andEqualTo("logic", logic.key)
-        );
-        example.orderBy("createTime").desc();
-        return one(sentencePaperMapper, example);
-    }
-
-    private List<SentencePaper> listByQuestion(SentenceQuestion question, SentenceLogic logic){
-        Example example = new Example(SentencePaper.class);
-        example.and(
-                example.createCriteria()
-                        .andCondition(String.format(formatSet, question.getId()))
-        );
-        if (logic != null)
-            example.and(
-                    example.createCriteria()
-                        .andEqualTo("logic", logic.key)
-            );
-        return select(sentencePaperMapper, example);
-    }
-
-    public SentencePaper add(SentencePaper paper){
-        int result = insert(sentencePaperMapper, paper);
-        paper = one(sentencePaperMapper, paper.getId());
-        if(paper == null){
-            throw new SystemException("题目添加失败");
-        }
-        return paper;
-    }
-
-    public SentencePaper edit(SentencePaper paper){
-        SentencePaper in = one(sentencePaperMapper, paper.getId());
-        if(in == null){
-            throw new ParameterException("题目不存在");
-        }
-        int result = update(sentencePaperMapper, paper);
-        return paper;
-    }
-
-    public boolean delete(Number id){
-        SentencePaper in = one(sentencePaperMapper, id);
-        if(in == null){
-            throw new ParameterException("题目不存在");
-        }
-        int result = delete(sentencePaperMapper, id);
-        return result > 0;
-    }
-
-    public SentencePaper get(Number id){
-        SentencePaper in = one(sentencePaperMapper, id);
-
-        if(in == null){
-            throw new ParameterException("题目不存在");
-        }
-        return in;
-    }
-
-    public Page<SentencePaper> select(int page, int pageSize){
-        return select(sentencePaperMapper, page, pageSize);
-    }
-
-    public List<SentencePaper> select(Collection ids){
-        return select(sentencePaperMapper, ids);
-    }
-
-}

+ 0 - 16
server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java

@@ -37,12 +37,6 @@ public class UserCollectQuestionService extends AbstractService {
     @Resource
     private UserCollectQuestionRelationMapper userCollectQuestionRelationMapper;
 
-    @Resource
-    private QuestionNoService questionNoService;
-
-    @Resource
-    private QuestionService questionService;
-
     /**
      * 获取用户题目收藏列表
      * @param page
@@ -65,16 +59,6 @@ public class UserCollectQuestionService extends AbstractService {
 
         List<UserCollectQuestionRelation> pr = Transform.convert(list, UserCollectQuestionRelation.class);
 
-        // 获取题目信息
-        Collection questionIds = Transform.getIds(pr, UserCollectQuestionRelation.class, "questionId");
-        List<Question> questionList = questionService.select(questionIds);
-        Transform.combine(pr, questionList, UserCollectQuestionRelation.class, "questionId", "question", Question.class, "id");
-
-        // 获取题目编号信息
-        Collection questionNoIds = Transform.getIds(pr, UserCollectQuestionRelation.class, "questionNoId");
-        List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-        Transform.combine(pr, questionNoList, UserCollectQuestionRelation.class, "questionNoId", "questionNo", Question.class, "id");
-
         return new PageResult<>(pr, p.getTotal());
     }
 

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

@@ -39,12 +39,6 @@ public class UserNoteQuestionService extends AbstractService {
     @Resource
     private UserNoteQuestionRelationMapper userNoteQuestionRelationMapper;
 
-    @Resource
-    private QuestionNoService questionNoService;
-
-    @Resource
-    private QuestionService questionService;
-
     /**
      * 获取用户笔记列表
      * @param page
@@ -72,16 +66,6 @@ public class UserNoteQuestionService extends AbstractService {
 
         List<UserNoteQuestionRelation> pr = Transform.convert(list, UserNoteQuestionRelation.class);
 
-        // 获取题目信息
-        Collection questionIds = Transform.getIds(pr, UserNoteQuestionRelation.class, "questionId");
-        List<Question> questionList = questionService.select(questionIds);
-        Transform.combine(pr, questionList, UserNoteQuestionRelation.class, "questionId", "question", Question.class, "id");
-
-        // 获取题目编号信息
-        Collection questionNoIds = Transform.getIds(pr, UserNoteQuestionRelation.class, "questionNoId");
-        List<QuestionNo> questionNoList = questionNoService.select(questionNoIds);
-        Transform.combine(pr, questionNoList, UserNoteQuestionRelation.class, "questionNoId", "questionNo", Question.class, "id");
-
         return new PageResult<>(pr, p.getTotal());
     }
 

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

@@ -57,15 +57,15 @@ public class UserPaperService extends AbstractService {
      * @param page
      * @param size
      * @param userId
-     * @param module
-     * @param type
+     * @param origin
+     * @param structId
      * @param startTime
      * @param endTime
      * @param order
      * @param direction
      * @return
      */
-    public PageResult<UserPaper> list(int page, int size, Integer userId, PaperModule module, QuestionType type, String startTime, String endTime, String order, DirectionStatus direction){
+    public PageResult<UserPaper> list(int page, int size, Integer userId, PaperOrigin origin, Integer structId, String startTime, String endTime, String order, DirectionStatus direction){
 
         return new PageResult<>(null, 0);
     }

+ 52 - 4
server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.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;
@@ -12,6 +13,7 @@ import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.dao.UserQuestionMapper;
 import com.qxgmat.data.dao.entity.UserQuestion;
 import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.service.annotation.InitQuestion;
 import com.qxgmat.service.inline.QuestionNoService;
 import com.qxgmat.service.inline.SentenceQuestionService;
@@ -22,10 +24,8 @@ import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class UserQuestionService extends AbstractService {
@@ -42,10 +42,58 @@ public class UserQuestionService extends AbstractService {
      * @return
      */
     public PageResult<UserQuestion> listError(int page, int size, Integer userId){
+        // todo 查询错题列表
         return new PageResult<>(null, 0);
     }
 
     /**
+     * 根据用户题目获取该题总统计
+     * @param questionNoList
+     * @return
+     */
+    public UserQuestionStat statQuestion(List<UserQuestion> questionNoList){
+        UserQuestionStat stat = new UserQuestionStat();
+        Integer totalTime = 0;
+        Integer totalNumber = 0;
+        Integer totalCorrect = 0;
+        for(UserQuestion question : questionNoList){
+            totalTime += question.getUserTime();
+            totalNumber += 1;
+            totalCorrect += question.getIsCorrect();
+        }
+        stat.setUserCorrect(totalCorrect);
+        stat.setUserNumber(totalNumber);
+        stat.setUserTime(totalTime);
+        return stat;
+    }
+    /**
+     * 根据试卷分组获取统计信息
+     * @param questionIds
+     * @return
+     */
+    public Map<Object, UserQuestionStat> statQuestionMap(Collection questionIds){
+        Example example = new Example(UserQuestion.class);
+        example.and(
+                example.createCriteria()
+                .andIn("questionId", questionIds)
+        );
+        List<UserQuestion> userQuestionList = select(userQuestionMapper, example);
+        Map<Object, UserQuestionStat> relationMap = new HashMap<>();
+        Map<Integer, List<UserQuestion>> map = new HashMap<>();
+        for (UserQuestion userQuestion: userQuestionList){
+            if (!map.containsKey(userQuestion.getQuestionNoId())){
+                map.put(userQuestion.getQuestionId(), new ArrayList<>());
+            }
+            List<UserQuestion> list = map.get(userQuestion.getQuestionId());
+            list.add(userQuestion);
+        }
+        for(Object questionId : questionIds){
+            relationMap.put(questionId, statQuestion(map.get(questionId)));
+        }
+
+        return relationMap;
+    }
+    /**
      * 获取当前报告最后一题
      * @param userId
      * @param userReportId

+ 121 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java

@@ -0,0 +1,121 @@
+package com.qxgmat.service.extend;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.PageResult;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.entity.UserPaper;
+import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.relation.QuestionNoRelationMapper;
+import com.qxgmat.data.relation.UserPaperRelationMapper;
+import com.qxgmat.data.relation.UserReportRelationMapper;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
+import com.qxgmat.data.relation.entity.UserExercisePaperRelation;
+import com.qxgmat.service.UserPaperService;
+import com.qxgmat.service.inline.ExercisePaperService;
+import com.qxgmat.service.inline.QuestionNoService;
+import com.qxgmat.service.inline.QuestionService;
+import com.qxgmat.service.inline.UserReportService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ExaminationService extends AbstractService {
+
+    @Resource
+    private QuestionService questionService;
+
+    @Resource
+    private QuestionNoService questionNoService;
+
+    @Resource
+    private QuestionNoRelationMapper questionNoRelationMapper;
+
+    @Resource
+    private UserPaperRelationMapper userPaperRelationMapper;
+
+    @Resource
+    private UserPaperService userPaperService;
+
+    @Resource
+    private UserReportRelationMapper userReportRelationMapper;
+
+    @Resource
+    private UserReportService userReportService;
+    /**
+     *
+     * @param page
+     * @param pageSize
+     * @param questionType
+     * @param structId
+     * @param questionNo
+     * @param paperId
+     * @param place
+     * @param difficult
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<QuestionNoRelation> listAdmin(int page, int pageSize, String questionType, Number structId, Number questionNo, Number paperId, String place, String difficult, String order, DirectionStatus direction){
+        if(order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+
+        Page<QuestionNoRelation> p = page(() -> {
+            questionNoRelationMapper.listExaminationAdmin(questionType, structId, questionNo, paperId, place, difficult, finalOrder, finalDirection.key);
+        }, page, pageSize);
+
+        Collection ids = Transform.getIds(p, QuestionNoRelation.class, "id");
+
+        // 获取详细数据
+        List<QuestionNoRelation> list = questionNoService.relation(questionNoService.select(ids));
+        Transform.replace(p, list, QuestionNoRelation.class, "id");
+
+        return p;
+    }
+
+
+    /**
+     * 查找用户作业, 并关联用户最后一次作业
+     * @param page
+     * @param size
+     * @param structId
+     * @param userId
+     * @param logic
+     * @param logicExtend
+     * @param times
+     * @return
+     */
+    public PageResult<UserExercisePaperRelation> list(int page, int size, Number structId, Number userId, ExerciseLogic logic, String logicExtend, Integer times){
+        String logicKey = logic != null ? logic.key : "";
+        Page<UserPaper> p = page(()->{
+            userPaperRelationMapper.listExercisePaper(structId, userId, logicKey, logicExtend, times);
+        },page, size);
+
+        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+
+        // 获取详细数据
+        List<UserPaper> list = userPaperService.select(ids);
+        List<UserExercisePaperRelation> pr = Transform.convert(list, UserExercisePaperRelation.class);
+
+        // 获取最后一次作业结果
+        List<UserReport> reportList = userReportRelationMapper.listLast(ids);
+        Collection reportIds = Transform.getIds(reportList, UserReport.class, "id");
+        Transform.replace(reportList, userReportService.select(reportIds), UserReport.class, "id");
+
+        Transform.combine(p, reportList, UserExercisePaperRelation.class, "id", "report", UserReport.class, "paperId");
+
+        return new PageResult<>(pr, p.getTotal());
+    }
+
+}

+ 200 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExerciseService.java

@@ -0,0 +1,200 @@
+package com.qxgmat.service.extend;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.PageResult;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.QuestionType;
+import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.QuestionNoRelationMapper;
+import com.qxgmat.data.relation.UserPaperRelationMapper;
+import com.qxgmat.data.relation.UserReportRelationMapper;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
+import com.qxgmat.data.relation.entity.UserExercisePaperRelation;
+import com.qxgmat.service.inline.ExercisePaperService;
+import com.qxgmat.service.UserPaperService;
+import com.qxgmat.service.inline.QuestionNoService;
+import com.qxgmat.service.inline.QuestionService;
+import com.qxgmat.service.inline.UserReportService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ExerciseService extends AbstractService {
+    @Value("${paper.exerciseLength}")
+    public Integer paperLength;
+
+    @Value("${paper.irLength}")
+    public Integer irLength;
+
+    @Value("${paper.awaLength}")
+    public Integer awaLength;
+
+    @Resource
+    private QuestionService questionService;
+
+    @Resource
+    private QuestionNoService questionNoService;
+
+    @Resource
+    private ExercisePaperService exercisePaperService;
+
+    @Resource
+    private QuestionNoRelationMapper questionNoRelationMapper;
+
+    @Resource
+    private UserPaperRelationMapper userPaperRelationMapper;
+
+    @Resource
+    private UserPaperService userPaperService;
+
+    @Resource
+    private UserReportRelationMapper userReportRelationMapper;
+
+    @Resource
+    private UserReportService userReportService;
+    /**
+     *
+     * @param page
+     * @param pageSize
+     * @param questionType
+     * @param structId
+     * @param questionNo
+     * @param paperId
+     * @param place
+     * @param difficult
+     * @param startTime
+     * @param endTime
+     * @param order
+     * @param direction
+     * @return
+     */
+    public Page<QuestionNoRelation> listAdmin(int page, int pageSize, String questionType, Number structId, Number questionNo, Number paperId, String place, String difficult, String startTime, String endTime, String order, DirectionStatus direction){
+        if(order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
+        }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+
+        Page<QuestionNoRelation> p = page(() -> {
+            questionNoRelationMapper.listExerciseAdmin(questionType, structId, questionNo, paperId, place, difficult, startTime, endTime, finalOrder, finalDirection.key);
+        }, page, pageSize);
+
+        Collection ids = Transform.getIds(p, QuestionNoRelation.class, "id");
+
+        // 获取详细数据
+        List<QuestionNoRelation> list = questionNoService.relation(questionNoService.select(ids));
+        Transform.replace(p, list, QuestionNoRelation.class, "id");
+
+        return p;
+    }
+
+
+    /**
+     * 查找用户作业, 并关联用户最后一次作业
+     * @param page
+     * @param size
+     * @param structId
+     * @param userId
+     * @param logic
+     * @param logicExtend
+     * @param times
+     * @return
+     */
+    public PageResult<UserExercisePaperRelation> list(int page, int size, Number structId, Number userId, ExerciseLogic logic, String logicExtend, Integer times){
+        String logicKey = logic != null ? logic.key : "";
+        Page<UserPaper> p = page(()->{
+            userPaperRelationMapper.listExercisePaper(structId, userId, logicKey, logicExtend, times);
+        },page, size);
+
+        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+
+        // 获取详细数据
+        List<UserPaper> list = userPaperService.select(ids);
+        List<UserExercisePaperRelation> pr = Transform.convert(list, UserExercisePaperRelation.class);
+
+        // 获取最后一次作业结果
+        List<UserReport> reportList = userReportRelationMapper.listLast(ids);
+        Collection reportIds = Transform.getIds(reportList, UserReport.class, "id");
+        Transform.replace(reportList, userReportService.select(reportIds), UserReport.class, "id");
+
+        Transform.combine(p, reportList, UserExercisePaperRelation.class, "id", "report", UserReport.class, "paperId");
+
+        return new PageResult<>(pr, p.getTotal());
+    }
+
+    /**
+     * 根据题目创建组卷序列
+     * @param logic
+     * @param questionList
+     * @return
+     */
+    @Transactional
+    public List<ExercisePaper> createPaper(String prefixTitle, QuestionType questionType, Integer three, Integer four, Integer length, ExerciseLogic logic, String extend, List<QuestionNoRelation> questionList){
+        Integer no = 0;
+        List<ExercisePaper> list = new ArrayList<>();
+        List<Integer> tmp = new ArrayList<>(length);
+        for(QuestionNo question : questionList){
+            tmp.add(question.getId());
+            if (tmp.size() == length){
+                no += 1;
+                ExercisePaper paper = exercisePaperService.add(ExercisePaper.builder()
+                        .logic(logic.key)
+                        .logicExtend(extend)
+                        .questionType(questionType.key)
+                        .structThree(three)
+                        .structFour(four)
+                        .no(no)
+                        .questionNumber(tmp.size())
+                        .status(0)
+                        .questionNoIds(tmp.toArray(new Integer[0])).build()
+                );
+
+                paper.setTitle(exercisePaperService.generateTitle(prefixTitle, length, paper.getNo(), paper.getQuestionNumber()));
+                list.add(paper);
+                tmp.clear();
+            }
+        }
+        if (tmp.size() > 0){
+            no += 1;
+            ExercisePaper paper = exercisePaperService.add(ExercisePaper.builder()
+                    .logic(logic.key)
+                    .logicExtend(extend)
+                    .questionType(questionType.key)
+                    .structThree(three)
+                    .structFour(four)
+                    .no(no)
+                    .questionNumber(tmp.size())
+                    .status(0)
+                    .questionNoIds(tmp.toArray(new Integer[0])).build()
+            );
+            paper.setTitle(exercisePaperService.generateTitle(prefixTitle, length, paper.getNo(), paper.getQuestionNumber()));
+            list.add(paper);
+        }
+        return list;
+    }
+
+    /**
+     * 切换新组卷
+     * @param logic
+     * @param ids
+     */
+    @Transactional
+    public void switchPaper(Integer three, Integer four, ExerciseLogic logic, Collection ids){
+        // 先将可用卷删除
+        List<ExercisePaper> list = exercisePaperService.listByLogic(three, four, logic, null);
+        Collection oldIds = Transform.getIds(list, ExercisePaper.class, "id");
+        exercisePaperService.updatePaper(oldIds, 0);
+        // 将新组卷启用
+        exercisePaperService.updatePaper(ids, 1);
+    }
+}

+ 4 - 3
server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageService.java

@@ -8,6 +8,7 @@ import com.qxgmat.service.inline.UserMessageService;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.Map;
 
 @Service
 public class MessageService {
@@ -18,10 +19,10 @@ public class MessageService {
     @Resource
     private UserMessageService userMessageService;
 
-    public UserMessage send(Integer userId, MessageType type, UserMessage userMessage){
+    public UserMessage send(Integer userId, MessageType type, Map<String, String> info){
         try {
-            userMessage.setUserId(userId);
-            return userMessage;
+            // 根据模版创建
+            return null;
         }catch (Exception e){
             throw new SystemException("Message生成失败", e);
         }

+ 7 - 73
server/gateway-api/src/main/java/com/qxgmat/service/PreviewService.java

@@ -1,4 +1,4 @@
-package com.qxgmat.service;
+package com.qxgmat.service.extend;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
@@ -18,10 +18,8 @@ import com.qxgmat.data.dao.entity.UserPaper;
 import com.qxgmat.data.dao.entity.UserReport;
 import com.qxgmat.data.relation.UserPaperRelationMapper;
 import com.qxgmat.data.relation.UserReportRelationMapper;
-import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
-import com.qxgmat.service.extend.QuestionFlowService;
-import com.qxgmat.service.extend.ToolsService;
+import com.qxgmat.service.UserPaperService;
 import com.qxgmat.service.inline.QuestionNoService;
 import com.qxgmat.service.inline.UserReportService;
 import org.slf4j.Logger;
@@ -41,9 +39,6 @@ public class PreviewService extends AbstractService {
     private PreviewPaperMapper previewPaperMapper;
 
     @Resource
-    private QuestionNoService questionNoService;
-
-    @Resource
     private UserReportService userReportService;
 
     @Resource
@@ -55,15 +50,6 @@ public class PreviewService extends AbstractService {
     @Resource
     private UserPaperRelationMapper userPaperRelationMapper;
 
-    @Resource
-    private ToolsService toolsService;
-
-    // 完成一次
-    public boolean finished(UserPaper userPaper){
-
-        return true;
-    }
-
     /**
      * 查找用户作业,并关联用户完成度最高的最后一次
      * @param page
@@ -167,7 +153,7 @@ public class PreviewService extends AbstractService {
     }
 
     @Transactional
-    public PreviewPaper add(PreviewPaper previewPaper, Integer time){
+    public PreviewPaper add(PreviewPaper previewPaper){
         int result = insert(previewPaperMapper, previewPaper);
         previewPaper = one(previewPaperMapper, previewPaper.getId());
         if(previewPaper == null){
@@ -187,7 +173,7 @@ public class PreviewService extends AbstractService {
                     .title(previewPaper.getTitle())
                     .questionNoIds(previewPaper.getQuestionNoIds())
                     .questionNumber(previewPaper.getQuestionNoIds().length)
-                    .time(time)
+                    .time(previewPaper.getTime())
                     .build()
             );
         }
@@ -195,7 +181,7 @@ public class PreviewService extends AbstractService {
     }
 
     @Transactional
-    public PreviewPaper edit(PreviewPaper previewPaper, Integer time){
+    public PreviewPaper edit(PreviewPaper previewPaper){
         PreviewPaper in = one(previewPaperMapper, previewPaper.getId());
         if(in == null){
             throw new ParameterException("预习作业不存在");
@@ -227,7 +213,7 @@ public class PreviewService extends AbstractService {
                         .title(previewPaper.getTitle())
                         .questionNoIds(previewPaper.getQuestionNoIds())
                         .questionNumber(previewPaper.getQuestionNoIds().length)
-                        .time(time)
+                        .time(previewPaper.getTime())
                         .build()
                 );
                 editList.remove(userId);
@@ -240,63 +226,11 @@ public class PreviewService extends AbstractService {
                         .title(previewPaper.getTitle())
                         .questionNoIds(previewPaper.getQuestionNoIds())
                         .questionNumber(previewPaper.getQuestionNoIds().length)
-                        .time(time)
+                        .time(previewPaper.getTime())
                 .build(),
                 oldList,
                 PaperOrigin.PREVIEW, previewPaper.getId());
 
         return previewPaper;
     }
-
-    public boolean delete(Number id){
-        PreviewPaper in = one(previewPaperMapper, id);
-        if(in == null){
-            throw new ParameterException("预习作业不存在");
-        }
-        int result = delete(previewPaperMapper, id);
-        return result > 0;
-    }
-
-    public PreviewPaper get(Number id){
-        PreviewPaper in = one(previewPaperMapper, id);
-
-        if(in == null){
-            throw new ParameterException("预习作业不存在");
-        }
-        return in;
-    }
-
-    public Page<PreviewPaper> select(int page, int pageSize){
-        return select(previewPaperMapper, page, pageSize);
-    }
-
-    public Page<PreviewPaper> select(int page, int pageSize, Integer category, PreviewStatus status){
-        Example example = new Example(PreviewPaper.class);
-        if(category != null && category>0)
-            example.and(
-                    example.createCriteria().andEqualTo("category", category)
-            );
-        if (status!= PreviewStatus.ALL){
-            tk.mybatis.mapper.entity.Example.Criteria criteria = example.createCriteria();
-            switch(status){
-                case NO_START:
-                    criteria.andLessThan("startTime", new Date());
-                    break;
-                case PROCESS:
-                    criteria.andGreaterThanOrEqualTo("startTime", new Date()).andLessThan("endTime", new Date());
-                    break;
-                case FINISH:
-                    criteria.andGreaterThanOrEqualTo("endTime", new Date());
-                    break;
-            }
-            example.and(criteria);
-        }
-        example.orderBy("id").desc();
-        return select(previewPaperMapper, example, page, pageSize);
-    }
-
-    public List<PreviewPaper> select(Collection ids){
-        return select(previewPaperMapper, ids);
-    }
-
 }

+ 33 - 4
server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java

@@ -208,7 +208,7 @@ public class QuestionFlowService {
             if (paper.getIsAdapt() > 0){
 
             }else{
-
+                // 随机挑题
             }
             question.setQuestionNoId(relation.getId());
             question.setQuestionId(relation.getQuestionId());
@@ -245,7 +245,7 @@ public class QuestionFlowService {
             detail.put("object", objectCorrect);
             correct = correct & objectCorrect;
 
-            boolean optionsCorrect = this.sentenceAnswer(userAnswer.getJSONArray("options"), answer.getJSONArray("options"));
+            boolean optionsCorrect = this.sentenceAnswerOption(userAnswer.getJSONArray("options"), answer.getJSONArray("options"));
             detail.put("options", optionsCorrect);
 //            correct = correct & optionsCorrect;
 
@@ -312,9 +312,10 @@ public class QuestionFlowService {
         if (questionNoIds.size() == 0){
             throw new ParameterException("题目数为空");
         }
+        QuestionOrigin questionOrigin = QuestionOrigin.WithPaper(origin);
         if (filterTimes > 0){
             // 过滤重复多次的题目
-            questionNoIds = userPaperQuestionService.filterTimesQuestion(userId, QuestionOrigin.WithPaper(origin), questionNoIds, filterTimes);
+            questionNoIds = userPaperQuestionService.filterTimesQuestion(userId, questionOrigin, module, questionNoIds, filterTimes);
             if (questionNoIds.size() == 0){
                 throw new ParameterException("题目数为空");
             }
@@ -331,7 +332,10 @@ public class QuestionFlowService {
                 .originId(0)
                 .build();
         callback.callback(paper, 0);
-        return userPaperService.add(paper);
+        paper = userPaperService.add(paper);
+        // 绑定关系,用于下次处理过滤
+        userPaperQuestionService.addOrigin(userId, paper.getId(), questionOrigin, module, questionNoIds);
+        return paper;
     }
 
     /**
@@ -655,6 +659,31 @@ public class QuestionFlowService {
      */
     private Boolean sentenceAnswer(JSONArray userAnswer, JSONArray answer){
         // 数量一致,并且都包含
+        for(Object a : answer){
+            JSONArray singleArray = (JSONArray) a;
+            if (singleArray.size() == userAnswer.size()){
+                for (int i = 0; i < singleArray.size(); i++){
+                    JSONObject single = singleArray.getJSONObject(i);
+                    JSONObject user = userAnswer.getJSONObject(i);
+                    // 判断uuid是否一致
+                    if (!single.getString("uuid").equals(user.getString("uuid"))){
+                        return false;
+                    }
+                }
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 长难句多选答案判断
+     * @param userAnswer
+     * @param answer
+     * @return
+     */
+    private Boolean sentenceAnswerOption(JSONArray userAnswer, JSONArray answer){
+        // 数量一致,并且都包含
         if (userAnswer.size() == answer.size()){
             for(Object s : userAnswer){
                 if (!answer.contains(s)){

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

@@ -0,0 +1,165 @@
+package com.qxgmat.service.extend;
+
+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.dao.entity.Question;
+import com.qxgmat.data.dao.entity.SentencePaper;
+import com.qxgmat.data.dao.entity.SentenceQuestion;
+import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
+import com.qxgmat.service.inline.SentencePaperService;
+import com.qxgmat.service.inline.QuestionService;
+import com.qxgmat.service.inline.SentenceQuestionService;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class SentenceService {
+
+    @Value("${paper.sentenceLength}")
+    private Integer paperLength;
+
+    @Resource
+    private QuestionService questionService;
+
+    @Resource
+    private SentenceQuestionService sentenceQuestionService;
+
+    @Resource
+    private SentencePaperService sentencePaperService;
+
+
+    /**
+     * 添加长难句题目:加入题库,关联题目,并关联长难句paper
+     * @param relation
+     * @return
+     */
+    @Transactional
+    public SentenceQuestion addQuestion(SentenceQuestionRelation relation){
+        SentenceQuestion in = sentenceQuestionService.getByNo(relation.getNo());
+        if (in != null){
+            throw new ParameterException("序号已经存在");
+        }
+        Question question = relation.getQuestion();
+        question.setQuestionType(QuestionType.SENTENCE.key);
+        question = questionService.add(question);
+        // 绑定关系
+        relation.setQuestionId(question.getId());
+        relation.setSubject(String.format("CNG%d", relation.getNo()));
+
+        SentenceQuestion sentenceQuestion =  sentenceQuestionService.add(relation);
+
+        // 绑定关系:统一组卷
+//        addQuestionToPaperWithNo(sentenceQuestion);
+//
+//        if (sentenceQuestion.getIsTrail() > 0){
+//            addQuestionToPaperWithTrail(sentenceQuestion);
+//        }
+        return sentenceQuestion;
+    }
+
+    /**
+     * 更新长难句题目:更新题库,,变更长难句paper
+     * @param relation
+     * @return
+     */
+    @Transactional
+    public SentenceQuestion editQuestion(SentenceQuestionRelation relation){
+        SentenceQuestion in = sentenceQuestionService.getByNo(relation.getNo());
+        if (in != null && !in.getId().equals(relation.getId())){
+            throw new ParameterException("序号已经存在");
+        }
+
+        Question question = relation.getQuestion();
+        question.setQuestionType(QuestionType.SENTENCE.key);
+        question = questionService.edit(question);
+
+        if(in == null){
+            in = sentenceQuestionService.get(relation.getId());
+        }
+        relation.setSubject(String.format("CNG%d", relation.getNo()));
+
+        // 根据序号调整分组:移出原有关系 - 绑定关系
+//        if (!in.getNo().equals(relation.getNo())){
+//            removeQuestionFromPaper(in, SentenceLogic.NO);
+//            addQuestionToPaperWithNo(relation);
+//        }
+
+        // 根据试用调整
+//        if (!in.getIsTrail().equals(relation.getIsTrail())){
+//            if (relation.getIsTrail() > 0){
+//                addQuestionToPaperWithTrail(relation);
+//            }else{
+//                removeQuestionFromPaper(in, SentenceLogic.TRAIL);
+//            }
+//        }
+        SentenceQuestion sentenceQuestion = sentenceQuestionService.edit(relation);
+
+        return sentenceQuestion;
+    }
+
+
+    /**
+     * 根据题目创建组卷序列
+     * @param logic
+     * @param questionList
+     * @return
+     */
+    @Transactional
+    public List<SentencePaper> createPaper(String prefixTitle, SentenceLogic logic, List<SentenceQuestion> questionList){
+        Integer no = 0;
+        List<SentencePaper> list = new ArrayList<>();
+        List<Integer> tmp = new ArrayList<>(paperLength);
+        for(SentenceQuestion question : questionList){
+            tmp.add(question.getId());
+            if (tmp.size() == paperLength){
+                no += 1;
+                SentencePaper paper = sentencePaperService.add(SentencePaper.builder()
+                        .logic(logic.key)
+                        .no(no)
+                        .questionNumber(tmp.size())
+                        .status(0)
+                        .questionNoIds(tmp.toArray(new Integer[0])).build()
+                );
+                paper.setTitle(sentencePaperService.generateTitle(prefixTitle, paperLength, paper.getNo(), paper.getQuestionNumber()));
+                list.add(paper);
+                tmp.clear();
+            }
+        }
+        if (tmp.size() > 0){
+            no += 1;
+            SentencePaper paper = sentencePaperService.add(SentencePaper.builder()
+                    .logic(logic.key)
+                    .no(no)
+                    .questionNumber(tmp.size())
+                    .status(0)
+                    .questionNoIds(tmp.toArray(new Integer[0])).build()
+            );
+            paper.setTitle(sentencePaperService.generateTitle(prefixTitle, paperLength, paper.getNo(), paper.getQuestionNumber()));
+            list.add(paper);
+        }
+        return list;
+    }
+
+    /**
+     * 切换新组卷
+     * @param logic
+     * @param ids
+     */
+    @Transactional
+    public void switchPaper(SentenceLogic logic, Collection ids){
+        // 先将可用卷删除
+        List<SentencePaper> list = sentencePaperService.listByLogic(logic);
+        Collection oldIds = Transform.getIds(list, SentencePaper.class, "id");
+        sentencePaperService.updatePaper(oldIds, 0);
+        // 将新组卷启用
+        sentencePaperService.updatePaper(ids, 1);
+    }
+}

+ 1 - 3
server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java

@@ -1,15 +1,13 @@
 package com.qxgmat.service.extend;
 
-import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
-import com.qxgmat.data.dao.TextbookPaperMapper;
 import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.TextbookLibrary;
 import com.qxgmat.data.dao.entity.TextbookPaper;
 import com.qxgmat.data.dao.entity.TextbookQuestion;
 import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
-import com.qxgmat.service.TextbookPaperService;
+import com.qxgmat.service.inline.TextbookPaperService;
 import com.qxgmat.service.inline.QuestionService;
 import com.qxgmat.service.inline.TextbookLibraryService;
 import com.qxgmat.service.inline.TextbookQuestionService;

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java

@@ -298,4 +298,14 @@ public class ToolsService {
         Rank rank = rankService.search(quantScore, verbalScore);
         return rank != null ? rank : new Rank();
     }
+
+    /**
+     * 根据模考分数获取排名
+     * @param score
+     * @return
+     */
+    public Rank scoreRank(JSONObject score){
+        Rank rank = rankService.search(score.getInteger("quant"), score.getInteger("verbal"));
+        return rank != null ? rank : new Rank();
+    }
 }

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

@@ -1,20 +1,16 @@
-package com.qxgmat.service;
+package com.qxgmat.service.inline;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.dao.ExaminationPaperMapper;
 import com.qxgmat.data.dao.entity.ExaminationPaper;
-import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.UserPaper;
-import com.qxgmat.service.inline.QuestionService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.Collection;
@@ -27,12 +23,6 @@ public class ExaminationPaperService extends AbstractService {
     @Resource
     private ExaminationPaperMapper examinationPaperMapper;
 
-    @Resource
-    private QuestionService questionService;
-
-    public void initUserPaper(UserPaper userPaper, Integer id){
-    }
-
     /**
      * 根据第三层获取paper
      * @param id

+ 0 - 3
server/gateway-api/src/main/java/com/qxgmat/service/inline/ExaminationStructService.java

@@ -6,11 +6,8 @@ import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.dao.ExaminationStructMapper;
-import com.qxgmat.data.dao.ExerciseStructMapper;
 import com.qxgmat.data.dao.entity.ExaminationPaper;
 import com.qxgmat.data.dao.entity.ExaminationStruct;
-import com.qxgmat.data.dao.entity.ExerciseStruct;
-import com.qxgmat.service.ExaminationPaperService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.cache.annotation.CacheEvict;

+ 50 - 56
server/gateway-api/src/main/java/com/qxgmat/service/ExercisePaperService.java

@@ -1,30 +1,18 @@
-package com.qxgmat.service;
+package com.qxgmat.service.inline;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.PageResult;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.SettingKey;
 import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
 import com.qxgmat.data.dao.ExercisePaperMapper;
 import com.qxgmat.data.dao.entity.ExercisePaper;
-import com.qxgmat.data.dao.entity.Question;
-import com.qxgmat.data.dao.entity.UserPaper;
-import com.qxgmat.data.dao.entity.UserReport;
 import com.qxgmat.data.relation.ExercisePaperRelationMapper;
-import com.qxgmat.data.relation.UserPaperRelationMapper;
-import com.qxgmat.data.relation.UserReportRelationMapper;
-import com.qxgmat.data.relation.entity.QuestionNoRelation;
-import com.qxgmat.data.relation.entity.UserExercisePaperRelation;
-import com.qxgmat.service.inline.QuestionService;
-import com.qxgmat.service.inline.UserReportService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.ArrayList;
@@ -41,20 +29,58 @@ public class ExercisePaperService extends AbstractService {
     @Resource
     private ExercisePaperRelationMapper exercisePaperRelationMapper;
 
-    @Resource
-    private QuestionService questionService;
-
-    @Resource
-    private UserPaperRelationMapper userPaperRelationMapper;
+    /**
+     * 切换paper状态
+     * @param ids
+     * @param status
+     */
+    public void updatePaper(Collection ids, Integer status){
+        Example example = new Example(ExercisePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("id", ids)
+        );
+        update(exercisePaperMapper, example, ExercisePaper.builder().status(status).build());
+    }
 
-    @Resource
-    private UserPaperService userPaperService;
 
-    @Resource
-    private UserReportRelationMapper userReportRelationMapper;
+    /**
+     * 获取可用的试卷列表:单个分组逻辑, 扩展逻辑
+     * @param three
+     * @param four
+     * @param logic
+     * @param extend
+     * @return
+     */
+    public List<ExercisePaper> listByLogic(Integer three, Integer four, ExerciseLogic logic, String extend){
+        Example example = new Example(ExercisePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("structThree", three)
+                        .andEqualTo("structFour", four)
+                        .andEqualTo("logic", logic.key)
+                        .andEqualTo("status", 1)
+        );
+        if (extend != null){
+            example.and(
+                    example.createCriteria()
+                    .andEqualTo("logicExtend", extend)
+            );
+        }
+        example.orderBy("no").asc();
+        return select(exercisePaperMapper, example);
+    }
 
-    @Resource
-    private UserReportService userReportService;
+    /**
+     * 生成试卷名称
+     * @param prefixTitle
+     * @param no
+     * @param questionNumber
+     * @return
+     */
+    public String generateTitle(String prefixTitle, Integer length, Integer no, Integer questionNumber){
+        return String.format("%s#%d~%d", prefixTitle, (no - 1) * length + 1, (no - 1) * length + questionNumber);
+    }
 
     /**
      * 获取考点分组所有可用考点信息
@@ -74,38 +100,6 @@ public class ExercisePaperService extends AbstractService {
         }
         return places;
     }
-    /**
-     * 查找用户作业, 并关联用户最后一次作业
-     * @param page
-     * @param size
-     * @param structId
-     * @param userId
-     * @param logic
-     * @param logicExtend
-     * @param times
-     * @return
-     */
-    public PageResult<UserExercisePaperRelation> list(int page, int size, Number structId, Number userId, ExerciseLogic logic, String logicExtend, Integer times){
-        String logicKey = logic != null ? logic.key : "";
-        Page<UserPaper> p = page(()->{
-            userPaperRelationMapper.listExercisePaper(structId, userId, logicKey, logicExtend, times);
-        },page, size);
-
-        Collection ids = Transform.getIds(p, UserPaper.class, "id");
-
-        // 获取详细数据
-        List<UserPaper> list = userPaperService.select(ids);
-        List<UserExercisePaperRelation> pr = Transform.convert(list, UserExercisePaperRelation.class);
-
-        // 获取最后一次作业结果
-        List<UserReport> reportList = userReportRelationMapper.listLast(ids);
-        Collection reportIds = Transform.getIds(reportList, UserReport.class, "id");
-        Transform.replace(reportList, userReportService.select(reportIds), UserReport.class, "id");
-
-        Transform.combine(p, reportList, UserExercisePaperRelation.class, "id", "report", UserReport.class, "paperId");
-
-        return new PageResult<>(pr, p.getTotal());
-    }
 
     public ExercisePaper add(ExercisePaper paper){
         int result = insert(exercisePaperMapper, paper);

+ 0 - 36
server/gateway-api/src/main/java/com/qxgmat/service/inline/ExerciseQuestionService.java

@@ -2,15 +2,10 @@ package com.qxgmat.service.inline;
 
 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.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.ExercisePaperQuestionMapper;
 import com.qxgmat.data.dao.entity.ExercisePaperQuestion;
-import com.qxgmat.data.dao.entity.QuestionNo;
-import com.qxgmat.data.relation.ExerciseQuestionRelationMapper;
 import com.qxgmat.data.relation.QuestionNoRelationMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -27,37 +22,6 @@ public class ExerciseQuestionService extends AbstractService {
     @Resource
     private ExercisePaperQuestionMapper exerciseQuestionMapper;
 
-    @Resource
-    private ExerciseQuestionRelationMapper exerciseQuestionRelationMapper;
-
-    @Resource
-    private QuestionNoRelationMapper questionNoRelationMapper;
-
-    @Resource
-    private QuestionNoService questionNoService;
-
-
-    public Page<ExercisePaperQuestion> listAdmin(int page, int pageSize, String questionType, Number structId, Number questionNo, Number paperId, String place, String difficult, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
-
-        Page<ExercisePaperQuestion> p = page(() -> {
-            exerciseQuestionRelationMapper.listAdmin(questionType, structId, questionNo, paperId, place, difficult, startTime, endTime, finalOrder, finalDirection.key);
-        }, page, pageSize);
-
-        Collection ids = Transform.getIds(p, ExercisePaperQuestion.class, "id");
-
-        // 获取详细数据
-        List<ExercisePaperQuestion> list = select(ids);
-        Transform.replace(p, list, ExercisePaperQuestion.class, "id");
-
-        return p;
-    }
-
     public ExercisePaperQuestion add(ExercisePaperQuestion question){
         int result = insert(exerciseQuestionMapper, question);
         question = one(exerciseQuestionMapper, question.getId());

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

@@ -0,0 +1,92 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.PageResult;
+import com.nuliji.tools.Transform;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.QuestionType;
+import com.qxgmat.data.constants.enums.module.PaperModule;
+import com.qxgmat.data.constants.enums.module.PaperOrigin;
+import com.qxgmat.data.constants.enums.module.QuestionModule;
+import com.qxgmat.data.constants.enums.status.PreviewStatus;
+import com.qxgmat.data.dao.PreviewPaperMapper;
+import com.qxgmat.data.dao.entity.PreviewPaper;
+import com.qxgmat.data.dao.entity.UserPaper;
+import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.relation.UserPaperRelationMapper;
+import com.qxgmat.data.relation.UserReportRelationMapper;
+import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
+import com.qxgmat.service.UserPaperService;
+import com.qxgmat.service.extend.ToolsService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Service
+public class PreviewPaperService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(PreviewPaperService.class);
+
+    @Resource
+    private PreviewPaperMapper previewPaperMapper;
+
+
+    public boolean delete(Number id){
+        PreviewPaper in = one(previewPaperMapper, id);
+        if(in == null){
+            throw new ParameterException("预习作业不存在");
+        }
+        int result = delete(previewPaperMapper, id);
+        return result > 0;
+    }
+
+    public PreviewPaper get(Number id){
+        PreviewPaper in = one(previewPaperMapper, id);
+
+        if(in == null){
+            throw new ParameterException("预习作业不存在");
+        }
+        return in;
+    }
+
+    public Page<PreviewPaper> select(int page, int pageSize){
+        return select(previewPaperMapper, page, pageSize);
+    }
+
+    public Page<PreviewPaper> select(int page, int pageSize, Integer category, PreviewStatus status){
+        Example example = new Example(PreviewPaper.class);
+        if(category != null && category>0)
+            example.and(
+                    example.createCriteria().andEqualTo("category", category)
+            );
+        if (status!= PreviewStatus.ALL){
+            tk.mybatis.mapper.entity.Example.Criteria criteria = example.createCriteria();
+            switch(status){
+                case NO_START:
+                    criteria.andLessThan("startTime", new Date());
+                    break;
+                case PROCESS:
+                    criteria.andGreaterThanOrEqualTo("startTime", new Date()).andLessThan("endTime", new Date());
+                    break;
+                case FINISH:
+                    criteria.andGreaterThanOrEqualTo("endTime", new Date());
+                    break;
+            }
+            example.and(criteria);
+        }
+        example.orderBy("id").desc();
+        return select(previewPaperMapper, example, page, pageSize);
+    }
+
+    public List<PreviewPaper> select(Collection ids){
+        return select(previewPaperMapper, ids);
+    }
+
+}

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

@@ -7,6 +7,7 @@ import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.module.StructModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.QuestionNoMapper;
 import com.qxgmat.data.dao.entity.Question;
@@ -28,6 +29,7 @@ import java.util.stream.Collectors;
 public class QuestionNoService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(QuestionNoService.class);
     protected boolean SOFT_FLAG = true;
+    final static String formatSet = "FIND_IN_SET('%d', module_struct)";
 
     @Resource
     private QuestionNoMapper questionNoMapper;
@@ -38,15 +40,6 @@ public class QuestionNoService extends AbstractService {
     @Resource
     private QuestionService questionService;
 
-//    private List<String> stops = new ArrayList<String>(){{
-//       add(".");
-//       add(",");
-//       add("!");
-//       add(":");
-//       add(";");
-//       add("?");
-//    }};
-
     /**
      * 根据题干搜索相似题目: 相似度80%
      * @param page
@@ -96,6 +89,23 @@ public class QuestionNoService extends AbstractService {
     }
 
     /**
+     * 获取结构模块下的题目列表: 按序号排列
+     * @param module
+     * @param structId
+     * @return
+     */
+    public List<QuestionNoRelation> listByStruct(StructModule module, Integer structId){
+        Example example = new Example(QuestionNo.class);
+        example.and(
+                example.createCriteria()
+                .andEqualTo("module", module.key)
+                .andCondition(String.format(formatSet, structId))
+        );
+        example.orderBy("no").asc();
+        return relation(select(questionNoMapper, example));
+    }
+
+    /**
      * 根据题目标号列表获取题目
      * @param nos
      * @param module
@@ -253,7 +263,7 @@ public class QuestionNoService extends AbstractService {
         return relationMap;
     }
 
-    private List<QuestionNoRelation> relation(List<QuestionNo> p){
+    public List<QuestionNoRelation> relation(List<QuestionNo> p){
         List<QuestionNoRelation> relationList = Transform.convert(p, QuestionNoRelation.class);
 
         Collection questionIds = Transform.getIds(p, QuestionNo.class, "questionId");
@@ -262,7 +272,7 @@ public class QuestionNoService extends AbstractService {
         return relationList;
     }
 
-    private QuestionNoRelation relation(QuestionNo p){
+    public QuestionNoRelation relation(QuestionNo p){
         QuestionNoRelation relation = Transform.convert(p, QuestionNoRelation.class);
 
         Question question = questionService.get(p.getQuestionId());

+ 6 - 6
server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionService.java

@@ -61,12 +61,12 @@ public class QuestionService extends AbstractService {
             ids.addAll(Arrays.stream(questionIds).collect(Collectors.toList()));
         }
         List<Question> questionList = select(ids);
-        Map questionNoMap = Transform.getMap(questionList, Question.class, "id");
+        Map questionMap = Transform.getMap(questionList, Question.class, "id");
         List<Question> l = new ArrayList<>();
         for(Integer k: questionIdsMap.keySet()){
             l.clear();
             for (Integer questionNoId : questionIdsMap.get(k)){
-                l.add((Question)questionNoMap.get(questionNoId));
+                l.add((Question)questionMap.get(questionNoId));
             }
             relationMap.put(k, statPaper(l));
         }
@@ -94,7 +94,7 @@ public class QuestionService extends AbstractService {
         }else{
             question.setOfficialContent("");
         }
-        if (question.getAssociationContent().length > 0){
+        if (question.getAssociationContent() != null && question.getAssociationContent().length > 0){
             question.setAssociationTime(new Date());
         }
         int result = insert(questionMapper, question);
@@ -111,13 +111,13 @@ public class QuestionService extends AbstractService {
             throw new ParameterException("题目不存在");
         }
         // 按实际更新更改更新时间
-        if (!in.getQxContent().equals(question.getQxContent())){
+        if (question.getQxContent() != null && (in.getQxContent() == null || !in.getQxContent().equals(question.getQxContent()))){
             question.setQxTime(new Date());
         }
-        if (!in.getOfficialContent().equals(question.getOfficialContent())){
+        if (question.getOfficialContent() != null && (in.getOfficialContent() == null || !in.getOfficialContent().equals(question.getOfficialContent()))){
             question.setOfficialTime(new Date());
         }
-        if (in.getAssociationContent().length != question.getAssociationContent().length){
+        if (question.getAssociationContent() != null && (in.getAssociationContent() == null || in.getAssociationContent().length != question.getAssociationContent().length)){
             question.setAssociationTime(new Date());
         }
         int result = update(questionMapper, question);

+ 154 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/SentencePaperService.java

@@ -0,0 +1,154 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.logic.SentenceLogic;
+import com.qxgmat.data.dao.SentencePaperMapper;
+import com.qxgmat.data.dao.entity.SentencePaper;
+import com.qxgmat.data.dao.entity.SentenceQuestion;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class SentencePaperService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(SentencePaperService.class);
+
+    final static String formatSet = "FIND_IN_SET('%d', question_no_ids)";
+
+    @Resource
+    private SentencePaperMapper sentencePaperMapper;
+
+    /**
+     * 切换paper状态
+     * @param ids
+     * @param status
+     */
+    public void updatePaper(Collection ids, Integer status){
+        Example example = new Example(SentencePaper.class);
+        example.and(
+                example.createCriteria()
+                .andIn("id", ids)
+        );
+        update(sentencePaperMapper, example, SentencePaper.builder().status(status).build());
+    }
+
+    /**
+     * 获取可用的试卷列表:单个分组逻辑
+     * @param logic
+     * @return
+     */
+    public List<SentencePaper> listByLogic(SentenceLogic logic){
+        Example example = new Example(SentencePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("logic", logic.key)
+                        .andEqualTo("status", 1)
+        );
+        example.orderBy("no").asc();
+        return select(sentencePaperMapper, example);
+    }
+
+    /**
+     * 按序号获取组卷
+     * @param no
+     * @param logic
+     * @return
+     */
+    public SentencePaper getByNo(Integer no, SentenceLogic logic){
+        Example example = new Example(SentencePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("no", no)
+                        .andEqualTo("logic", logic.key)
+        );
+        return one(sentencePaperMapper, example);
+    }
+
+    /**
+     * 生成试卷名称
+     * @param prefixTitle
+     * @param no
+     * @param questionNumber
+     * @return
+     */
+    public String generateTitle(String prefixTitle, Integer length, Integer no, Integer questionNumber){
+        return String.format("%s#%d~%d", prefixTitle, (no - 1) * length + 1, (no - 1) * length + questionNumber);
+    }
+
+    public SentencePaper getLast(SentenceLogic logic){
+        Example example = new Example(SentencePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("logic", logic.key)
+        );
+        example.orderBy("createTime").desc();
+        return one(sentencePaperMapper, example);
+    }
+
+    public List<SentencePaper> listByQuestion(SentenceQuestion question, SentenceLogic logic){
+        Example example = new Example(SentencePaper.class);
+        example.and(
+                example.createCriteria()
+                        .andCondition(String.format(formatSet, question.getId()))
+        );
+        if (logic != null)
+            example.and(
+                    example.createCriteria()
+                        .andEqualTo("logic", logic.key)
+            );
+        return select(sentencePaperMapper, example);
+    }
+
+    public SentencePaper add(SentencePaper paper){
+        int result = insert(sentencePaperMapper, paper);
+        paper = one(sentencePaperMapper, paper.getId());
+        if(paper == null){
+            throw new SystemException("题目添加失败");
+        }
+        return paper;
+    }
+
+    public SentencePaper edit(SentencePaper paper){
+        SentencePaper in = one(sentencePaperMapper, paper.getId());
+        if(in == null){
+            throw new ParameterException("题目不存在");
+        }
+        int result = update(sentencePaperMapper, paper);
+        return paper;
+    }
+
+    public boolean delete(Number id){
+        SentencePaper in = one(sentencePaperMapper, id);
+        if(in == null){
+            throw new ParameterException("题目不存在");
+        }
+        int result = delete(sentencePaperMapper, id);
+        return result > 0;
+    }
+
+    public SentencePaper get(Number id){
+        SentencePaper in = one(sentencePaperMapper, id);
+
+        if(in == null){
+            throw new ParameterException("题目不存在");
+        }
+        return in;
+    }
+
+    public Page<SentencePaper> select(int page, int pageSize){
+        return select(sentencePaperMapper, page, pageSize);
+    }
+
+    public List<SentencePaper> select(Collection ids){
+        return select(sentencePaperMapper, ids);
+    }
+
+}

+ 16 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java

@@ -47,7 +47,8 @@ public class SentenceQuestionService extends AbstractService {
         if(keyword != null)
             example.and(
                     example.createCriteria()
-                    .andLike("title", "%"+keyword+"%")
+                            .orLike("title", "%"+keyword+"%")
+                            .orLike("subject", "%"+keyword+"%")
             );
         return page(() -> select(sentenceQuestionMapper, example), page, size);
     }
@@ -172,6 +173,20 @@ public class SentenceQuestionService extends AbstractService {
         return one(sentenceQuestionMapper, example);
     }
 
+    /**
+     * 获取所有组卷试题
+     * @return
+     */
+    public List<SentenceQuestion> allPaper(){
+        Example example = new Example(SentenceQuestion.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("isPaper", 1)
+        );
+        example.orderBy("no").asc();
+        return select(sentenceQuestionMapper, example);
+    }
+
     public SentenceQuestion add(SentenceQuestion question){
         int result = insert(sentenceQuestionMapper, question);
         question = one(sentenceQuestionMapper, question.getId());

+ 19 - 8
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookLibraryService.java

@@ -74,22 +74,33 @@ public class TextbookLibraryService extends AbstractService {
                 .andEqualTo("id", history.getLibraryId())
         );
         example.orderBy("id").desc();
-        TextbookLibrary last = one(textbookLibraryMapper, example);
-        if (last == null){
+        TextbookLibrary library = one(textbookLibraryMapper, example);
+        if (library == null){
             throw new ParameterException("机经不存在");
         }
-        history = textbookLibraryHistoryService.add(history);
+        Date now = new Date();
         if (!history.getQuant().isEmpty()){
-            last.setQuant(history.getQuant());
+            library.setQuant(history.getQuant());
+            library.setQuantVersion(library.getQuantVersion() + 1);
+            library.setQuantTime(now);
+            history.setQuantVersion(library.getQuantVersion());
         }
         if (!history.getIr().isEmpty()){
-            last.setIr(history.getIr());
+            library.setIr(history.getIr());
+            library.setIrVersion(library.getIrVersion() + 1);
+            library.setIrTime(now);
+            history.setIrVersion(library.getIrVersion());
         }
         if (!history.getRc().isEmpty()){
-            last.setRc(history.getRc());
+            library.setRc(history.getRc());
+            library.setRcVersion(library.getRcVersion() + 1);
+            library.setRcTime(now);
+            history.setRcVersion(library.getRcVersion());
         }
-        last.setHistoryNumber(last.getHistoryNumber() + 1);
-        return edit(last);
+        library.setHistoryNumber(library.getHistoryNumber() + 1);
+
+        history = textbookLibraryHistoryService.add(history);
+        return edit(library);
     }
 
     public TextbookLibrary add(TextbookLibrary ad){

+ 2 - 23
server/gateway-api/src/main/java/com/qxgmat/service/TextbookPaperService.java

@@ -1,50 +1,29 @@
-package com.qxgmat.service;
+package com.qxgmat.service.inline;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.logic.TextbookLogic;
 import com.qxgmat.data.dao.TextbookPaperMapper;
 import com.qxgmat.data.dao.entity.*;
-import com.qxgmat.data.relation.entity.SentenceQuestionRelation;
-import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
-import com.qxgmat.service.inline.QuestionService;
-import com.qxgmat.service.inline.TextbookLibraryService;
-import com.qxgmat.service.inline.TextbookQuestionService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
-import java.text.SimpleDateFormat;
 import java.util.*;
-import java.util.stream.Collectors;
 
 @Service
 public class TextbookPaperService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(TextbookPaperService.class);
 
     final static String formatSet = "FIND_IN_SET('%d', question_no_ids)";
-    final static String formatTitle = "";
 
     @Resource
     private TextbookPaperMapper textbookPaperMapper;
 
-    @Resource
-    private QuestionService questionService;
-
-    @Resource
-    private TextbookQuestionService textbookQuestionService;
-
-    @Resource
-    private TextbookLibraryService textbookLibraryService;
-
-
     /**
      * 更新所有组卷title
      * @param libraryId
@@ -64,7 +43,7 @@ public class TextbookPaperService extends AbstractService {
     }
 
     /**
-     * 生成题目id
+     * 生成试卷名称
      * @param prefixTitle
      * @param no
      * @param questionNumber

+ 0 - 3
server/gateway-api/src/main/java/com/qxgmat/service/inline/TextbookQuestionService.java

@@ -29,9 +29,6 @@ import java.util.stream.Collectors;
 @Service
 public class TextbookQuestionService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(TextbookQuestionService.class);
-    SimpleDateFormat stringToDate = new SimpleDateFormat("yyyy-MM-dd");
-    SimpleDateFormat dateToString = new SimpleDateFormat("yyyy年MM月dd日");
-    SimpleDateFormat dateToDay = new SimpleDateFormat("dd日");
 
     @Resource
     private TextbookQuestionMapper textbookQuestionMapper;

+ 0 - 3
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserClassService.java

@@ -21,9 +21,6 @@ public class UserClassService extends AbstractService {
     @Resource
     private UserClassMapper userClassMapper;
 
-    @Resource
-    private UserPayService userPayService;
-
     /**
      * 合并用户信息,将old转移至new
      * @param oldUserId

+ 38 - 6
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserPaperQuestionService.java

@@ -66,13 +66,45 @@ public class UserPaperQuestionService extends AbstractService {
         }
     }
 
-    public List<Integer> filterTimesQuestion(Integer userId, QuestionOrigin origin, Collection<Integer> questionNoIds, Integer filterTimes){
-        List<UserPaperQuestion> userPaperQuestionList = userPaperQuestionRelationMapper.filterTimes(userId, origin.key, questionNoIds, filterTimes);
-        List<Integer> ids = new ArrayList<>(userPaperQuestionList.size());
-        for(UserPaperQuestion question : userPaperQuestionList){
-            ids.add(question.getQuestionNoId());
+    /**
+     * 符合过滤次数的试题
+     * @param userId
+     * @param origin
+     * @param questionNoIds
+     * @param filterTimes
+     * @return
+     */
+    public List<Integer> filterTimesQuestion(Integer userId, QuestionOrigin origin, QuestionModule module, List<Integer> questionNoIds, Integer filterTimes){
+        List<UserPaperQuestion> filterQuestionList = userPaperQuestionRelationMapper.filterTimes(userId, origin.key, module.key, questionNoIds, filterTimes);
+        if (filterQuestionList == null || filterQuestionList.size() == 0){
+            return questionNoIds;
+        }
+        // 移除符合过滤条件的题目
+        for(UserPaperQuestion question : filterQuestionList){
+            questionNoIds.remove(question.getQuestionNoId());
+        }
+        return questionNoIds;
+    }
+
+    /**
+     * 批量添加所有题目关系
+     * @param userId
+     * @param paperId
+     * @param origin
+     * @param module
+     * @param questionNoIds
+     */
+    public void addOrigin(Integer userId, Integer paperId, QuestionOrigin origin, QuestionModule module, List<Integer> questionNoIds){
+        for(Integer questionNoId : questionNoIds){
+            UserPaperQuestion paperQuestion = UserPaperQuestion.builder()
+                    .userId(userId)
+                    .questionModule(module.key)
+                    .questionOrigin(origin.key)
+                    .questionNoId(questionNoId)
+                    .paperId(paperId)
+                    .build();
+            add(paperQuestion);
         }
-        return ids;
     }
 
     /**

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

@@ -49,7 +49,7 @@ public class UserReportService extends AbstractService {
         if(userClassList.size() == 0) return relationMap;
         for(UserReport row: userClassList){
             List<UserReport> l;
-            Number paperId = row.getPaperId();
+            Integer paperId = row.getPaperId();
             if(!relationMap.containsKey(paperId)){
                 l = new ArrayList<>();
                 relationMap.put(paperId, l);

+ 189 - 1
server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java

@@ -1,34 +1,222 @@
 package com.qxgmat.task;
 
+import com.alibaba.fastjson.JSONObject;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.QuestionDifficult;
+import com.qxgmat.data.constants.enums.QuestionType;
+import com.qxgmat.data.constants.enums.SettingKey;
+import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
+import com.qxgmat.data.constants.enums.logic.SentenceLogic;
+import com.qxgmat.data.constants.enums.module.StructModule;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
+import com.qxgmat.service.extend.ExerciseService;
+import com.qxgmat.service.extend.SentenceService;
+import com.qxgmat.service.inline.ExerciseStructService;
+import com.qxgmat.service.inline.QuestionNoService;
+import com.qxgmat.service.inline.SentenceQuestionService;
+import com.qxgmat.service.inline.SettingService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.stereotype.Component;
 
+import java.util.*;
+import java.util.stream.Collectors;
+
 @Component
 public class AsyncTask {
     private static final Logger logger = LoggerFactory.getLogger(AsyncTask.class);
 
+    @Autowired
+    private SentenceQuestionService sentenceQuestionService;
+
+    @Autowired
+    private SentenceService sentenceService;
+
+    @Autowired
+    private ExerciseService exerciseService;
+
+    @Autowired
+    private QuestionNoService questionNoService;
+
+    @Autowired
+    private ExerciseStructService exerciseStructService;
+
+    @Autowired
+    private SettingService settingService;
+
     @Async
     public void autoExercisePaper() {
         logger.info("自动练习组卷:顺序,考点,难易度");
         long start = System.currentTimeMillis();
+        Setting setting = settingService.getByKey(SettingKey.EXERCISE_PAPER_STATUS);
+        JSONObject status = setting.getValue();
+        status.put("process", 10);
+        // 按所有4级结构
+        List<ExerciseStruct> p = exerciseStructService.all();
+        for(ExerciseStruct struct : p){
+            if (struct.getLevel()!=4){
+                continue;
+            }
+            String prefixTitle = String.format("%s%s", struct.getTitleEn(), struct.getTitleZh());
+            QuestionType questionType = QuestionType.ValueOf(struct.getExtend());
+            List<QuestionNoRelation> list = questionNoService.listByStruct(StructModule.EXERCISE, struct.getId());
+
+            // 按顺序组卷
+            List<ExercisePaper> noPapers = exerciseService.createPaper(prefixTitle, questionType, struct.getParentId(), struct.getId(), exerciseService.paperLength, ExerciseLogic.NO, null, list);
+            Collection noIds = Transform.getIds(noPapers, SentencePaper.class, "id");
+            exerciseService.switchPaper(struct.getParentId(), struct.getId(), ExerciseLogic.NO, noIds);
+
+            // 按难度组卷
+            List<Integer> allDifficultIds = new ArrayList<>();
+            for(QuestionDifficult difficult : QuestionDifficult.all()){
+                List<QuestionNoRelation> difficultList = list.stream().filter((question)-> question.getQuestion().getDifficult().equals(difficult.key)).collect(Collectors.toList());
+                List<ExercisePaper> difficultPapers = exerciseService.createPaper(String.format("%s %s", prefixTitle, difficult.key), questionType, struct.getParentId(), struct.getId(), exerciseService.paperLength, ExerciseLogic.DIFFICULT, difficult.key, difficultList);
+                Collection difficultIds = Transform.getIds(difficultPapers, ExercisePaper.class, "id");
+                allDifficultIds.addAll(difficultIds);
+            }
+            exerciseService.switchPaper(struct.getParentId(), struct.getId(), ExerciseLogic.DIFFICULT, allDifficultIds);
+
+            // 按考点组卷
+            Map<String, List<QuestionNoRelation>> placeMap = new HashMap<>();
+            for(QuestionNoRelation relation:list){
+                String place = relation.getQuestion().getPlace();
+                if (!placeMap.containsKey(place)){
+                    placeMap.put(place, new ArrayList<>());
+                }
+                List<QuestionNoRelation> placeList = placeMap.get(place);
+                placeList.add(relation);
+            }
+            List<Integer> allPlaceIds = new ArrayList<>();
+            for(String place: placeMap.keySet()){
+                List<QuestionNoRelation> placeList = placeMap.get(place);
+                List<ExercisePaper> difficultPapers = exerciseService.createPaper(String.format("%s %s", prefixTitle, place), questionType, struct.getParentId(), struct.getId(), exerciseService.paperLength, ExerciseLogic.PLACE, place, placeList);
+                Collection placeIds = Transform.getIds(difficultPapers, ExercisePaper.class, "id");
+                allPlaceIds.addAll(placeIds);
+            }
+            exerciseService.switchPaper(struct.getParentId(), struct.getId(), ExerciseLogic.PLACE, allPlaceIds);
+
+            // 按难易度组卷:保持和下方难易度组卷一致
+            list.sort((x, y)-> {
+                // 难度从高到低
+                Integer xScore = x.getTotalCorrect() * 100/ x.getTotalNumber();
+                Integer yScore = y.getTotalCorrect() * 100/ y.getTotalNumber();
+                return xScore.compareTo(yScore);
+            });
+            List<ExercisePaper> errorPapers = exerciseService.createPaper(prefixTitle, questionType, struct.getParentId(), struct.getId(), exerciseService.paperLength, ExerciseLogic.ERROR, null, list);
+            Collection errorIds = Transform.getIds(errorPapers, SentencePaper.class, "id");
+            exerciseService.switchPaper(struct.getParentId(), struct.getId(), ExerciseLogic.ERROR, errorIds);
+        }
+        // 作文组卷
+        for(ExerciseStruct struct : p){
+            if (struct.getLevel()!=3 || !struct.getExtend().equals(QuestionType.AWA.key)){
+                continue;
+            }
+            String prefixTitle = String.format("%s%s", struct.getTitleEn(), struct.getTitleZh());
+            QuestionType questionType = QuestionType.ValueOf(struct.getExtend());
+            List<QuestionNoRelation> list = questionNoService.listByStruct(StructModule.EXERCISE, struct.getId());
+
+            // 按顺序组卷
+            List<ExercisePaper> noPapers = exerciseService.createPaper(prefixTitle, questionType, struct.getId(), 0, exerciseService.awaLength, ExerciseLogic.NO, null, list);
+            Collection noIds = Transform.getIds(noPapers, SentencePaper.class, "id");
+            exerciseService.switchPaper(struct.getId(), 0, ExerciseLogic.NO, noIds);
+        }
+
+        // 逻辑组卷
+        for(ExerciseStruct struct : p){
+            if (struct.getLevel()!=3 || !struct.getExtend().equals(QuestionType.IR.key)){
+                continue;
+            }
+            String prefixTitle = String.format("%s%s", struct.getTitleEn(), struct.getTitleZh());
+            QuestionType questionType = QuestionType.ValueOf(struct.getExtend());
+            List<QuestionNoRelation> list = questionNoService.listByStruct(StructModule.EXERCISE, struct.getId());
+
+            // 按顺序组卷
+            List<ExercisePaper> noPapers = exerciseService.createPaper(prefixTitle, questionType, struct.getId(), 0, exerciseService.irLength, ExerciseLogic.NO, null, list);
+            Collection noIds = Transform.getIds(noPapers, SentencePaper.class, "id");
+            exerciseService.switchPaper(struct.getId(), 0, ExerciseLogic.NO, noIds);
+        }
+
+        settingService.edit(setting);
         long end = System.currentTimeMillis();
-        logger.info("完成任务一,耗时:" + (end - start) + "毫秒");
+        logger.info("自动练习组卷,耗时:" + (end - start) + "毫秒");
     }
 
     @Async
     public void autoExercisePaperError() {
         logger.info("自动练习:难易度组卷,全局难易度判断");
+        long start = System.currentTimeMillis();
+        // 按所有4级结构
+        List<ExerciseStruct> p = exerciseStructService.all();
+        for(ExerciseStruct struct : p){
+            if (struct.getLevel()!=4){
+                continue;
+            }
+            String prefixTitle = String.format("%s%s", struct.getTitleEn(), struct.getTitleZh());
+            QuestionType questionType = QuestionType.ValueOf(struct.getExtend());
+            List<QuestionNoRelation> list = questionNoService.listByStruct(StructModule.EXERCISE, struct.getId());
+
+            // 按难易度组卷:保持和上方难易度组卷一致
+            list.sort((x, y)-> {
+                // 难度从高到低
+                Integer xScore = x.getTotalCorrect() * 100/ x.getTotalNumber();
+                Integer yScore = y.getTotalCorrect() * 100/ y.getTotalNumber();
+                return xScore.compareTo(yScore);
+            });
+            List<ExercisePaper> errorPapers = exerciseService.createPaper(prefixTitle, questionType, struct.getParentId(), struct.getId(), exerciseService.paperLength, ExerciseLogic.ERROR, null, list);
+            Collection errorIds = Transform.getIds(errorPapers, SentencePaper.class, "id");
+            exerciseService.switchPaper(struct.getParentId(), struct.getId(), ExerciseLogic.ERROR, errorIds);
+        }
+        long end = System.currentTimeMillis();
+        logger.info("自动练习难易度组卷,耗时:" + (end - start) + "毫秒");
     }
 
     @Async
     public void autoSentencePaper() {
         logger.info("自动长难句:对于试用卷进行自动生成");
+        long start = System.currentTimeMillis();
+        Setting setting = settingService.getByKey(SettingKey.SENTENCE_PAPER_STATUS);
+        JSONObject status = setting.getValue();
+        status.put("process", 10);
+        settingService.edit(setting);
+        // 获取所有组卷长难句题目
+        List<SentenceQuestion> list = sentenceQuestionService.allPaper();
+        status.put("process", 20);
+        settingService.edit(setting);
+        // 组正常卷
+        List<SentencePaper> noPapers = sentenceService.createPaper("长难句", SentenceLogic.NO, list);
+        status.put("process", 30);
+        settingService.edit(setting);
+        Collection noIds = Transform.getIds(noPapers, SentencePaper.class, "id");
+        status.put("process", 40);
+        settingService.edit(setting);
+        sentenceService.switchPaper(SentenceLogic.NO, noIds);
+        status.put("process", 60);
+        settingService.edit(setting);
+        // 组试用卷
+        List<SentenceQuestion> trailList = list.stream().filter((question)-> question.getIsTrail() > 0).collect(Collectors.toList());
+        List<SentencePaper> trailPapers = sentenceService.createPaper("长难句试用", SentenceLogic.TRAIL, trailList);
+        status.put("process", 70);
+        settingService.edit(setting);
+        Collection trailIds = Transform.getIds(trailPapers, SentencePaper.class, "id");
+        status.put("process", 80);
+        settingService.edit(setting);
+        sentenceService.switchPaper(SentenceLogic.TRAIL, trailIds);
+        status.put("process", 100);
+        settingService.edit(setting);
+        long end = System.currentTimeMillis();
+        logger.info("自动长难句组卷,耗时:" + (end - start) + "毫秒");
     }
 
     @Async
     public void postTextbookToEmail(){
         logger.info("发布机经:发送到订阅用户邮箱");
+        long start = System.currentTimeMillis();
+        // 获取订阅用户及其邮箱
+
+        long end = System.currentTimeMillis();
+        logger.info("发布机经,耗时:" + (end - start) + "毫秒");
     }
 }

+ 3 - 0
server/gateway-api/src/main/resources/application.yml

@@ -74,6 +74,9 @@ self:
 paper:
   sentenceLength: 20
   textbookLength: 31
+  exerciseLength: 20
+  awaLength: 1
+  irLength: 12
 
 examination:
   verbalA: 1