Browse Source

Merge branch 'master' of https://git.proginn.com/zaixianjiaoyu/sourcecode

KaysonCui 5 years ago
parent
commit
4bd99f206a
63 changed files with 1483 additions and 214 deletions
  1. 7 6
      front/project/admin/routes/subject/exercise/page.js
  2. 16 1
      front/project/admin/routes/subject/question/page.js
  3. 4 4
      front/project/admin/routes/subject/sentence/page.js
  4. 1 1
      front/project/admin/routes/subject/sentenceArticle/index.js
  5. 6 1
      front/project/admin/routes/subject/sentenceArticle/page.js
  6. 1 1
      front/project/admin/routes/subject/sentenceQuestion/index.js
  7. 8 7
      front/project/admin/routes/subject/sentenceQuestion/page.js
  8. 1 1
      front/project/admin/routes/subject/textbookQuestion/index.js
  9. 5 3
      front/src/components/Editor/index.js
  10. 0 1
      server/build.gradle
  11. 14 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/logic/ExerciseLogic.java
  12. 14 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/logic/SentenceLogic.java
  13. 8 1
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/PaperModule.java
  14. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExercisePaper.java
  15. 70 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/SentencePaper.java
  16. 122 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java
  17. 0 35
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserQuestion.java
  18. 3 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExercisePaperMapper.xml
  19. 3 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/SentencePaperMapper.xml
  20. 6 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPaperMapper.xml
  21. 1 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserQuestionMapper.xml
  22. 36 0
      server/data/src/main/java/com/qxgmat/data/inline/PaperStat.java
  23. 14 0
      server/data/src/main/java/com/qxgmat/data/relation/ExercisePaperRelationMapper.java
  24. 10 0
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java
  25. 38 0
      server/data/src/main/java/com/qxgmat/data/relation/entity/UserExercisePaperRelation.java
  26. 25 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExercisePaperRelationMapper.xml
  27. 30 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml
  28. 10 11
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  29. 1 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SentenceController.java
  30. 92 33
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  31. 24 9
      server/gateway-api/src/main/java/com/qxgmat/controller/api/SentenceController.java
  32. 13 3
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/QuestionDto.java
  33. 65 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/QuestionDetailExtendDto.java
  34. 59 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserExercisePaperExtendDto.java
  35. 20 9
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserHomeworkPreviewExtendDto.java
  36. 13 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/ExaminationStartDto.java
  37. 23 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/ExerciseStartDto.java
  38. 23 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/PreviewStartDto.java
  39. 13 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionFinishDto.java
  40. 15 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionNextDto.java
  41. 25 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionSubmitDto.java
  42. 5 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/SentenceStartDto.java
  43. 13 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExerciseGroupDto.java
  44. 24 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionDetailDto.java
  45. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserSentencePaperDto.java
  46. 4 14
      server/gateway-api/src/main/java/com/qxgmat/service/ExaminationPaperService.java
  47. 77 14
      server/gateway-api/src/main/java/com/qxgmat/service/ExercisePaperService.java
  48. 73 3
      server/gateway-api/src/main/java/com/qxgmat/service/HomeworkPreviewService.java
  49. 111 6
      server/gateway-api/src/main/java/com/qxgmat/service/SentencePaperService.java
  50. 5 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteService.java
  51. 53 1
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  52. 47 0
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java
  53. 6 5
      server/gateway-api/src/main/java/com/qxgmat/service/extend/TradeService.java
  54. 86 7
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java
  55. 48 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionService.java
  56. 14 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java
  57. 5 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserClassService.java
  58. 18 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserPayService.java
  59. 3 9
      server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java
  60. 2 2
      server/gateway-api/src/main/java/com/qxgmat/util/annotation/PayModuleCallback.java
  61. 1 0
      server/gateway-api/src/main/java/com/qxgmat/util/shiro/ShiroConfig.java
  62. 3 0
      server/gateway-api/src/main/resources/application.yml
  63. 1 1
      server/tools/src/main/java/com/nuliji/tools/mybatis/handler/NativeJsonHandler.java

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

@@ -172,7 +172,8 @@ export default class extends Page {
                 { title: '题源联想', ids: record.question.associationContent, field: 'associationContent', module: 'exercise', modal: true },
                 (data) => {
                   data.id = record.questionId;
-                  Question.edit(data).then(() => {
+                  data.associationContent = data.associationContent.map(row => row.id);
+                  return Question.edit(data).then(() => {
                     asyncSMessage('修改成功!');
                   });
                 });
@@ -242,16 +243,16 @@ export default class extends Page {
       data.endTime = data.time[1] || '';
     }
     Exercise.listQuestion(data).then(result => {
-      this.setTableData([{ question: {}, questionNo: { moduleStruct: [0] }, paper: {} }], result.total || 1);
+      this.setTableData(result.list, result.total || 1);
     });
   }
 
   autoAction() {
     asyncDelConfirm('组卷确认', '是否重新组卷?', () => {
-      return Exercise.auto();
-    }).then(() => {
-      asyncSMessage('开始组卷!');
-      this.refresh();
+      return Exercise.auto().then(() => {
+        asyncSMessage('开始组卷!');
+        this.refresh();
+      });
     });
   }
 

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

@@ -24,14 +24,18 @@ export default class extends Page {
     this.placeSetting = null;
     this.associationContent = [];
     this.uuid = [];
+    this.examinationStructMap = {};
+    this.exerciseStructMap = {};
   }
 
   init() {
     Promise.all([
       Exercise.allStruct().then(result => {
+        this.exerciseStructMap = getMap(result, 'id');
         return { value: 'exercise', key: 'exercise', label: '练习', title: '练习', children: formatTreeData(result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; }), 'id', 'title', 'parentId') };
       }),
       Examination.allStruct().then(result => {
+        this.examinationStructMap = getMap(result, 'id');
         return { value: 'examination', key: 'examination', label: '模考', title: '模考', children: formatTreeData(result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; }), 'id', 'title', 'parentId') };
       }),
     ]).then(result => {
@@ -121,11 +125,22 @@ export default class extends Page {
         const data = form.getFieldsValue(['id', 'moduleStruct', 'questionNo']);
         data.moduleStruct = data.moduleStruct.map(row => row);
         data.module = data.moduleStruct.shift();
+        const node = data.moduleStruct[data.moduleStruct.length - 1];
+        let nodeString;
+        switch (data.module) {
+          case 'exercise':
+            nodeString = this.exerciseStructMap[node].titleEn;
+            break;
+          case 'examination':
+            nodeString = this.examinationStructMap[node].titleEn;
+            break;
+          default:
+        }
+        data.no = `${nodeString}-${data.no}`;
         data.questionId = data.id || 0;
         delete data.id;
         data.no = data.questionNo;
         delete data.questionNo;
-        // todo 合并struct+no:-连接
         Question.addNo(data).then((result) => {
           const { questionNos = [] } = this.state;
           questionNos.push(result);

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

@@ -167,10 +167,10 @@ export default class extends Page {
 
   autoAction() {
     asyncDelConfirm('组卷确认', '是否重新组卷?', () => {
-      return Sentence.auto();
-    }).then(() => {
-      asyncSMessage('开始组卷!');
-      this.refresh();
+      return Sentence.auto().then(() => {
+        asyncSMessage('开始组卷!');
+        this.refresh();
+      });
     });
   }
 

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

@@ -4,7 +4,7 @@ import group from '../group';
 export default {
   path: '/subject/sentence/article/:id?',
   key: 'subject-sentence-article',
-  title: '文章处理',
+  title: '长难句文章',
   needLogin: true,
   module,
   group,

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

@@ -41,12 +41,14 @@ export default class extends Page {
   }
 
   refreshPart(chapter) {
+    const { form } = this.props;
     const { id } = this.params;
     Sentence.listArticle({ chapter }).then(result => {
       this.partList = result.list.map(row => row.part);
       if (id) {
         this.partList = this.partList.filter(row => row !== this.data.part);
       }
+      form.validateFields(['part'], { force: true });
     });
   }
 
@@ -55,7 +57,10 @@ export default class extends Page {
     const { form } = this.props;
     let handler;
     if (id) {
-      handler = Sentence.getArticle({ id });
+      handler = Sentence.getArticle({ id }).then((result) => {
+        this.refreshPart(result.chapter);
+        return result;
+      });
     } else {
       handler = Promise.resolve({ part: 1 });
     }

+ 1 - 1
front/project/admin/routes/subject/sentenceQuestion/index.js

@@ -4,7 +4,7 @@ import group from '../group';
 export default {
   path: '/subject/sentence/question/:id?',
   key: 'subject-sentence-question',
-  title: '新建长难句题目',
+  title: '长难句题目',
   needLogin: true,
   module,
   group,

+ 8 - 7
front/project/admin/routes/subject/sentenceQuestion/page.js

@@ -55,6 +55,7 @@ export default class extends Page {
       if (!err) {
         const data = form.getFieldsValue();
         data.isTrail = data.isTrail ? 1 : 0;
+        data.question.description = data.question.stem.replace(/<[^>]+>/g, '');
         let handler;
         if (data.id) {
           handler = Sentence.editQuestion(data);
@@ -116,9 +117,9 @@ export default class extends Page {
     return <Block flex>
       <h1>题干信息</h1>
       <Form>
-        {getFieldDecorator('id')(<input hidden />)}
+        {getFieldDecorator('question.id')(<input hidden />)}
         <Form.Item>
-          {getFieldDecorator('stem', {
+          {getFieldDecorator('question.stem', {
           })(
             <Editor placeholder='请输入内容' />,
           )}
@@ -136,7 +137,7 @@ export default class extends Page {
           <td>主语</td>
           <td>
             <Form.Item>
-              {getFieldDecorator('content.subject')(
+              {getFieldDecorator('question.content.subject')(
                 <Select mode='tags' maxTagCount={200} notFoundContent={null} tokenSeparators={[',', ',']} />,
               )}
             </Form.Item>
@@ -145,7 +146,7 @@ export default class extends Page {
         <tr>
           <td>谓语</td>
           <td><Form.Item>
-            {getFieldDecorator('content.predicate')(
+            {getFieldDecorator('question.content.predicate')(
               <Select mode='tags' maxTagCount={200} notFoundContent={null} tokenSeparators={[',', ',']} />,
             )}
           </Form.Item></td>
@@ -153,7 +154,7 @@ export default class extends Page {
         <tr>
           <td>宾语</td>
           <td><Form.Item>
-            {getFieldDecorator('content.object')(
+            {getFieldDecorator('question.content.object')(
               <Select mode='tags' maxTagCount={200} notFoundContent={null} tokenSeparators={[',', ',']} />,
             )}
           </Form.Item></td>
@@ -168,7 +169,7 @@ export default class extends Page {
       <h1>选项信息(长难句)</h1>
       <Form>
         <Form.Item>
-          {getFieldDecorator('content.options')(
+          {getFieldDecorator('question.content.options')(
             <Checkbox.Group options={SentenceOption} />,
           )}
         </Form.Item>
@@ -181,7 +182,7 @@ export default class extends Page {
     return <Block flex>
       <Form>
         <Form.Item label='千行解析'>
-          {getFieldDecorator('qxContent', {
+          {getFieldDecorator('question.qxContent', {
           })(
             <Editor placeholder='输入内容' />,
           )}

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

@@ -4,7 +4,7 @@ import group from '../group';
 export default {
   path: '/subject/textbook/question/:id?',
   key: 'subject-textbook-question',
-  title: '新建机经题目',
+  title: '机经题目',
   needLogin: true,
   module,
   group,

+ 5 - 3
front/src/components/Editor/index.js

@@ -48,6 +48,7 @@ class Editor extends React.Component {
     super(props);
     this.quillRef = null;
     this.state = {};
+    this.loading = 0;
     this.modules = Object.assign({}, modules, props.modules);
     // console.log(this.modules);
     this.modules.toolbar.handlers.image = () => this.image();
@@ -109,11 +110,12 @@ class Editor extends React.Component {
           ref={el => {
             this.quillRef = el;
           }}
-          defaultValue={this.props.value}
           style={this.props.style}
           theme={this.props.theme || 'snow'}
-          onChange={(content, delta, source, editor) => this.props.onChange && this.props.onChange(content, delta, source, editor)}
-          // value={new Delta(this.props.value)}
+          onChange={(content, delta, source, editor) => {
+            if (this.props.onChange) this.props.onChange(content, delta, source, editor);
+          }}
+          value={this.props.value || ''}
           modules={this.modules}
           formats={this.formats}
           placeholder={this.props.placeholder}

+ 0 - 1
server/build.gradle

@@ -91,7 +91,6 @@ subprojects {
 
 //自定义环境 start
     def env = System.getProperty("ENV") ?: (System.getenv("ENV") ?: "dev")
-    println(env)
     sourceSets {
         main {
             resources {

+ 14 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/logic/ExerciseLogic.java

@@ -0,0 +1,14 @@
+package com.qxgmat.data.constants.enums.logic;
+
+public enum ExerciseLogic {
+    NO("no"), PLACE("place"), DIFFICULT("difficult"), ERROR("error");
+    public String key;
+    private ExerciseLogic(String key){
+        this.key = key;
+    }
+
+    public static ExerciseLogic ValueOf(String name){
+        if (name == null) return null;
+        return ExerciseLogic.valueOf(name.toUpperCase());
+    }
+}

+ 14 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/logic/SentenceLogic.java

@@ -0,0 +1,14 @@
+package com.qxgmat.data.constants.enums.logic;
+
+public enum SentenceLogic {
+    NO("no"), TRAIL("trail");
+    public String key;
+    private SentenceLogic(String key){
+        this.key = key;
+    }
+
+    public static SentenceLogic ValueOf(String name){
+        if (name == null) return null;
+        return SentenceLogic.valueOf(name.toUpperCase());
+    }
+}

+ 8 - 1
server/data/src/main/java/com/qxgmat/data/constants/enums/module/PaperModule.java

@@ -1,7 +1,14 @@
 package com.qxgmat.data.constants.enums.module;
 
 public enum PaperModule {
-    EXERCISE("exercise"), EXAMINATION("examination"), COLLECT("collect"), ERROR("error"), HOMEWORK_PREVIEW("homework_preview");
+    EXERCISE("exercise"),
+    EXAMINATION("examination"),
+    COLLECT("collect"),
+    ERROR("error"),
+    HOMEWORK_PREVIEW("homework_preview"),
+    TEXTBOOK("textbook"),
+    SENTENCE("sentence"),
+    ;
     public String key;
     private PaperModule(String key){
         this.key = key;

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

@@ -17,6 +17,12 @@ public class ExercisePaper implements Serializable {
     private String type;
 
     /**
+     * 组卷序号
+     */
+    @Column(name = "`no`")
+    private Integer no;
+
+    /**
      * 组卷逻辑:order ,place,difficult,error
      */
     @Column(name = "`logic`")
@@ -99,6 +105,24 @@ public class ExercisePaper implements Serializable {
     }
 
     /**
+     * 获取组卷序号
+     *
+     * @return no - 组卷序号
+     */
+    public Integer getNo() {
+        return no;
+    }
+
+    /**
+     * 设置组卷序号
+     *
+     * @param no 组卷序号
+     */
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    /**
      * 获取组卷逻辑:order ,place,difficult,error
      *
      * @return logic - 组卷逻辑:order ,place,difficult,error
@@ -250,6 +274,7 @@ public class ExercisePaper implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", type=").append(type);
+        sb.append(", no=").append(no);
         sb.append(", logic=").append(logic);
         sb.append(", logicExtend=").append(logicExtend);
         sb.append(", structId=").append(structId);
@@ -292,6 +317,16 @@ public class ExercisePaper implements Serializable {
         }
 
         /**
+         * 设置组卷序号
+         *
+         * @param no 组卷序号
+         */
+        public Builder no(Integer no) {
+            obj.setNo(no);
+            return this;
+        }
+
+        /**
          * 设置组卷逻辑:order ,place,difficult,error
          *
          * @param logic 组卷逻辑:order ,place,difficult,error

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

@@ -17,6 +17,18 @@ public class SentencePaper implements Serializable {
     private String title;
 
     /**
+     * 组卷序号
+     */
+    @Column(name = "`no`")
+    private Integer no;
+
+    /**
+     * 组卷逻辑:no,trail
+     */
+    @Column(name = "`logic`")
+    private String logic;
+
+    /**
      * 题目数量
      */
     @Column(name = "`question_number`")
@@ -69,6 +81,42 @@ public class SentencePaper implements Serializable {
     }
 
     /**
+     * 获取组卷序号
+     *
+     * @return no - 组卷序号
+     */
+    public Integer getNo() {
+        return no;
+    }
+
+    /**
+     * 设置组卷序号
+     *
+     * @param no 组卷序号
+     */
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    /**
+     * 获取组卷逻辑:no,trail
+     *
+     * @return logic - 组卷逻辑:no,trail
+     */
+    public String getLogic() {
+        return logic;
+    }
+
+    /**
+     * 设置组卷逻辑:no,trail
+     *
+     * @param logic 组卷逻辑:no,trail
+     */
+    public void setLogic(String logic) {
+        this.logic = logic;
+    }
+
+    /**
      * 获取题目数量
      *
      * @return question_number - 题目数量
@@ -130,6 +178,8 @@ public class SentencePaper implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", title=").append(title);
+        sb.append(", no=").append(no);
+        sb.append(", logic=").append(logic);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", status=").append(status);
@@ -167,6 +217,26 @@ public class SentencePaper implements Serializable {
         }
 
         /**
+         * 设置组卷序号
+         *
+         * @param no 组卷序号
+         */
+        public Builder no(Integer no) {
+            obj.setNo(no);
+            return this;
+        }
+
+        /**
+         * 设置组卷逻辑:no,trail
+         *
+         * @param logic 组卷逻辑:no,trail
+         */
+        public Builder logic(String logic) {
+            obj.setLogic(logic);
+            return this;
+        }
+
+        /**
          * 设置题目数量
          *
          * @param questionNumber 题目数量

+ 122 - 16
server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "user_paper")
@@ -43,8 +44,8 @@ public class UserPaper implements Serializable {
     /**
      * 练习次数
      */
-    @Column(name = "`number`")
-    private Integer number;
+    @Column(name = "`times`")
+    private Integer times;
 
     /**
      * 总时间
@@ -52,6 +53,24 @@ public class UserPaper implements Serializable {
     @Column(name = "`time`")
     private Integer time;
 
+    /**
+     * 用户做题时间-累计
+     */
+    @Column(name = "`user_time`")
+    private Integer userTime;
+
+    /**
+     * 正确总题数-累计
+     */
+    @Column(name = "`correct_number`")
+    private Integer correctNumber;
+
+    /**
+     * 删除时间
+     */
+    @Column(name = "`delete_time`")
+    private Date deleteTime;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -161,19 +180,19 @@ public class UserPaper implements Serializable {
     /**
      * 获取练习次数
      *
-     * @return number - 练习次数
+     * @return times - 练习次数
      */
-    public Integer getNumber() {
-        return number;
+    public Integer getTimes() {
+        return times;
     }
 
     /**
      * 设置练习次数
      *
-     * @param number 练习次数
+     * @param times 练习次数
      */
-    public void setNumber(Integer number) {
-        this.number = number;
+    public void setTimes(Integer times) {
+        this.times = times;
     }
 
     /**
@@ -194,6 +213,60 @@ public class UserPaper implements Serializable {
         this.time = time;
     }
 
+    /**
+     * 获取用户做题时间-累计
+     *
+     * @return user_time - 用户做题时间-累计
+     */
+    public Integer getUserTime() {
+        return userTime;
+    }
+
+    /**
+     * 设置用户做题时间-累计
+     *
+     * @param userTime 用户做题时间-累计
+     */
+    public void setUserTime(Integer userTime) {
+        this.userTime = userTime;
+    }
+
+    /**
+     * 获取正确总题数-累计
+     *
+     * @return correct_number - 正确总题数-累计
+     */
+    public Integer getCorrectNumber() {
+        return correctNumber;
+    }
+
+    /**
+     * 设置正确总题数-累计
+     *
+     * @param correctNumber 正确总题数-累计
+     */
+    public void setCorrectNumber(Integer correctNumber) {
+        this.correctNumber = correctNumber;
+    }
+
+    /**
+     * 获取删除时间
+     *
+     * @return delete_time - 删除时间
+     */
+    public Date getDeleteTime() {
+        return deleteTime;
+    }
+
+    /**
+     * 设置删除时间
+     *
+     * @param deleteTime 删除时间
+     */
+    public void setDeleteTime(Date deleteTime) {
+        this.deleteTime = deleteTime;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -206,8 +279,11 @@ public class UserPaper implements Serializable {
         sb.append(", module=").append(module);
         sb.append(", moduleId=").append(moduleId);
         sb.append(", questionNoIds=").append(questionNoIds);
-        sb.append(", number=").append(number);
+        sb.append(", times=").append(times);
         sb.append(", time=").append(time);
+        sb.append(", userTime=").append(userTime);
+        sb.append(", correctNumber=").append(correctNumber);
+        sb.append(", deleteTime=").append(deleteTime);
         sb.append("]");
         return sb.toString();
     }
@@ -282,22 +358,52 @@ public class UserPaper implements Serializable {
         }
 
         /**
+         * 设置总时间
+         *
+         * @param time 总时间
+         */
+        public Builder time(Integer time) {
+            obj.setTime(time);
+            return this;
+        }
+
+        /**
          * 设置练习次数
          *
-         * @param number 练习次数
+         * @param times 练习次数
          */
-        public Builder number(Integer number) {
-            obj.setNumber(number);
+        public Builder times(Integer times) {
+            obj.setTimes(times);
             return this;
         }
 
         /**
-         * 设置总时间
+         * 设置用户做题时间-累计
          *
-         * @param time 总时间
+         * @param userTime 用户做题时间-累计
          */
-        public Builder time(Integer time) {
-            obj.setTime(time);
+        public Builder userTime(Integer userTime) {
+            obj.setUserTime(userTime);
+            return this;
+        }
+
+        /**
+         * 设置正确总题数-累计
+         *
+         * @param correctNumber 正确总题数-累计
+         */
+        public Builder correctNumber(Integer correctNumber) {
+            obj.setCorrectNumber(correctNumber);
+            return this;
+        }
+
+        /**
+         * 设置删除时间
+         *
+         * @param deleteTime 删除时间
+         */
+        public Builder deleteTime(Date deleteTime) {
+            obj.setDeleteTime(deleteTime);
             return this;
         }
 

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

@@ -52,12 +52,6 @@ public class UserQuestion implements Serializable {
     private Date createTime;
 
     /**
-     * 系统答案:json
-     */
-    @Column(name = "`answer`")
-    private JSONObject answer;
-
-    /**
      * 用户答案:json
      */
     @Column(name = "`user_answer`")
@@ -208,24 +202,6 @@ public class UserQuestion implements Serializable {
     }
 
     /**
-     * 获取系统答案:json
-     *
-     * @return answer - 系统答案:json
-     */
-    public JSONObject getAnswer() {
-        return answer;
-    }
-
-    /**
-     * 设置系统答案:json
-     *
-     * @param answer 系统答案:json
-     */
-    public void setAnswer(JSONObject answer) {
-        this.answer = answer;
-    }
-
-    /**
      * 获取用户答案:json
      *
      * @return user_answer - 用户答案:json
@@ -275,7 +251,6 @@ public class UserQuestion implements Serializable {
         sb.append(", time=").append(time);
         sb.append(", userTime=").append(userTime);
         sb.append(", createTime=").append(createTime);
-        sb.append(", answer=").append(answer);
         sb.append(", userAnswer=").append(userAnswer);
         sb.append(", isCorrect=").append(isCorrect);
         sb.append("]");
@@ -370,16 +345,6 @@ public class UserQuestion implements Serializable {
         }
 
         /**
-         * 设置系统答案:json
-         *
-         * @param answer 系统答案:json
-         */
-        public Builder answer(JSONObject answer) {
-            obj.setAnswer(answer);
-            return this;
-        }
-
-        /**
          * 设置用户答案:json
          *
          * @param userAnswer 用户答案:json

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

@@ -7,6 +7,7 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="type" jdbcType="VARCHAR" property="type" />
+    <result column="no" jdbcType="INTEGER" property="no" />
     <result column="logic" jdbcType="VARCHAR" property="logic" />
     <result column="logic_extend" jdbcType="VARCHAR" property="logicExtend" />
     <result column="struct_id" jdbcType="INTEGER" property="structId" />
@@ -20,7 +21,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `type`, `logic`, `logic_extend`, `struct_id`, `struct_parent`, `title`, `question_number`, 
-    `question_no_ids`, `status`
+    `id`, `type`, `no`, `logic`, `logic_extend`, `struct_id`, `struct_parent`, `title`, 
+    `question_number`, `question_no_ids`, `status`
   </sql>
 </mapper>

+ 3 - 1
server/data/src/main/java/com/qxgmat/data/dao/mapping/SentencePaperMapper.xml

@@ -7,6 +7,8 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="no" jdbcType="INTEGER" property="no" />
+    <result column="logic" jdbcType="VARCHAR" property="logic" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="status" jdbcType="INTEGER" property="status" />
@@ -15,6 +17,6 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `question_number`, `question_no_ids`, `status`
+    `id`, `title`, `no`, `logic`, `question_number`, `question_no_ids`, `status`
   </sql>
 </mapper>

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

@@ -11,13 +11,17 @@
     <result column="module" jdbcType="VARCHAR" property="module" />
     <result column="module_id" jdbcType="INTEGER" property="moduleId" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
-    <result column="number" jdbcType="INTEGER" property="number" />
+    <result column="times" jdbcType="INTEGER" property="times" />
     <result column="time" jdbcType="INTEGER" property="time" />
+    <result column="user_time" jdbcType="INTEGER" property="userTime" />
+    <result column="correct_number" jdbcType="INTEGER" property="correctNumber" />
+    <result column="delete_time" jdbcType="TIMESTAMP" property="deleteTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `title`, `module`, `module_id`, `question_no_ids`, `number`, `time`
+    `id`, `user_id`, `title`, `module`, `module_id`, `question_no_ids`, `times`, `time`, 
+    `user_time`, `correct_number`, `delete_time`
   </sql>
 </mapper>

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

@@ -13,7 +13,6 @@
     <result column="time" jdbcType="INTEGER" property="time" />
     <result column="user_time" jdbcType="INTEGER" property="userTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
-    <result column="answer" jdbcType="VARCHAR" property="answer" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="user_answer" jdbcType="VARCHAR" property="userAnswer" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="is_correct" jdbcType="INTEGER" property="isCorrect" />
   </resultMap>
@@ -22,6 +21,6 @@
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `report_id`, `question_id`, `question_no_id`, `time`, `user_time`, 
-    `create_time`, `answer`, `user_answer`, `is_correct`
+    `create_time`, `user_answer`, `is_correct`
   </sql>
 </mapper>

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

@@ -0,0 +1,36 @@
+package com.qxgmat.data.inline;
+
+public class PaperStat {
+    // 总做题时间
+    private Integer totalTime;
+
+    // 总做题数
+    private Integer totalNumber;
+
+    // 总正确次数
+    private Integer totalCorrect;
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+    public Integer getTotalNumber() {
+        return totalNumber;
+    }
+
+    public void setTotalNumber(Integer totalNumber) {
+        this.totalNumber = totalNumber;
+    }
+
+    public Integer getTotalCorrect() {
+        return totalCorrect;
+    }
+
+    public void setTotalCorrect(Integer totalCorrect) {
+        this.totalCorrect = totalCorrect;
+    }
+}

+ 14 - 0
server/data/src/main/java/com/qxgmat/data/relation/ExercisePaperRelationMapper.java

@@ -0,0 +1,14 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.ExercisePaper;
+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 ExercisePaperRelationMapper {
+    List<ExercisePaper> groupPlace();
+}

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

@@ -18,14 +18,24 @@ public interface UserPaperRelationMapper {
             @Param("startTime") String startTime,
             @Param("endTime") String endTime
     );
+
     List<UserPaper> listHomeworkPreview(
             @Param("category") Number category,
             @Param("userId") Number userId,
             @Param("endTime") String endTime,
             @Param("finish") Boolean finish
     );
+
     List<UserPaper> listHomeworkPreviewGroupTop(
             @Param("userId") Number userId,
             @Param("top") Number top
     );
+
+    List<UserPaper> listExercisePaper(
+            @Param("structId") Number structId,
+            @Param("userId") Number userId,
+            @Param("logic") String logic,
+            @Param("logicExtend") String logicExtend,
+            @Param("times") Integer times
+    );
 }

+ 38 - 0
server/data/src/main/java/com/qxgmat/data/relation/entity/UserExercisePaperRelation.java

@@ -0,0 +1,38 @@
+package com.qxgmat.data.relation.entity;
+
+import com.qxgmat.data.dao.entity.*;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public class UserExercisePaperRelation extends UserPaper {
+    private ExercisePaper paper;
+
+    private UserReport report;
+
+    private User user;
+
+    public User getUser() {
+        return user;
+    }
+
+    public void setUser(User user) {
+        this.user = user;
+    }
+
+    public UserReport getReport() {
+        return report;
+    }
+
+    public void setReport(UserReport report) {
+        this.report = report;
+    }
+
+    public ExercisePaper getPaper() {
+        return paper;
+    }
+
+    public void setPaper(ExercisePaper paper) {
+        this.paper = paper;
+    }
+}

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

@@ -0,0 +1,25 @@
+<?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.ExercisePaperRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.ExercisePaper">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    ep.`id`
+  </sql>
+
+  <!--获取考点分组所有考点信息-->
+  <select id="groupPlace" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `exercise_paper` ep
+    where ep.`logic` = "place" and ep.`status` = 1
+    group by ep.`logic_extend`
+  </select>
+</mapper>

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

@@ -93,4 +93,34 @@
         and up.`module` = "homework_preview"
         and up1.create_time &gt; up.create_time) &lt; ${top}
   </select>
+
+  <!--
+    用户练习-练习册列表: 用户端
+  -->
+  <select id="listExercisePaper" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `user_paper` up
+    left join `exercise_paper` hp on hp.`id` = up.`module_id` and ep.`status` = 1
+    and up.`module` = "homework_preview"
+    <if test="category != null">
+      and hp.`category` = #{category,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and hp.`endTime` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+    where
+    hp.`id` != null
+    <if test="userId != null">
+      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+    </if>
+    <if test="finish != null">
+      <if test="finish == true">
+        and up.`number` > 1
+      </if>
+      <if test="finish == false">
+        and up.`number` = 0
+      </if>>
+    </if>
+  </select>
 </mapper>

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

@@ -47,9 +47,10 @@ public class QuestionController {
     @ApiOperation(value = "添加题目", httpMethod = "POST")
     public Response<Question> add(@RequestBody @Validated QuestionDto dto, HttpServletRequest request) {
         Question entity = Transform.dtoToEntity(dto);
-        // 添加
-//        entity.setModule(QuestionModule.EXERCISE.key);
-        entity = exercisePaperService.addQuestion(entity);
+        entity = questionService.add(entity);
+        // 更新编号绑定
+        questionNoService.bindQuestion(dto.getQuestionNoIds(), entity.getId());
+
         managerLogService.log(request);
         return ResponseHelp.success(entity);
     }
@@ -58,7 +59,10 @@ public class QuestionController {
     @RequestMapping(value = "/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "修改题目", httpMethod = "PUT")
     public Response<Boolean> edit(@RequestBody @Validated QuestionDto dto, HttpServletRequest request) {
+        Question entity = Transform.dtoToEntity(dto);
+        entity = questionService.edit(entity);
         // 更新编号绑定
+        questionNoService.bindQuestion(dto.getQuestionNoIds(), entity.getId());
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }
@@ -87,9 +91,8 @@ public class QuestionController {
     @ApiOperation(value = "添加编号", httpMethod = "POST")
     public Response<QuestionNo> addNo(@RequestBody @Validated QuestionNoDto dto, HttpServletRequest request) {
         QuestionNo entity = Transform.dtoToEntity(dto);
-        // 添加
-//        entity.setModule(QuestionModule.EXERCISE.key);
         entity = questionNoService.add(entity);
+
         managerLogService.log(request);
         return ResponseHelp.success(entity);
     }
@@ -97,11 +100,7 @@ public class QuestionController {
     @RequestMapping(value = "/delete/no", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除题目编号", httpMethod = "DELETE")
     public Response<Boolean> delete(int id, HttpServletRequest request) {
-
-//        Question entity = Transform.dtoToEntity(dto);
-        // 添加
-//        entity.setModule(QuestionModule.EXERCISE.key);
-//        entity = exercisePaperService.editQuestion(entity);
+        questionNoService.delete(id);
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }
@@ -134,7 +133,7 @@ public class QuestionController {
     @RequestMapping(value = "/search/no", method = RequestMethod.POST)
     @ApiOperation(value = "搜索题目编号列表:题目编号搜索", httpMethod = "POST")
     public Response<PageMessage<QuestionNoExtendDto>> searchNo(@RequestBody @Validated QuestionNoSearchDto dto, HttpServletRequest request) {
-        PageResult<QuestionNoRelation> p = questionNoService.searchNo(dto.getPage(), dto.getSize(), dto.getNo());
+        PageResult<QuestionNoRelation> p = questionNoService.searchNo(dto.getPage(), dto.getSize(), dto.getNo(), dto.getModule());
         List<QuestionNoExtendDto> pr = Transform.convert(p, QuestionNoExtendDto.class);
 
         return ResponseHelp.success(pr, dto.getPage(), dto.getSize(), p.getTotal());

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

@@ -73,6 +73,7 @@ public class SentenceController {
     @RequestMapping(value = "/article/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除长难句文章", httpMethod = "DELETE")
     public Response<Boolean> deleteArticle(@RequestParam int id, HttpServletRequest request) {
+        sentenceArticleService.delete(id);
         managerLogService.log(request);
         return ResponseHelp.success(sentenceArticleService.delete(id));
     }

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

@@ -3,26 +3,31 @@ package com.qxgmat.controller.api;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
-import com.qxgmat.data.dao.entity.ExercisePaper;
-import com.qxgmat.data.dao.entity.User;
-import com.qxgmat.data.dao.entity.UserClass;
+import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
+import com.qxgmat.data.constants.enums.module.PayModule;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.entity.UserExercisePaperRelation;
 import com.qxgmat.data.relation.entity.UserHomeworkPreviewRelation;
+import com.qxgmat.dto.extend.UserExercisePaperExtendDto;
 import com.qxgmat.dto.extend.UserHomeworkPreviewExtendDto;
+import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.UserClassDetailDto;
+import com.qxgmat.dto.response.UserExerciseGroupDto;
+import com.qxgmat.dto.response.UserQuestionDetailDto;
 import com.qxgmat.help.ShiroHelp;
+import com.qxgmat.service.ExercisePaperService;
 import com.qxgmat.service.HomeworkPreviewService;
 import com.qxgmat.service.UserPaperService;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RequestMethod;
-import org.springframework.web.bind.annotation.RequestParam;
-import org.springframework.web.bind.annotation.RestController;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpSession;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 
@@ -50,19 +55,38 @@ public class QuestionController {
     private HomeworkPreviewService homeworkPreviewService;
 
     @Autowired
+    private ExercisePaperService exercisePaperService;
+
+    @Autowired
     private UserClassService userClassService;
 
+    @Autowired
+    private UserPayService userPayService;
+
     @RequestMapping(value = "/class/process", method = RequestMethod.GET)
     @ApiOperation(value = "获取课程进度", notes = "获取所有课程及状态进度", httpMethod = "GET")
     public Response<List<UserClassDetailDto>> classProcess()  {
         User user = (User) shiroHelp.getLoginUser();
         List<UserClass> userClassList = userClassService.getByUser(user.getId());
+        List<UserClassDetailDto> dtos = Transform.convert(userClassList, UserClassDetailDto.class);
 
         // 获取每个科目的最后3次作业
         Map<Object, Collection<UserHomeworkPreviewRelation>> previewMap = homeworkPreviewService.groupByCategory(user.getId(), 3);
+        Transform.combine(dtos, previewMap, UserClassDetailDto.class, "category", "previews", UserHomeworkPreviewExtendDto.class);
+
+        // 获取课程状态
+        List<UserPay> pays = userPayService.listUnUse(user.getId(), PayModule.CLASS);
+        Collection ids = Transform.getIds(userClassList, UserClass.class, "category");
+        for(UserPay pay : pays){
+            Integer category = Integer.valueOf(pay.getModuleExtend());
+            if (!ids.contains(category)){
+                UserClassDetailDto dto = new UserClassDetailDto();
+                dto.setCategory(category);
+                dto.setPayed(true);
+                dtos.add(dto);
+            }
+        }
 
-        List<UserClassDetailDto> dtos = Transform.convert(userClassList, UserClassDetailDto.class);
-        Transform.combine(dtos, previewMap, UserClassDetailDto.class, "moduleId", "previews", UserHomeworkPreviewExtendDto.class);
         return ResponseHelp.success(dtos);
     }
 
@@ -80,29 +104,63 @@ public class QuestionController {
 
         List<UserHomeworkPreviewExtendDto> pr = Transform.convert(p, UserHomeworkPreviewExtendDto.class);
 
+        // 获取试卷统计信息
+        Map map = Transform.getMap(p, UserHomeworkPreviewRelation.class, "id", "preview");
+        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
+        for(Object value : map.keySet()){
+            Integer key = (Integer) value;
+            HomeworkPreview preview = (HomeworkPreview) map.get(key);
+            questionNoIdsMap.put(key, preview.getQuestionNoIds());
+        }
+        Map statMap = questionNoService.statPaperMap(questionNoIdsMap);
+        Transform.combine(pr, statMap, UserHomeworkPreviewExtendDto.class, "id", "stat");
+
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
     @RequestMapping(value = "/exercise/process", method = RequestMethod.GET)
     @ApiOperation(value = "练习进度", httpMethod = "GET")
-    public Response<PageMessage<ExercisePaper>> exerciseProcess(
-            @RequestParam(required = false, defaultValue = "1") int page,
-            @RequestParam(required = false, defaultValue = "100") int size,
+    public Response<List<UserExerciseGroupDto>> exerciseProcess(
+            @RequestParam(required = true) Integer structId, // 第三层,查询第4层,以及第三层汇总
             HttpSession session) {
-        Page<ExercisePaper> p=null;
+        Page<UserExerciseGroupDto> p=null;
 
-        return ResponseHelp.success(p, page, size, p.getTotal());
+        return ResponseHelp.success(p);
+    }
+
+    @RequestMapping(value = "/exercise/place", method = RequestMethod.GET)
+    @ApiOperation(value = "练习组卷考点分组条件", httpMethod = "GET")
+    public Response<List<String>> exercisePlace(HttpSession session) {
+        return ResponseHelp.success(exercisePaperService.groupPlace());
     }
 
     @RequestMapping(value = "/exercise/paper", method = RequestMethod.GET)
     @ApiOperation(value = "练习组卷列表", httpMethod = "GET")
-    public Response<PageMessage<ExercisePaper>> listExercisePaper(
+    public Response<PageMessage<UserExercisePaperExtendDto>> listExercisePaper(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = true) Integer structId,
+            @RequestParam(required = true) String logic,
+            @RequestParam(required = false, name = "logic_extend") String logicExtend,
+            @RequestParam(required = false)  Integer times,
             HttpSession session) {
-        Page<ExercisePaper> p = null;
+        User user = (User) shiroHelp.getLoginUser();
+        PageResult<UserExercisePaperRelation> p = exercisePaperService.list(page, size, structId, user.getId(), ExerciseLogic.ValueOf(logic), logicExtend, times);
 
-        return ResponseHelp.success(p, page, size, p.getTotal());
+        List<UserExercisePaperExtendDto> pr = Transform.convert(p, UserExercisePaperExtendDto.class);
+
+        // 获取试卷统计信息
+        Map map = Transform.getMap(p, UserExercisePaperRelation.class, "id", "paper");
+        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
+        for(Object value : map.keySet()){
+            Integer key = (Integer) value;
+            ExercisePaper paper = (ExercisePaper) map.get(key);
+            questionNoIdsMap.put(key, paper.getQuestionNoIds());
+        }
+        Map statMap = questionNoService.statPaperMap(questionNoIdsMap);
+        Transform.combine(pr, statMap, UserHomeworkPreviewExtendDto.class, "id", "stat");
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
     @RequestMapping(value = "/examination/process", method = RequestMethod.GET)
@@ -129,45 +187,46 @@ public class QuestionController {
 
     @RequestMapping(value = "/detail", method = RequestMethod.GET)
     @ApiOperation(value = "获取题目详情", notes = "获取题目详情", httpMethod = "GET")
-    public Response<User> detail(
-            @RequestParam(required = false) String questionNoId
+    public Response<UserQuestionDetailDto> detail(
+            @RequestParam(required = false) String userQuestionId
     )  {
         User user = (User) shiroHelp.getLoginUser();
         return ResponseHelp.success(null);
     }
 
-    @RequestMapping(value = "/start", method = RequestMethod.POST)
-    @ApiOperation(value = "开始考试", notes = "提交考试设置", httpMethod = "POST")
-    public Response<User> start(
-            @RequestParam(required = false) String paperId
-    )  {
+    @RequestMapping(value = "/exercise/start", method = RequestMethod.POST)
+    @ApiOperation(value = "开始: 练习", notes = "提交考试设置", httpMethod = "POST")
+    public Response<Boolean> start(@RequestBody @Validated ExerciseStartDto dto)  {
+        User user = (User) shiroHelp.getLoginUser();
+
+        return ResponseHelp.success(null);
+    }
+
+    @RequestMapping(value = "/preview/start", method = RequestMethod.POST)
+    @ApiOperation(value = "开始: 预习作业", notes = "提交考试设置", httpMethod = "POST")
+    public Response<User> start(@RequestBody @Validated PreviewStartDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         return ResponseHelp.success(null);
     }
 
     @RequestMapping(value = "/next", method = RequestMethod.POST)
     @ApiOperation(value = "获取下一题", notes = "获取下一题", httpMethod = "POST")
-    public Response<User> next(
-            @RequestParam(required = false) String reportId
-    )  {
+    public Response<User> next(@RequestBody @Validated QuestionNextDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         return ResponseHelp.success(null);
     }
 
     @RequestMapping(value = "/submit", method = RequestMethod.POST)
     @ApiOperation(value = "提交题目答案", notes = "提交题目", httpMethod = "POST")
-    public Response<User> submit(
-            @RequestParam(required = false) String questionNoId
-    )  {
+    public Response<User> submit(@RequestBody @Validated QuestionSubmitDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
+
         return ResponseHelp.success(null);
     }
 
     @RequestMapping(value = "/finish", method = RequestMethod.POST)
     @ApiOperation(value = "完成考试", notes = "完成考试", httpMethod = "POST")
-    public Response<User> finish(
-            @RequestParam(required = false) String paperId
-    )  {
+    public Response<User> finish(@RequestBody @Validated QuestionFinishDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         return ResponseHelp.success(null);
     }

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

@@ -4,11 +4,15 @@ import com.alibaba.fastjson.JSONObject;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
+import com.nuliji.tools.exception.AuthException;
 import com.qxgmat.data.constants.enums.SettingKey;
+import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.dto.request.SentenceStartDto;
 import com.qxgmat.dto.request.UserSentenceCodeDto;
 import com.qxgmat.dto.request.UserSentenceProcessDto;
 import com.qxgmat.dto.response.UserSentenceArticleDto;
+import com.qxgmat.dto.response.UserSentencePaperDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.SentencePaperService;
 import com.qxgmat.service.UserPaperService;
@@ -87,6 +91,7 @@ public class SentenceController
     public Response<Boolean> active(@RequestBody @Validated UserSentenceCodeDto dto) {
         UserSentenceProcess entity = Transform.dtoToEntity(dto);
         User user = (User) shiroHelp.getLoginUser();
+        if (user == null) throw new AuthException("需要登录");
 
         if (sentenceCodeService.isActive(user.getId()) == null){
             sentenceCodeService.active(user.getId(), dto.getCode());
@@ -101,9 +106,9 @@ public class SentenceController
             @RequestParam(required = true) Integer chapter,
             HttpSession session) {
         User user = (User) shiroHelp.getLoginUser();
-        // 查询用户code
 
-        if (sentenceCodeService.isActive(user.getId()) != null){
+        // 查询用户code
+        if (user != null && sentenceCodeService.isActive(user.getId()) != null){
             List<SentenceArticle> p = sentenceArticleService.listByChapter(chapter);
             List<UserSentenceArticleDto> pr = Transform.convert(p, UserSentenceArticleDto.class);
 
@@ -116,7 +121,12 @@ public class SentenceController
             List<SentenceArticle> p = sentenceArticleService.listByTrail();
             List<UserSentenceArticleDto> pr = Transform.convert(p, UserSentenceArticleDto.class);
 
-            List<UserSentenceProcess> processList = userSentenceProcessService.listAllByTrail(user.getId());
+            if (user != null){
+                // 查询文章进度
+                List<UserSentenceProcess> processList = userSentenceProcessService.listAllByTrail(user.getId());
+                Map process = Transform.getMap(processList,UserSentenceProcess.class, "part", "process");
+                Transform.combine(pr, process, UserSentenceArticleDto.class, "part", "process");
+            }
 
             return ResponseHelp.success(pr);
         }
@@ -136,16 +146,21 @@ public class SentenceController
 
     @RequestMapping(value = "/paper/list", method = RequestMethod.GET)
     @ApiOperation(value = "长难句组卷列表", httpMethod = "GET")
-    public Response<List<UserSentenceArticleDto>> listPaper(
+    public Response<List<UserSentencePaperDto>> listPaper(
             HttpSession session) {
         User user = (User) shiroHelp.getLoginUser();
         // 查询用户code
-        if (sentenceCodeService.isActive(user.getId()) != null){
+        if (user != null && sentenceCodeService.isActive(user.getId()) != null){
+            List<SentencePaper> p = sentencePaperService.listByLogic(SentenceLogic.NO);
+            List<UserSentencePaperDto> pr = Transform.convert(p, UserSentencePaperDto.class);
 
+            return ResponseHelp.success(pr);
         } else {
+            List<SentencePaper> p = sentencePaperService.listByLogic(SentenceLogic.TRAIL);
+            List<UserSentencePaperDto> pr = Transform.convert(p, UserSentencePaperDto.class);
 
+            return ResponseHelp.success(pr);
         }
-        return ResponseHelp.success(null);
     }
 
     @RequestMapping(value = "/question/detail", method = RequestMethod.GET)
@@ -159,10 +174,10 @@ public class SentenceController
 
     @RequestMapping(value = "/paper/start", method = RequestMethod.POST)
     @ApiOperation(value = "开始做题", notes = "提交考试设置", httpMethod = "POST")
-    public Response<User> start(
-            @RequestParam(required = false) String paperId
-    )  {
+    public Response<User> start(@RequestBody @Validated SentenceStartDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
+
+
         return ResponseHelp.success(null);
     }
 

+ 13 - 3
server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/QuestionDto.java

@@ -16,13 +16,15 @@ public class QuestionDto {
 
     private String stem;
 
-    @NotEmpty(message = "题型不能为空!")
+    private String description;
+
+//    @NotEmpty(message = "题型不能为空!")
     private String type;
 
-    @NotEmpty(message = "考点不能为空!")
+//    @NotEmpty(message = "考点不能为空!")
     private String place;
 
-    @NotEmpty(message = "难度不能为空!")
+//    @NotEmpty(message = "难度不能为空!")
     private String difficult;
 
     private Integer[] questionNoIds;
@@ -132,4 +134,12 @@ public class QuestionDto {
     public void setStem(String stem) {
         this.stem = stem;
     }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
 }

+ 65 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/QuestionDetailExtendDto.java

@@ -0,0 +1,65 @@
+package com.qxgmat.dto.extend;
+
+import com.alibaba.fastjson.JSONObject;
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.Question;
+
+@Dto(entity = Question.class)
+public class QuestionDetailExtendDto {
+
+    private Integer id;
+
+    private String stem;
+
+    private String type;
+    private String difficult;
+    private String place;
+
+    private String officialContent;
+
+    private String qxContent;
+
+    private JSONObject content;
+
+    private Integer[] associationContent;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getStem() {
+        return stem;
+    }
+
+    public void setStem(String stem) {
+        this.stem = stem;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDifficult() {
+        return difficult;
+    }
+
+    public void setDifficult(String difficult) {
+        this.difficult = difficult;
+    }
+
+    public String getPlace() {
+        return place;
+    }
+
+    public void setPlace(String place) {
+        this.place = place;
+    }
+}

+ 59 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserExercisePaperExtendDto.java

@@ -0,0 +1,59 @@
+package com.qxgmat.dto.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserPaper;
+import com.qxgmat.data.inline.PaperStat;
+
+@Dto(entity = UserPaper.class)
+public class UserExercisePaperExtendDto {
+
+    private Integer id;
+
+    private UserReportExtendDto report;
+
+    private Integer times;
+
+    private String title;
+
+    private PaperStat stat;
+
+    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;
+    }
+
+    public UserReportExtendDto getReport() {
+        return report;
+    }
+
+    public void setReport(UserReportExtendDto report) {
+        this.report = report;
+    }
+
+    public PaperStat getStat() {
+        return stat;
+    }
+
+    public void setStat(PaperStat stat) {
+        this.stat = stat;
+    }
+
+    public Integer getTimes() {
+        return times;
+    }
+
+    public void setTimes(Integer times) {
+        this.times = times;
+    }
+}

+ 20 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserHomeworkPreviewExtendDto.java

@@ -2,6 +2,7 @@ package com.qxgmat.dto.extend;
 
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserPaper;
+import com.qxgmat.data.inline.PaperStat;
 
 @Dto(entity = UserPaper.class)
 public class UserHomeworkPreviewExtendDto {
@@ -10,10 +11,12 @@ public class UserHomeworkPreviewExtendDto {
 
     private UserReportExtendDto report;
 
-    private Integer number;
+    private Integer times;
 
     private String title;
 
+    private PaperStat stat;
+
     public Integer getId() {
         return id;
     }
@@ -22,14 +25,6 @@ public class UserHomeworkPreviewExtendDto {
         this.id = id;
     }
 
-    public Integer getNumber() {
-        return number;
-    }
-
-    public void setNumber(Integer number) {
-        this.number = number;
-    }
-
     public String getTitle() {
         return title;
     }
@@ -45,4 +40,20 @@ public class UserHomeworkPreviewExtendDto {
     public void setReport(UserReportExtendDto report) {
         this.report = report;
     }
+
+    public PaperStat getStat() {
+        return stat;
+    }
+
+    public void setStat(PaperStat stat) {
+        this.stat = stat;
+    }
+
+    public Integer getTimes() {
+        return times;
+    }
+
+    public void setTimes(Integer times) {
+        this.times = times;
+    }
 }

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/ExaminationStartDto.java

@@ -0,0 +1,13 @@
+package com.qxgmat.dto.request;
+
+public class ExaminationStartDto {
+    private Integer paperId;
+
+    public Integer getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+}

+ 23 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/ExerciseStartDto.java

@@ -0,0 +1,23 @@
+package com.qxgmat.dto.request;
+
+public class ExerciseStartDto {
+    private Boolean disorder;
+
+    private Integer paperId;
+
+    public Boolean getDisorder() {
+        return disorder;
+    }
+
+    public void setDisorder(Boolean disorder) {
+        this.disorder = disorder;
+    }
+
+    public Integer getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+}

+ 23 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/PreviewStartDto.java

@@ -0,0 +1,23 @@
+package com.qxgmat.dto.request;
+
+public class PreviewStartDto {
+    private Boolean disorder;
+
+    private Integer previewId;
+
+    public Boolean getDisorder() {
+        return disorder;
+    }
+
+    public void setDisorder(Boolean disorder) {
+        this.disorder = disorder;
+    }
+
+    public Integer getPreviewId() {
+        return previewId;
+    }
+
+    public void setPreviewId(Integer previewId) {
+        this.previewId = previewId;
+    }
+}

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionFinishDto.java

@@ -0,0 +1,13 @@
+package com.qxgmat.dto.request;
+
+public class QuestionFinishDto {
+    private Integer userPaperId;
+
+    public Integer getUserPaperId() {
+        return userPaperId;
+    }
+
+    public void setUserPaperId(Integer userPaperId) {
+        this.userPaperId = userPaperId;
+    }
+}

+ 15 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionNextDto.java

@@ -0,0 +1,15 @@
+package com.qxgmat.dto.request;
+
+import com.alibaba.fastjson.JSONObject;
+
+public class QuestionNextDto {
+    private Integer userPaperId;
+
+    public Integer getUserPaperId() {
+        return userPaperId;
+    }
+
+    public void setUserPaperId(Integer userPaperId) {
+        this.userPaperId = userPaperId;
+    }
+}

+ 25 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/QuestionSubmitDto.java

@@ -0,0 +1,25 @@
+package com.qxgmat.dto.request;
+
+import com.alibaba.fastjson.JSONObject;
+
+public class QuestionSubmitDto {
+    private Integer userQuestionId;
+
+    private JSONObject answer;
+
+    public Integer getUserQuestionId() {
+        return userQuestionId;
+    }
+
+    public void setUserQuestionId(Integer userQuestionId) {
+        this.userQuestionId = userQuestionId;
+    }
+
+    public JSONObject getAnswer() {
+        return answer;
+    }
+
+    public void setAnswer(JSONObject answer) {
+        this.answer = answer;
+    }
+}

+ 5 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/SentenceStartDto.java

@@ -0,0 +1,5 @@
+package com.qxgmat.dto.request;
+
+public class SentenceStartDto {
+
+}

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExerciseGroupDto.java

@@ -0,0 +1,13 @@
+package com.qxgmat.dto.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserClass;
+import com.qxgmat.dto.extend.UserHomeworkPreviewExtendDto;
+
+import java.util.Date;
+import java.util.List;
+
+public class UserExerciseGroupDto {
+    private Integer structId;
+
+}

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

@@ -0,0 +1,24 @@
+package com.qxgmat.dto.response;
+
+import com.alibaba.fastjson.JSONObject;
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserQuestion;
+import com.qxgmat.dto.extend.QuestionDetailExtendDto;
+import com.qxgmat.dto.extend.QuestionNoExtendDto;
+
+import java.util.List;
+
+@Dto(entity = UserQuestion.class)
+public class UserQuestionDetailDto {
+    private Integer id;
+
+    private Integer questionId;
+
+    private Integer questionNoId;
+
+    private List<QuestionNoExtendDto> questionNos;
+
+    private JSONObject answer;
+
+    private QuestionDetailExtendDto question;
+}

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

@@ -0,0 +1,10 @@
+package com.qxgmat.dto.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.SentencePaper;
+import com.qxgmat.data.inline.PaperStat;
+
+@Dto(entity = SentencePaper.class)
+public class UserSentencePaperDto {
+    private PaperStat stat;
+}

+ 4 - 14
server/gateway-api/src/main/java/com/qxgmat/service/ExaminationPaperService.java

@@ -8,6 +8,7 @@ import com.nuliji.tools.exception.SystemException;
 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;
@@ -28,21 +29,10 @@ public class ExaminationPaperService extends AbstractService {
     @Resource
     private QuestionService questionService;
 
-    @Transactional
-    public Question addQuestion(Question question){
-        question = questionService.add(question);
-//        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-//        entity.setQuestionId(question.getId());
-//        return add(entity);
-        return question;
-    }
+    // 完成一次
+    public boolean finished(UserPaper userPaper){
 
-    @Transactional
-    public Question editQuestion(Question question){
-        question = questionService.edit(question);
-//        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-//        return edit(entity);
-        return question;
+        return true;
     }
 
     public ExaminationPaper add(ExaminationPaper paper){

+ 77 - 14
server/gateway-api/src/main/java/com/qxgmat/service/ExercisePaperService.java

@@ -2,19 +2,30 @@ package com.qxgmat.service;
 
 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.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.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;
 import java.util.Collection;
 import java.util.List;
 
@@ -26,27 +37,79 @@ public class ExercisePaperService extends AbstractService {
     private ExercisePaperMapper exercisePaperMapper;
 
     @Resource
+    private ExercisePaperRelationMapper exercisePaperRelationMapper;
+
+    @Resource
     private QuestionService questionService;
 
+    @Resource
+    private UserPaperRelationMapper userPaperRelationMapper;
+
+    @Resource
+    private UserPaperService userPaperService;
+
+    @Resource
+    private UserReportRelationMapper userReportRelationMapper;
+
+    @Resource
+    private UserReportService userReportService;
 
+    // 完成一次
+    public boolean finished(UserPaper userPaper){
 
-    @Transactional
-    public Question addQuestion(Question question){
-        question = questionService.add(question);
-        // 进行分组逻辑处理
-//        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-//        entity.setQuestionId(question.getId());
-//        return add(entity);
-        return question;
+        return true;
     }
+    /**
+     * 获取考点分组所有可用考点信息
+     * @return
+     */
+    public List<String> groupPlace(){
+        List<ExercisePaper> p = exercisePaperRelationMapper.groupPlace();
+
+        Collection ids = Transform.getIds(p, ExercisePaper.class, "id");
+
+        // 获取详细数据
+        List<ExercisePaper> list = select(ids);
 
-    @Transactional
-    public Question editQuestion(Question question){
-        question = questionService.edit(question);
-//        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-//        return edit(entity);
-        return question;
+        List<String> places = new ArrayList<>();
+        for(ExercisePaper paper : list){
+            places.add(paper.getLogicExtend());
+        }
+        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);
         paper = one(exercisePaperMapper, paper.getId());

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

@@ -7,6 +7,8 @@ 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.module.PaperModule;
 import com.qxgmat.data.constants.enums.status.HomeworkPreviewStatus;
 import com.qxgmat.data.dao.HomeworkPreviewMapper;
 import com.qxgmat.data.dao.entity.HomeworkPreview;
@@ -14,7 +16,10 @@ 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.UserHomeworkPreviewRelation;
+import com.qxgmat.service.extend.ToolsService;
+import com.qxgmat.service.inline.QuestionNoService;
 import com.qxgmat.service.inline.UserReportService;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -23,6 +28,7 @@ import org.springframework.transaction.annotation.Transactional;
 
 import javax.annotation.Resource;
 import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class HomeworkPreviewService extends AbstractService {
@@ -32,6 +38,9 @@ public class HomeworkPreviewService extends AbstractService {
     private HomeworkPreviewMapper homeworkPreviewMapper;
 
     @Resource
+    private QuestionNoService questionNoService;
+
+    @Resource
     private UserReportService userReportService;
 
     @Resource
@@ -43,6 +52,15 @@ public class HomeworkPreviewService extends AbstractService {
     @Resource
     private UserPaperRelationMapper userPaperRelationMapper;
 
+    @Resource
+    private ToolsService toolsService;
+
+    // 完成一次
+    public boolean finished(UserPaper userPaper){
+
+        return true;
+    }
+
     /**
      * 查找用户作业,并关联用户完成度最高的最后一次
      * @param page
@@ -160,8 +178,22 @@ public class HomeworkPreviewService extends AbstractService {
         if(homeworkPreview == null){
             throw new SystemException("预习作业添加失败");
         }
-        // todo 添加所有用户预习作业
-
+        Integer[] userIds = homeworkPreview.getUserIds();
+
+        // 获取考题时间
+        List<QuestionNoRelation> relationList = questionNoService.listByIds(homeworkPreview.getQuestionNoIds());
+        Integer time = toolsService.computerTime(SettingKey.EXERCISE_TIME, relationList);
+        for(Integer userId : userIds){
+            userPaperService.add(UserPaper.builder()
+                    .module(PaperModule.HOMEWORK_PREVIEW.key)
+                    .userId(userId)
+                    .title(homeworkPreview.getTitle())
+                    .moduleId(homeworkPreview.getId())
+                    .questionNoIds(homeworkPreview.getQuestionNoIds())
+                    .time(time)
+                    .build()
+            );
+        }
         return homeworkPreview;
     }
 
@@ -171,8 +203,46 @@ public class HomeworkPreviewService extends AbstractService {
         if(in == null){
             throw new ParameterException("预习作业不存在");
         }
-        // todo 修改所有用户预习作业
         int result = update(homeworkPreviewMapper, homeworkPreview);
+
+        List<Integer> oldList = Arrays.stream(in.getUserIds()).collect(Collectors.toList());
+        List<Integer> newList = Arrays.stream(homeworkPreview.getUserIds()).collect(Collectors.toList());
+
+        // 移除旧用户试卷
+        oldList.removeAll(newList);
+        userPaperService.removeByUsersAndPaper(oldList, PaperModule.HOMEWORK_PREVIEW, homeworkPreview.getId());
+
+        // 获取旧用户做为编辑试卷
+        List<Integer> editList = Arrays.stream(in.getUserIds()).collect(Collectors.toList());
+        editList.removeAll(oldList);
+
+        // 获取考题时间
+        List<QuestionNoRelation> relationList = questionNoService.listByIds(homeworkPreview.getQuestionNoIds());
+        Integer time = toolsService.computerTime(SettingKey.EXERCISE_TIME, relationList);
+        for(Integer userId : newList){
+            if (!editList.contains(userId)){
+                // 添加
+                userPaperService.add(UserPaper.builder()
+                        .module(PaperModule.HOMEWORK_PREVIEW.key)
+                        .userId(userId)
+                        .title(homeworkPreview.getTitle())
+                        .moduleId(homeworkPreview.getId())
+                        .questionNoIds(homeworkPreview.getQuestionNoIds())
+                        .time(time)
+                        .build()
+                );
+                editList.remove(userId);
+            }
+        }
+        // 修改
+        userPaperService.editByUsersAndPaper(UserPaper.builder()
+                .title(homeworkPreview.getTitle())
+                .questionNoIds(homeworkPreview.getQuestionNoIds())
+                .time(time)
+                .build(),
+                oldList,
+                PaperModule.HOMEWORK_PREVIEW, homeworkPreview.getId());
+
         return homeworkPreview;
     }
 

+ 111 - 6
server/gateway-api/src/main/java/com/qxgmat/service/SentencePaperService.java

@@ -5,6 +5,8 @@ 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;
@@ -14,16 +16,21 @@ 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);
+    @Value("${paper.sentenceLength}")
+    private Integer paperLength;
 
     @Resource
     private SentencePaperMapper sentencePaperMapper;
@@ -34,23 +41,121 @@ public class SentencePaperService extends AbstractService {
     @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);
-        // 根据序号创建
-        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-        entity.setQuestionId(question.getId());
-        return sentenceQuestionService.add(entity);
+        // 绑定关系
+        relation.setQuestionId(question.getId());
+
+        SentenceQuestion sentenceQuestion =  sentenceQuestionService.add(relation);
+
+        // 绑定关系
+        SentencePaper paper = addQuestionToPaper(sentenceQuestion);
+        sentenceQuestion.setPaperId(paper.getId());
+
+        sentenceQuestionService.edit(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());
+        }
+
         // 根据序号调整分组
-        SentenceQuestion entity = Transform.convert(relation, SentenceQuestion.class);
-        return sentenceQuestionService.edit(entity);
+        if (!in.getId().equals(relation.getId())){
+            // 移出原有关系
+            removeQuestionFromPaper(in);
+
+            // 绑定关系
+            SentencePaper paper = addQuestionToPaper(relation);
+            relation.setPaperId(paper.getId());
+        }
+
+        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 SentencePaper addQuestionToPaper(SentenceQuestion question){
+        // 根据序号创建
+        Integer paperNo = question.getNo() / paperLength + 1;
+        SentencePaper paper = getByNo(paperNo, SentenceLogic.NO);
+        if (paper == null){
+            paper = add(SentencePaper.builder()
+                    .logic(SentenceLogic.NO.key)
+                    .questionNumber(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);
+        }
+        return paper;
+    }
+
+    private Boolean removeQuestionFromPaper(SentenceQuestion question){
+        SentencePaper paper = get(question.getPaperId());
+        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]));
+        paper = edit(paper);
+        return true;
+    }
+
+    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);
     }
 
     public SentencePaper add(SentencePaper paper){

+ 5 - 0
server/gateway-api/src/main/java/com/qxgmat/service/UserNoteService.java

@@ -84,6 +84,11 @@ public class UserNoteService extends AbstractService {
         return new PageResult<>(pr, p.getTotal());
     }
 
+    /**
+     * 更新用户笔记:没有则添加
+     * @param note
+     * @return
+     */
     @Transactional
     public UserNote update(UserNote note){
         Example example = new Example(UserCollectQuestion.class);

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

@@ -5,24 +5,28 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.PageResult;
 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.QuestionModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.UserPaperMapper;
 import com.qxgmat.data.dao.entity.UserPaper;
 import com.qxgmat.data.relation.UserPaperRelationMapper;
+import com.qxgmat.util.annotation.Callback;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.List;
+import java.util.Map;
 
 @Service
 public class UserPaperService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(UserPaperService.class);
+    protected boolean SOFT_FLAG = true;
 
     @Resource
     private UserPaperMapper userPaperMapper;
@@ -30,11 +34,59 @@ public class UserPaperService extends AbstractService {
     @Resource
     private UserPaperRelationMapper userPaperRelationMapper;
 
+    @Resource
+    private ExercisePaperService exercisePaperService;
+
+    @Resource
+    private HomeworkPreviewService homeworkPreviewService;
+
+    @Resource
+    private ExaminationPaperService examinationPaperService;
+
+    private Map<PaperModule, Callback> finishCallback;
+
+    public UserPaperService(){
+        finishCallback = new HashMap<>();
+        finishCallback.put(PaperModule.EXERCISE, (obj)->{
+            return exercisePaperService.finished((UserPaper) obj);
+        });
+        finishCallback.put(PaperModule.HOMEWORK_PREVIEW, (obj)->{
+            return homeworkPreviewService.finished((UserPaper) obj);
+        });
+        finishCallback.put(PaperModule.EXAMINATION, (obj)->{
+            return homeworkPreviewService.finished((UserPaper) obj);
+        });
+    }
+
     public PageResult<UserPaper> list(int page, int size, Integer userId, PaperModule module, QuestionType type, String startTime, String endTime, String order, DirectionStatus direction){
 
         return new PageResult<>(null, 0);
     }
 
+    public Boolean removeByUsersAndPaper(Collection<Integer> userIds, PaperModule module, Integer paperId){
+        if(userIds.size() == 0) return false;
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("userId", userIds)
+                        .andEqualTo("module", module.key)
+                        .andEqualTo("moduleId", paperId)
+        );
+        return delete(userPaperMapper, example, SOFT_FLAG) > 0;
+    }
+
+    public Boolean editByUsersAndPaper(UserPaper userPaper, Collection<Integer> userIds, PaperModule module, Integer paperId){
+        if(userIds.size() == 0) return false;
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("userId", userIds)
+                        .andEqualTo("module", module.key)
+                        .andEqualTo("moduleId", paperId)
+        );
+        return update(userPaperMapper, example, userPaper) > 0;
+    }
+
     public UserPaper add(UserPaper paper){
         int result = insert(userPaperMapper, paper);
         paper = one(userPaperMapper, paper.getId());

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

@@ -0,0 +1,47 @@
+package com.qxgmat.service.extend;
+
+import com.alibaba.fastjson.JSONObject;
+import com.qxgmat.data.constants.enums.SettingKey;
+import com.qxgmat.data.dao.entity.QuestionNo;
+import com.qxgmat.data.dao.entity.Setting;
+import com.qxgmat.data.relation.entity.QuestionNoRelation;
+import com.qxgmat.service.inline.SettingService;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+@Service
+public class ToolsService {
+
+    @Resource
+    private SettingService settingService;
+
+    /**
+     * 根据练习或者模考时间设置计算考题考试时间
+     *      setting: {struct: {difficult: ""}}
+     * @param settingKey
+     * @param relationList
+     * @return
+     */
+    public Integer computerTime(SettingKey settingKey, List<QuestionNoRelation> relationList){
+        Setting setting = settingService.getByKey(settingKey);
+        JSONObject value = setting.getValue();
+
+        Integer time = 0;
+        for(QuestionNoRelation relation:relationList){
+            JSONObject difficultMap = null;
+            for (Integer struct : relation.getModuleStruct()){
+                // 判断结构体
+                difficultMap = value.getJSONObject(String.valueOf(struct));
+                if (difficultMap != null) break;
+            }
+            if (difficultMap == null) continue;
+            // 判断难度
+            String t = difficultMap.getString(relation.getQuestion().getDifficult());
+            if (t == null || t.isEmpty()) continue;
+            time += Integer.valueOf(t);
+        }
+        return time;
+    }
+}

+ 6 - 5
server/gateway-api/src/main/java/com/qxgmat/service/extend/TradeService.java

@@ -4,13 +4,14 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.Tools;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
+import com.qxgmat.data.constants.enums.module.PayModule;
 import com.qxgmat.data.constants.enums.trade.PayType;
 import com.qxgmat.data.constants.enums.trade.TradeStatus;
 import com.qxgmat.data.dao.PayMapper;
 import com.qxgmat.data.dao.entity.Pay;
 import com.qxgmat.service.inline.UserClassService;
 import com.qxgmat.service.inline.UserServiceService;
-import com.qxgmat.util.annotation.PayModuleCallback;
+import com.qxgmat.util.annotation.Callback;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
@@ -34,14 +35,14 @@ public class TradeService extends AbstractService {
     @Resource
     private UserClassService userClassService;
 
-    private Map<String, PayModuleCallback> registerCallback;
+    private Map<PayModule, Callback> registerCallback;
 
     public TradeService(){
         registerCallback = new HashMap<>();
-        registerCallback.put("service", (pay)->{
+        registerCallback.put(PayModule.SERVICE, (pay)->{
             return userServiceService.payed((Pay)pay);
         });
-        registerCallback.put("class", (pay)->{
+        registerCallback.put(PayModule.CLASS, (pay)->{
             return userClassService.payed((Pay)pay);
         });
     }
@@ -91,7 +92,7 @@ public class TradeService extends AbstractService {
                 || pay.getTradeStatus() == TradeStatus.CLOSE.index)
             throw new ParameterException("该支付无效");
 
-        PayModuleCallback callback = registerCallback.get(pay.getModule());
+        Callback callback = registerCallback.get(pay.getModule());
         try {
             boolean r = callback.callback(pay);
             if (!r)

+ 86 - 7
server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java

@@ -11,6 +11,7 @@ import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.QuestionNoMapper;
 import com.qxgmat.data.dao.entity.Question;
 import com.qxgmat.data.dao.entity.QuestionNo;
+import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.relation.QuestionNoRelationMapper;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import org.slf4j.Logger;
@@ -18,14 +19,13 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
 import java.util.stream.Collectors;
 
 @Service
 public class QuestionNoService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(QuestionNoService.class);
+    protected boolean SOFT_FLAG = true;
 
     @Resource
     private QuestionNoMapper questionNoMapper;
@@ -60,14 +60,20 @@ public class QuestionNoService extends AbstractService {
      * @param page
      * @param size
      * @param no
+     * @param module
      * @return
      */
-    public PageResult<QuestionNoRelation> searchNo(int page, int size, String no){
+    public PageResult<QuestionNoRelation> searchNo(int page, int size, String no, String module){
         Example example = new Example(QuestionNo.class);
         example.and(
                 example.createCriteria()
                         .andLike("no", no)
         );
+        if (module != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("module", module)
+            );
         example.orderBy("id").asc();
         Page<QuestionNo> p = page(()->select(questionNoMapper, example), page, size);
         return new PageResult<>(relation(p), p.getTotal());
@@ -80,6 +86,7 @@ public class QuestionNoService extends AbstractService {
      * @return
      */
     public List<QuestionNoRelation> listByNos(String[] nos, String module){
+        if (nos.length == 0) return new ArrayList<>();
         Example example = new Example(QuestionNo.class);
         example.and(
                 example.createCriteria()
@@ -94,6 +101,11 @@ public class QuestionNoService extends AbstractService {
         return relation(p);
     }
 
+    /**
+     * 根据题目获取关联的题目编号
+     * @param questionId
+     * @return
+     */
     public List<QuestionNo> listByQuestion(Number questionId){
         Example example = new Example(QuestionNo.class);
         example.and(
@@ -103,12 +115,80 @@ public class QuestionNoService extends AbstractService {
         return select(questionNoMapper, example);
     }
 
+    /**
+     * 根据题目编号id获取关联题目
+     * @param ids
+     * @return
+     */
     public List<QuestionNoRelation> listByIds(Number[] ids){
         List<QuestionNo> p = select(questionNoMapper, ids);
         return relation(p);
     }
 
-    public List<QuestionNoRelation> relation(List<QuestionNo> p){
+    /**
+     * 绑定no和question
+     * @param ids
+     * @param questionId
+     * @return
+     */
+    public Boolean bindQuestion(Integer[] ids, Integer questionId){
+        if (ids.length == 0) return false;
+        Example example = new Example(QuestionNo.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("id", Arrays.stream(ids).collect(Collectors.toList()))
+        );
+        int result = update(questionNoMapper, example, QuestionNo.builder().questionId(questionId).build());
+        return result > 0;
+    }
+
+    /**
+     * 根据题目获取总试卷统计信息
+     * @param questionNoList
+     * @return
+     */
+    public PaperStat statPaper(List<QuestionNo> questionNoList){
+        PaperStat stat = new PaperStat();
+        Integer totalTime = 0;
+        Integer totalNumber = 0;
+        Integer totalCorrect = 0;
+        for(QuestionNo questionNo : questionNoList){
+            totalTime += questionNo.getTotalTime();
+            totalNumber += questionNo.getTotalNumber();
+            totalCorrect += questionNo.getTotalCorrect();
+        }
+        stat.setTotalCorrect(totalCorrect);
+        stat.setTotalNumber(totalNumber);
+        stat.setTotalTime(totalTime);
+        return stat;
+    }
+
+    /**
+     * 根据试卷分组获取统计信息
+     * @param questionNoIdsMap
+     * @return
+     */
+    public Map<Integer, PaperStat> statPaperMap(Map<Integer, Integer[]> questionNoIdsMap){
+        Map<Integer, PaperStat> relationMap = new HashMap<>();
+        List<Integer> ids = new ArrayList<>();
+        for(Integer[] questionNoIds : questionNoIdsMap.values()){
+            ids.addAll(Arrays.stream(questionNoIds).collect(Collectors.toList()));
+        }
+        List<QuestionNo> questionNoList = select(ids);
+        Map questionNoMap = Transform.getMap(questionNoList, QuestionNo.class, "id");
+        List<QuestionNo> l = new ArrayList<>();
+        for(Integer k: questionNoIdsMap.keySet()){
+            l.clear();
+            for (Integer questionNoId : questionNoIdsMap.get(k)){
+                l.add((QuestionNo)questionNoMap.get(questionNoId));
+            }
+            relationMap.put(k, statPaper(l));
+        }
+
+        return relationMap;
+    }
+
+    private List<QuestionNoRelation> relation(List<QuestionNo> p){
         List<QuestionNoRelation> relationList = Transform.convert(p, QuestionNoRelation.class);
 
         Collection questionIds = Transform.getIds(p, QuestionNo.class, "questionId");
@@ -117,8 +197,7 @@ public class QuestionNoService extends AbstractService {
         return relationList;
     }
 
-
-    public QuestionNoRelation relation(QuestionNo p){
+    private QuestionNoRelation relation(QuestionNo p){
         QuestionNoRelation relation = Transform.convert(p, QuestionNoRelation.class);
 
         Question question = questionService.get(p.getQuestionId());

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

@@ -10,14 +10,15 @@ import com.qxgmat.data.dao.HomeworkPreviewMapper;
 import com.qxgmat.data.dao.QuestionMapper;
 import com.qxgmat.data.dao.entity.HomeworkPreview;
 import com.qxgmat.data.dao.entity.Question;
+import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.relation.QuestionRelationMapper;
 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;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class QuestionService extends AbstractService {
@@ -29,6 +30,51 @@ public class QuestionService extends AbstractService {
     @Resource
     private QuestionRelationMapper questionRelationMapper;
 
+    /**
+     * 根据题目获取总试卷统计信息
+     * @param questionNoList
+     * @return
+     */
+    public PaperStat statPaper(List<Question> questionNoList){
+        PaperStat stat = new PaperStat();
+        Integer totalTime = 0;
+        Integer totalNumber = 0;
+        Integer totalCorrect = 0;
+        for(Question question : questionNoList){
+            totalTime += question.getTotalTime();
+            totalNumber += question.getTotalNumber();
+            totalCorrect += question.getTotalCorrect();
+        }
+        stat.setTotalCorrect(totalCorrect);
+        stat.setTotalNumber(totalNumber);
+        stat.setTotalTime(totalTime);
+        return stat;
+    }
+
+    /**
+     * 根据试卷分组获取统计信息
+     * @param questionIdsMap
+     * @return
+     */
+    public Map<Integer, PaperStat> statPaperMap(Map<Integer, Integer[]> questionIdsMap){
+        Map<Integer, PaperStat> relationMap = new HashMap<>();
+        List<Integer> ids = new ArrayList<>();
+        for(Integer[] questionIds : questionIdsMap.values()){
+            ids.addAll(Arrays.stream(questionIds).collect(Collectors.toList()));
+        }
+        List<Question> questionList = select(ids);
+        Map questionNoMap = 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));
+            }
+            relationMap.put(k, statPaper(l));
+        }
+
+        return relationMap;
+    }
 
     public Question add(Question question){
         int result = insert(questionMapper, question);

+ 14 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/SentenceQuestionService.java

@@ -56,6 +56,20 @@ public class SentenceQuestionService extends AbstractService {
         return relation;
     }
 
+    /**
+     * 根据序号查询
+     * @param no
+     * @return
+     */
+    public SentenceQuestion getByNo(Integer no){
+        Example example = new Example(SentenceQuestion.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("no", no)
+        );
+        return one(sentenceQuestionMapper, example);
+    }
+
     public SentenceQuestion add(SentenceQuestion question){
         int result = insert(sentenceQuestionMapper, question);
         question = one(sentenceQuestionMapper, question.getId());

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

@@ -60,6 +60,11 @@ public class UserClassService extends AbstractService {
         update(userClassMapper, example, UserClass.builder().userId(newUserId).build());
     }
 
+    /**
+     * 获取用户课程列表
+     * @param userId
+     * @return
+     */
     public List<UserClass> getByUser(Number userId){
         Example example = new Example(UserService.class);
         example.and(

+ 18 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserPayService.java

@@ -5,6 +5,7 @@ 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.module.PayModule;
 import com.qxgmat.data.dao.UserNoteMapper;
 import com.qxgmat.data.dao.UserPayMapper;
 import com.qxgmat.data.dao.entity.UserNote;
@@ -37,6 +38,23 @@ public class UserPayService extends AbstractService {
         update(userPayMapper, example, UserPay.builder().userId(newUserId).build());
     }
 
+    /**
+     * 获取未使用的购买信息:根据模块
+     * @param userId
+     * @param module
+     * @return
+     */
+    public List<UserPay> listUnUse(Integer userId, PayModule module){
+        Example example = new Example(UserPay.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("module", module.key)
+                        .andEqualTo("isUse", 0)
+        );
+        return select(userPayMapper, example);
+    }
+
     public UserPay add(UserPay pay){
         int result = insert(userPayMapper, pay);
         pay = one(userPayMapper, pay.getId());

+ 3 - 9
server/gateway-api/src/main/java/com/qxgmat/task/AsyncTask.java

@@ -11,7 +11,7 @@ public class AsyncTask {
 
     @Async("autoExercisePaper")
     public void autoExercisePaper() {
-        logger.info("自动练习组卷");
+        logger.info("自动练习组卷:顺序,考点,难易度");
         long start = System.currentTimeMillis();
         long end = System.currentTimeMillis();
         logger.info("完成任务一,耗时:" + (end - start) + "毫秒");
@@ -19,17 +19,11 @@ public class AsyncTask {
 
     @Async("autoExercisePaperError")
     public void autoExercisePaperError() {
-        logger.info("自动练习难易度组卷");
-        long start = System.currentTimeMillis();
-        long end = System.currentTimeMillis();
-        logger.info("完成任务一,耗时:" + (end - start) + "毫秒");
+        logger.info("自动练习:难易度组卷,全局难易度判断");
     }
 
     @Async("autoSentencePaper")
     public void autoSentencePaper() {
-        logger.info("自动长难句");
-        long start = System.currentTimeMillis();
-        long end = System.currentTimeMillis();
-        logger.info("完成任务一,耗时:" + (end - start) + "毫秒");
+        logger.info("自动长难句:对于试用卷进行自动生成");
     }
 }

+ 2 - 2
server/gateway-api/src/main/java/com/qxgmat/util/annotation/PayModuleCallback.java

@@ -5,6 +5,6 @@ package com.qxgmat.util.annotation;
  * Created by gaojie on 2017/11/20.
  */
 @FunctionalInterface
-public interface PayModuleCallback {
-    boolean callback(Object pay);
+public interface Callback {
+    boolean callback(Object obj);
 }

+ 1 - 0
server/gateway-api/src/main/java/com/qxgmat/util/shiro/ShiroConfig.java

@@ -55,6 +55,7 @@ public class ShiroConfig {
         chain.addPathDefinition("/admin/auth/**", "anon");
         chain.addPathDefinition("/admin/**", "role[manager]");
         chain.addPathDefinition("/api/my/**", "role[user]");
+        chain.addPathDefinition("/api/question/**", "role[user]");
 
         chain.addPathDefinition("/**", "anon");
         return chain;

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

@@ -53,3 +53,6 @@ third:
 
 self:
   secret: qianxing-duoshaojiaoyu
+
+paper:
+  sentenceLength: 20

+ 1 - 1
server/tools/src/main/java/com/nuliji/tools/mybatis/handler/NativeJsonHandler.java

@@ -15,7 +15,7 @@ import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 
-@MappedJdbcTypes({JdbcType.LONGVARCHAR, JdbcType.VARCHAR})
+//@MappedJdbcTypes({JdbcType.LONGVARCHAR, JdbcType.VARCHAR})
 public class NativeJsonHandler<T> extends BaseTypeHandler<T> {
     private static final ObjectMapper mapper = new ObjectMapper();
     private Class<T> clazz;