Browse Source

feat(server): 机经操作

Go 5 years ago
parent
commit
8aff263e34
100 changed files with 3490 additions and 552 deletions
  1. 6 0
      front/project/Constant.js
  2. 5 0
      front/project/admin/routes/class/group.js
  3. 3 0
      front/project/admin/routes/class/index.js
  4. 124 1
      front/project/admin/routes/setting/rank/page.js
  5. 162 46
      front/project/admin/routes/setting/struct/page.js
  6. 4 4
      front/project/admin/routes/setting/time/page.js
  7. 6 6
      front/project/admin/routes/subject/exercise/page.js
  8. 4 1
      front/project/admin/routes/subject/previewDetail/page.js
  9. 2 4
      front/project/admin/routes/subject/question/page.js
  10. 16 2
      front/project/admin/routes/subject/sentenceQuestion/page.js
  11. 142 1
      front/project/admin/routes/subject/textbook/page.js
  12. 37 1
      front/project/admin/routes/subject/textbookQuestion/index.less
  13. 291 46
      front/project/admin/routes/subject/textbookQuestion/page.js
  14. 21 4
      front/project/admin/routes/user/ask/page.js
  15. 26 6
      front/project/admin/routes/user/askDetail/page.js
  16. 15 0
      front/project/admin/routes/user/examination/index.js
  17. 3 0
      front/project/admin/routes/user/examination/index.less
  18. 10 0
      front/project/admin/routes/user/examination/page.js
  19. 180 1
      front/project/admin/routes/user/feedback/page.js
  20. 3 1
      front/project/admin/routes/user/index.js
  21. 4 4
      front/project/admin/routes/user/preview/page.js
  22. 15 0
      front/project/admin/routes/user/student/index.js
  23. 3 0
      front/project/admin/routes/user/student/index.less
  24. 132 0
      front/project/admin/routes/user/student/page.js
  25. 8 4
      front/project/admin/stores/system.js
  26. 33 0
      front/project/admin/stores/textbook.js
  27. 14 2
      front/src/services/AsyncTools.js
  28. 10 1
      front/src/services/Tools.js
  29. 27 6
      server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionGroup.java
  30. 2 2
      server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionType.java
  31. 1 16
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  32. 14 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/logic/TextbookLogic.java
  33. 16 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/FeedbackModule.java
  34. 25 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/status/FeedbackStatus.java
  35. 13 2
      server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayChannel.java
  36. 28 5
      server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayType.java
  37. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ClassCommentMapper.java
  38. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ClassCourseNoMapper.java
  39. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ClassFaqMapper.java
  40. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/UserCourseMapper.java
  41. 63 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ClassComment.java
  42. 63 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ClassCourseNo.java
  43. 168 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ClassFaq.java
  44. 243 59
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExaminationPaper.java
  45. 70 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExaminationStruct.java
  46. 32 32
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExercisePaper.java
  47. 56 65
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExerciseStruct.java
  48. 46 11
      server/data/src/main/java/com/qxgmat/data/dao/entity/Pay.java
  49. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/PreviewPaper.java
  50. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/Question.java
  51. 7 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/QuestionNo.java
  52. 27 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/SentencePaper.java
  53. 54 28
      server/data/src/main/java/com/qxgmat/data/dao/entity/SentenceQuestion.java
  54. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookPaper.java
  55. 69 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookQuestion.java
  56. 133 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourse.java
  57. 219 35
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserFeedbackError.java
  58. 43 17
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPay.java
  59. 26 26
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserQuestion.java
  60. 1 1
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserReport.java
  61. 10 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassCommentMapper.xml
  62. 10 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassCourseNoMapper.xml
  63. 19 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassFaqMapper.xml
  64. 10 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExaminationPaperMapper.xml
  65. 3 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExaminationStructMapper.xml
  66. 3 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExercisePaperMapper.xml
  67. 4 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExerciseStructMapper.xml
  68. 5 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PayMapper.xml
  69. 3 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PreviewPaperMapper.xml
  70. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/QuestionMapper.xml
  71. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/SentencePaperMapper.xml
  72. 4 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/SentenceQuestionMapper.xml
  73. 5 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookPaperMapper.xml
  74. 5 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookQuestionMapper.xml
  75. 18 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseMapper.xml
  76. 10 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserFeedbackErrorMapper.xml
  77. 4 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPayMapper.xml
  78. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserQuestionMapper.xml
  79. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/ExerciseQuestionRelationMapper.java
  80. 27 0
      server/data/src/main/java/com/qxgmat/data/relation/TextbookQuestionRelationMapper.java
  81. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/UserCollectQuestionRelationMapper.java
  82. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/UserNoteQuestionRelationMapper.java
  83. 16 0
      server/data/src/main/java/com/qxgmat/data/relation/entity/TextbookQuestionRelation.java
  84. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExerciseQuestionRelationMapper.xml
  85. 48 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookQuestionRelationMapper.xml
  86. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCollectQuestionRelationMapper.xml
  87. 17 15
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserNoteQuestionRelationMapper.xml
  88. 24 1
      server/data/src/main/resources/db/migration/V1__init_table.sql
  89. 1 1
      server/data/src/main/resources/mybatis-generator.xml
  90. 4 0
      server/gateway-api/build.gradle
  91. 5 0
      server/gateway-api/src/main/java/com/qxgmat/Application.java
  92. 4 3
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExaminationController.java
  93. 1 2
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/ExerciseController.java
  94. 71 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  95. 125 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/TextbookController.java
  96. 10 14
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserAskController.java
  97. 23 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  98. 33 2
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserFeedbackErrorController.java
  99. 27 7
      server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java
  100. 0 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java

+ 6 - 0
front/project/Constant.js

@@ -4,6 +4,8 @@ export const QuestionDifficult = [{ label: 'easy', value: 'easy' }, { label: 'me
 
 export const QuestionType = [{ label: 'SC/语法', value: 'sc' }, { label: 'RC/阅读', value: 'rc' }, { label: 'CR/逻辑', value: 'cr' }, { label: 'PS/数学', value: 'ps' }, { label: 'DS/数学', value: 'ds' }, { label: 'IR/综合推理', value: 'ir' }, { label: 'AWA/作文', value: 'awa' }];
 
+export const TextbookType = [{ label: 'PS/数学', value: 'ps' }, { label: 'DS/数学', value: 'ds' }];
+
 export const MoneyRange = [{ label: '0', value: 0 }, { label: '1-1000', value: 1 }, { label: '1000-5000', value: 2 }, { label: '5000-10000', value: 3 }, { label: '10000以上', value: 4 }];
 
 export const AskTarget = [{ label: '题目', value: 'question' }, { label: '官方', value: 'official' }, { label: '千行解析', value: 'qx' }, { label: '题源联想', value: 'association' }];
@@ -18,6 +20,10 @@ export const SwitchSelect = [{ value: 0, label: '否' }, { value: 1, label: '是
 
 export const AskStatus = [{ value: 0, label: '新增' }, { value: 1, label: '已回答' }, { value: 2, label: '忽略' }];
 
+export const FeedbackStatus = [{ value: 0, label: '新增' }, { value: 1, label: '已处理' }, { value: 2, label: '忽略' }];
+
+export const FeedbackModule = [{ value: 'question', label: '题目' }, { value: 'data', label: '资料' }];
+
 export const PrepareStatus = [{ label: '学生-Domestic', value: 'student_domestic' }, { label: '学生-Overseas', value: 'student_overseas' }, { label: '在职-Domestic', value: 'worker_domestic' }, { label: '在职-Overseas', value: 'worker_overseas' }, { label: 'Gap Year', value: 'gap_year' }];
 
 export const PrepareExaminationTime = [{ label: '近1个月', value: 'one_month' }, { label: '近2个月', value: 'two_month' }, { label: '近3个月', value: 'three_month' }, { label: '半年内', value: 'six_month' }];

+ 5 - 0
front/project/admin/routes/class/group.js

@@ -0,0 +1,5 @@
+export default {
+  key: 'class',
+  name: '课程管理',
+  icon: 'appstore',
+};

+ 3 - 0
front/project/admin/routes/class/index.js

@@ -0,0 +1,3 @@
+
+
+export default [];

+ 124 - 1
front/project/admin/routes/setting/rank/page.js

@@ -1,10 +1,133 @@
 import React from 'react';
+import { Button, Upload } from 'antd';
 import './index.less';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { asyncSMessage, asyncForm, asyncDelConfirm } from '@src/services/AsyncTools';
+import { System } from '../../../stores/system';
 
 export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.itemList = [{
+      key: 'id',
+      type: 'hidden',
+    }, {
+      key: 'totalScore',
+      type: 'number',
+      name: '总分',
+    }, {
+      key: 'totalRank',
+      type: 'number',
+      name: '总排名',
+    }, {
+      key: 'quantScore',
+      type: 'number',
+      name: 'Q分',
+    }, {
+      key: 'quantRank',
+      type: 'number',
+      name: 'Q排名',
+    }, {
+      key: 'verbalScore',
+      type: 'number',
+      name: 'V分',
+    }, {
+      key: 'verbalRank',
+      type: 'number',
+      name: 'V排名',
+    }];
+
+    this.columns = [{
+      title: '总分',
+      dataIndex: 'totalScore',
+    }, {
+      title: '总排名',
+      dataIndex: 'totalRank',
+    }, {
+      title: 'Q分',
+      dataIndex: 'quantScore',
+    }, {
+      title: 'Q排名',
+      dataIndex: 'quantRank',
+    }, {
+      title: 'V分',
+      dataIndex: 'verbalScore',
+    }, {
+      title: 'V排名',
+      dataIndex: 'verbalRank',
+    }];
+
+    this.actionList = [{
+      key: 'import',
+      name: '批量导入',
+      render: (item) => {
+        return <Upload
+          showUploadList={false}
+          beforeUpload={(file) => System.importRank(file).then((result) => {
+            asyncSMessage(result);
+          })}
+        >
+          <Button>{item.name}</Button>
+        </Upload>;
+      },
+    }, {
+      key: 'del',
+      name: '批量删除',
+      type: 'danger',
+      needSelect: 1,
+    }];
+  }
+
+  initData() {
+    System.listRank().then(result => {
+      this.setState({ list: result });
+    });
+  }
+
+  addAction() {
+    asyncForm('新增', this.itemList, {}, data => {
+      return System.addRank(data).then(() => {
+        asyncSMessage('新增成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  editRow(row) {
+    asyncForm('编辑', this.itemList, row, data => {
+      return System.editRank(data).then(() => {
+        asyncSMessage('编辑成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  delAction() {
+    const { selectedKeys } = this.state;
+    asyncDelConfirm('删除确认', '是否删除选中数据?', () => {
+      return Promise.all(selectedKeys.map(row => System.delRank({ id: row })));
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.refresh();
+    });
+  }
+
   renderView() {
-    return <Block flex />;
+    return <Block flex>
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        columns={this.columns}
+        list={this.state.list}
+        pagination={false}
+        loading={this.props.core.loading}
+      />
+    </Block>;
   }
 }

+ 162 - 46
front/project/admin/routes/setting/struct/page.js

@@ -5,7 +5,7 @@ import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import TreeLayout from '@src/layouts/TreeLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
-import { formatTreeData } from '@src/services/Tools';
+import { formatTreeData, getMap } from '@src/services/Tools';
 import { asyncDelConfirm, asyncForm, asyncSMessage } from '@src/services/AsyncTools';
 // import { System } from '../../../stores/system';
 import { Examination } from '../../../stores/examination';
@@ -36,14 +36,40 @@ export default class extends Page {
       type: 'hidden',
     }, {
       key: 'parentId',
-      type: 'tree',
+      type: 'hidden',
+    }, {
+      key: 'parentName',
+      type: 'input',
       name: '父节点',
-      tree: [],
-      fieldNames: { label: 'title', value: 'value', children: 'children' },
-      notFoundContent: null,
-      onChange: (value) => {
-        console.log(value);
-      },
+      disabled: true,
+    }, {
+      key: 'titleZh',
+      name: '中文名称',
+      type: 'input',
+      placeholder: '请输入中文名称',
+      required: true,
+    }, {
+      key: 'titleEn',
+      name: '英文名称',
+      type: 'input',
+      placeholder: '请输入英文名称',
+      required: true,
+    }, {
+      key: 'description',
+      name: '描述',
+      type: 'textarea',
+      placeholder: '请输入描述',
+      required: true,
+    }, {
+      key: 'isSentence',
+      type: 'hidden',
+    }, {
+      key: 'isExamination',
+      type: 'hidden',
+    }];
+    this.exerciseItemListLimit = [{
+      key: 'id',
+      type: 'hidden',
     }, {
       key: 'titleZh',
       name: '中文名称',
@@ -62,6 +88,12 @@ export default class extends Page {
       type: 'textarea',
       placeholder: '请输入描述',
       required: true,
+    }, {
+      key: 'isSentence',
+      type: 'hidden',
+    }, {
+      key: 'isExamination',
+      type: 'hidden',
     }];
     this.examinationActionList = [{
       key: 'addChild',
@@ -85,14 +117,38 @@ export default class extends Page {
       type: 'hidden',
     }, {
       key: 'parentId',
-      type: 'tree',
+      type: 'hidden',
+    }, {
+      key: 'parentName',
+      type: 'input',
       name: '父节点',
-      tree: [],
-      fieldNames: { label: 'title', value: 'value', children: 'children' },
-      notFoundContent: null,
-      onChange: (value) => {
-        console.log(value);
-      },
+      disabled: true,
+    }, {
+      key: 'titleZh',
+      name: '中文名称',
+      type: 'input',
+      placeholder: '请输入中文名称',
+      required: true,
+    }, {
+      key: 'titleEn',
+      name: '英文名称',
+      type: 'input',
+      placeholder: '请输入英文名称',
+      required: true,
+    }, {
+      key: 'description',
+      name: '描述',
+      type: 'textarea',
+      placeholder: '请输入描述',
+      required: true,
+    }, {
+      key: 'isAdapt',
+      type: 'hidden',
+    }];
+
+    this.examinationItemListLimit = [{
+      key: 'id',
+      type: 'hidden',
     }, {
       key: 'titleZh',
       name: '中文名称',
@@ -111,16 +167,18 @@ export default class extends Page {
       type: 'textarea',
       placeholder: '请输入描述',
       required: true,
+    }, {
+      key: 'isAdapt',
+      type: 'hidden',
     }];
     this.state.tab = 'exercise';
   }
 
   initData() {
-    this.refresh();
+    this.refresh(this.state.tab);
   }
 
-  refresh() {
-    const { tab } = this.state;
+  refresh(tab) {
     if (tab === 'exercise') {
       return this.refreshExercise();
     }
@@ -133,6 +191,7 @@ export default class extends Page {
       this.exerciseItemList[1].tree = formatTreeData([{ title: '根节点', id: 0 }].concat(list), 'id', 'title', 'parentId');
       this.setState({
         exerciseList: list,
+        exerciseMap: getMap(list, 'id'),
         exerciseStruct: formatTreeData(list.map(row => {
           if (row.level < 4) return row;
           row = Object.assign({}, row);
@@ -155,16 +214,17 @@ export default class extends Page {
       this.examinationItemList[1].tree = formatTreeData([{ title: '根节点', id: 0 }].concat(list), 'id', 'title', 'parentId');
       this.setState({
         examinationList: list,
+        examinationMap: getMap(list, 'id'),
         examinationStruct: formatTreeData(list.map(row => {
           if (row.level !== 2) return row;
-          row = Object.assign({}, row);
-          row.title = <div className='node'>{row.title}<Button className='after-node' size='small' type={row.questionStatus > 0 ? 'primary' : 'ghost'} onClick={(e) => {
-            e.preventDefault();
-            row.payStatus = row.payStatus > 0 ? 0 : 1;
-            Examination.editStruct(row).then(() => {
-              this.refresh();
-            });
-          }}>{row.payStatus > 0 ? [<Icon type="pay-circle" />, <span>付费</span>] : [<Icon type="eye" />, <span>免费</span>]}</Button></div>;
+          // row = Object.assign({}, row);
+          // row.title = <div className='node'>{row.title}<Button className='after-node' size='small' type={row.questionStatus > 0 ? 'primary' : 'ghost'} onClick={(e) => {
+          //   e.preventDefault();
+          //   row.payStatus = row.payStatus > 0 ? 0 : 1;
+          //   Examination.editStruct(row).then(() => {
+          //     this.refresh();
+          //   });
+          // }}>{row.payStatus > 0 ? [<Icon type="pay-circle" />, <span>付费</span>] : [<Icon type="eye" />, <span>免费</span>]}</Button></div>;
           return row;
         }), 'id', 'title', 'parentId'),
       });
@@ -174,20 +234,34 @@ export default class extends Page {
   addChildAction() {
     const { tab, exerciseList, examinationList, selectedKeys } = this.state;
     let itemList;
-    let node = 0;
+    let node;
+    let dep;
     if (tab === 'exercise') {
       itemList = this.exerciseItemList;
       if (selectedKeys.length > 0) {
-        node = exerciseList.filter(row => row.id === Number(selectedKeys[0]))[0].id;
+        ([node] = exerciseList.filter(row => row.id === Number(selectedKeys[0])));
       }
+      // 长难句还在该逻辑内,不允许添加下属节点
+      if (node.level <= 1 || node.level >= 4) {
+        asyncSMessage('不允许添加该节点的子节点', 'warn');
+        return;
+      }
+      dep = {};
     } else {
       itemList = this.examinationItemList;
       if (selectedKeys.length > 0) {
-        node = examinationList.filter(row => row.id === Number(selectedKeys[0]))[0].id;
+        ([node] = examinationList.filter(row => row.id === Number(selectedKeys[0])));
+      }
+      if (node.level <= 0 || node.level >= 3) {
+        asyncSMessage('不允许添加该节点的子节点', 'warn');
+        return;
       }
+      dep = {
+        isAdapt: node.isAdapt,
+      };
     }
-    asyncForm('新增', itemList, { parentId: `${node}` }, data => {
-      console.log(data);
+
+    asyncForm('新增', itemList, Object.assign({ parentId: `${node.id}`, parentName: node.title }, dep), data => {
       let handler;
       if (tab === 'exercise') {
         handler = Exercise.addStruct(data);
@@ -205,18 +279,35 @@ export default class extends Page {
     const { tab, exerciseList, examinationList, selectedKeys } = this.state;
     let itemList;
     let node;
+    let dep;
     if (tab === 'exercise') {
       itemList = this.exerciseItemList;
       if (selectedKeys.length > 0) {
-        node = exerciseList.filter(row => row.id === Number(selectedKeys[0]))[0].parentId;
+        ([node] = exerciseList.filter(row => row.id === Number(selectedKeys[0])));
+      }
+      if (node.level <= 2) {
+        asyncSMessage('不允许添加该节点的兄弟节点', 'warn');
+        return;
       }
+      dep = {
+        parentName: this.state.exerciseMap[node.parentId].title,
+      };
     } else {
       itemList = this.examinationItemList;
       if (selectedKeys.length > 0) {
-        node = examinationList.filter(row => row.id === Number(selectedKeys[0]))[0].parentId;
+        ([node] = examinationList.filter(row => row.id === Number(selectedKeys[0])));
+      }
+      if (node.level <= 1) {
+        asyncSMessage('不允许添加该节点的兄弟节点', 'warn');
+        return;
       }
+      dep = {
+        isAdapt: node.isAdapt,
+        parentName: this.state.examinationMap[node.parentId].title,
+      };
     }
-    asyncForm('新增', itemList, { parentId: `${node}` }, data => {
+
+    asyncForm('新增', itemList, Object.assign({ parentId: `${node.parentId}`, parentName: node.title }, dep), data => {
       let handler;
       if (tab === 'exercise') {
         handler = Exercise.addStruct(data);
@@ -233,18 +324,39 @@ export default class extends Page {
   editAction() {
     const { tab, exerciseList, examinationList, selectedKeys } = this.state;
     let itemList;
-    let list;
+    let node;
     if (tab === 'exercise') {
       itemList = this.exerciseItemList;
-      list = exerciseList;
+      ([node] = exerciseList.filter(row => row.id === Number(selectedKeys[0])).map(row => {
+        row.parentId = `${row.parentId}`;
+        return row;
+      }));
+      if (node.level <= 2) {
+        itemList = this.exerciseItemListLimit;
+      }
+      if (node.extend) {
+        asyncSMessage('该节点不允许编辑', 'warn');
+        return;
+      }
+      node.parentName = this.state.exerciseMap[node.parentId].title;
     } else {
       itemList = this.examinationItemList;
-      list = examinationList;
+      ([node] = examinationList.filter(row => row.id === Number(selectedKeys[0])).map(row => {
+        row.parentId = `${row.parentId}`;
+        return row;
+      }));
+      if (node.level <= 1) {
+        itemList = this.examinationItemListLimit;
+      }
+      // 千行可以被修改
+      // if (node.extend) {
+      //   asyncSMessage('该节点不允许编辑', 'warn');
+      //   return;
+      // }
+      node.parentName = this.state.examinationMap[node.parentId].title;
     }
-    asyncForm('编辑', itemList, list.filter(row => row.id === Number(selectedKeys[0])).map(row => {
-      row.parentId = `${row.parentId}`;
-      return row;
-    })[0], data => {
+
+    asyncForm('编辑', itemList, node, data => {
       let handler;
       if (tab === 'exercise') {
         handler = Exercise.editStruct(data);
@@ -281,8 +393,10 @@ export default class extends Page {
         onAction={key => this.onAction(key)} />
       <TreeLayout autoExpandParent defaultExpandAll checkable itemList={this.state.examinationStruct} selectedKeys={this.state.selectedKeys} onSelect={(selectedKeys) => {
         this.setState({ selectedKeys });
-      }} checkedKeys={this.state.checkedKeys} onCheck={(checkedKeys) => {
-        this.setState({ checkedKeys });
+      }} checkedKeys={this.state.checkedKeys} checkStrictly onCheck={(checkedKeys, e) => {
+        if (e.node.props.level > 2) {
+          this.setState({ checkedKeys: { checkedKeys, halfCheckedKeys: e.halfCheckedKeys } });
+        }
       }} />
     </Block>;
   }
@@ -297,8 +411,10 @@ export default class extends Page {
         onAction={key => this.onAction(key)} />
       <TreeLayout autoExpandParent defaultExpandAll checkable itemList={this.state.exerciseStruct} selectedKeys={this.state.selectedKeys} onSelect={(selectedKeys) => {
         this.setState({ selectedKeys });
-      }} checkedKeys={this.state.checkedKeys} onCheck={(checkedKeys) => {
-        this.setState({ checkedKeys });
+      }} checkedKeys={this.state.checkedKeys} checkStrictly onCheck={(checkedKeys, e) => {
+        if (e.node.props.level > 2) {
+          this.setState({ checkedKeys: { checkedKeys, halfCheckedKeys: e.halfCheckedKeys } });
+        }
       }} />
     </Block>;
   }
@@ -307,7 +423,7 @@ export default class extends Page {
     const { tab } = this.state;
     return <Block><Tabs activeKey={tab} onChange={(value) => {
       this.setState({ tab: value, selectedKeys: [], checkedKeys: [] });
-      this.refresh();
+      this.refresh(value);
     }}>
       <Tabs.TabPane tab="练习结构" key="exercise">
         {this.renderExercise()}

+ 4 - 4
front/project/admin/routes/setting/time/page.js

@@ -9,7 +9,7 @@ import { asyncSMessage } from '@src/services/AsyncTools';
 import TableLayout from '@src/layouts/TableLayout';
 import { QuestionDifficult } from '../../../../Constant';
 import { System } from '../../../stores/system';
-import { Examination } from '../../../stores/examination';
+// import { Examination } from '../../../stores/examination';
 import { Exercise } from '../../../stores/exercise';
 
 export default class extends Page {
@@ -112,10 +112,10 @@ export default class extends Page {
   }
 
   structExamination() {
-    return Examination.allStruct().then(result => {
+    return Exercise.allStruct().then(result => {
       const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; return row; });
       this.setState({
-        examinationList: list.filter(row => row.level === 1),
+        examinationList: list.filter(row => row.level === 1 && row.isExamination),
       });
     });
   }
@@ -221,7 +221,7 @@ export default class extends Page {
 
   renderExamination() {
     return <TableLayout
-      columns={this.exerciseColumns}
+      columns={this.examinationColumns}
       list={this.state.exerciseList}
       pagination={false}
       loading={this.props.core.loading}

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

@@ -107,9 +107,9 @@ export default class extends Page {
       },
     }, {
       title: '题型',
-      dataIndex: 'type',
+      dataIndex: 'questionType',
       render: (text, record) => {
-        return QuestionTypeMap[record.question.type] || text;
+        return QuestionTypeMap[record.question.questionType] || text;
       },
     }, {
       title: '练习册',
@@ -216,22 +216,22 @@ export default class extends Page {
       filterForm[3].select = [].concat(...Object.keys(result).map(key => result[key]));
       this.setState({ place: result });
     });
-    bindSearch(filterForm, 'paper_id', this, (search) => {
+    bindSearch(filterForm, 'paperId', this, (search) => {
       return Exercise.listPaper(search);
     }, (row) => {
       return {
         title: row.title,
         value: row.id,
       };
-    }, this.state.search.paper_id ? [Number(this.state.search.paper_id)] : [], null);
-    bindSearch(filterForm, 'question_no_id', this, (search) => {
+    }, this.state.search.paperId ? Number(this.state.search.paperId) : null, null);
+    bindSearch(filterForm, 'questionNoId', this, (search) => {
       return Question.searchNo(search);
     }, (row) => {
       return {
         title: row.no,
         value: row.id,
       };
-    }, this.state.search.question_no_id ? [Number(this.state.search.question_no_id)] : [], null);
+    }, this.state.search.questionNoId ? Number(this.state.search.questionNoId) : null, null);
     this.initAuto();
   }
 

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

@@ -7,6 +7,7 @@ import Select from '@src/components/Select';
 // import FileUpload from '@src/components/FileUpload';
 import { formatFormError, generateSearch, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
+// import { PreviewMode } from '../../../../Constant';
 import QuestionNoList from '../../../components/QuestionNoList';
 import { Preview } from '../../../stores/preview';
 import { User } from '../../../stores/user';
@@ -45,6 +46,7 @@ export default class extends Page {
     handler
       .then(result => {
         const { questionNoIds } = result;
+        result.time = [result.startTime, result.endTime];
         form.setFieldsValue(result);
         generateSearch('userIds', { mode: 'multiple' }, this, (search) => {
           return User.list(search);
@@ -53,7 +55,7 @@ export default class extends Page {
             title: `${row.nickname}(${row.mobile})`,
             value: row.id,
           };
-        }, result.userIds || [], null);
+        }, result.userIds, null);
         this.setState({ questionNoIds });
       });
   }
@@ -63,6 +65,7 @@ export default class extends Page {
     form.validateFields((err) => {
       if (!err) {
         const data = form.getFieldsValue();
+        [data.startTime, data.endTime] = data.time;
         let handler;
         data.questionNoIds = this.state.questionNos.map(row => row.id);
         if (data.id) {

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

@@ -476,7 +476,7 @@ export default class extends Page {
       <h1>题目属性</h1>
       <Form>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
-          {getFieldDecorator('type', {
+          {getFieldDecorator('questionType', {
             rules: [
               { required: true, message: '请选择题型' },
             ],
@@ -492,9 +492,7 @@ export default class extends Page {
               { required: true, message: '请选择考点' },
             ],
           })(
-            <Select select={this.placeList} placeholder='请选择考点' onChange={(v) => {
-              this.refreshPart(v);
-            }} />,
+            <Select select={this.placeList} placeholder='请选择考点' />,
           )}
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='难度'>

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

@@ -46,6 +46,7 @@ export default class extends Page {
     handler
       .then(result => {
         form.setFieldsValue(result);
+        this.setState({ data: result });
       });
   }
 
@@ -55,6 +56,7 @@ export default class extends Page {
       if (!err) {
         const data = form.getFieldsValue();
         data.isTrail = data.isTrail ? 1 : 0;
+        data.isCustomer = data.isCustomer ? 1 : 0;
         data.question.description = data.question.stem.replace(/<[^>]+>/g, '');
         let handler;
         if (data.id) {
@@ -72,12 +74,15 @@ export default class extends Page {
   }
 
   renderTitle() {
+    const { id } = this.params;
+    const { data } = this.state;
     const { getFieldDecorator } = this.props.form;
     return <Block>
       <Form>
         {getFieldDecorator('id')(<input hidden />)}
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目序号'>
-          {getFieldDecorator('no', {
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目序号' help='设定后,不允许修改'>
+          {id && (data.isSystem ? '是' : '否')}
+          {!id && getFieldDecorator('no', {
             rules: [
               { required: true, message: '请输入序号' },
               // {
@@ -92,6 +97,15 @@ export default class extends Page {
             <InputNumber min={1} precision={0} formatter={(v) => parseInt(v, 10) || 1} />,
           )}
         </Form.Item>
+        {/* 不允许修改组卷逻辑 */}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='自定义库' help='打开后,不自动组卷,用于预习作业,设定后,不允许修改'>
+          {id && (data.isSystem ? '是' : '否')}
+          {!id && getFieldDecorator('isCustomer', {
+            valuePropName: 'checked',
+          })(
+            <Switch checkedChildren='on' unCheckedChildren='off' />,
+          )}
+        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='名称'>
           {getFieldDecorator('title', {
             rules: [

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

@@ -1,10 +1,151 @@
 import React from 'react';
+import { Button } from 'antd';
+import { Link } from 'react-router-dom';
 import './index.less';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+// import { asyncSMessage } from '@src/services/AsyncTools';
+import { TextbookType } from '../../../../Constant';
+import { Exercise } from '../../../stores/exercise';
+// import { System } from '../../../stores/system';
+import { Question } from '../../../stores/question';
+// import { Slient } from '../../../stores/slient';
+// import Association from '../../../components/Association';
 
+const TextbookTypeMap = getMap(TextbookType, 'value', 'label');
+
+const filterForm = [
+  {
+    key: 'type',
+    type: 'select',
+    allowClear: true,
+    name: '题型',
+    select: TextbookType,
+    placeholder: '请选择',
+    number: true,
+  },
+  {
+    key: 'paperId',
+    type: 'select',
+    allowClear: true,
+    name: '练习册',
+    select: [],
+    placeholder: '请选择',
+    number: true,
+  },
+  {
+    key: 'questionNoId',
+    type: 'select',
+    allowClear: true,
+    name: '题目ID',
+    select: [],
+    number: true,
+    placeholder: '请输入',
+  },
+];
 export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.actionList = [{
+      key: 'add',
+      name: '新建',
+      render: (item) => {
+        return <Button onClick={() => {
+          linkTo('/subject/textbook/question');
+        }}>{item.name}</Button>;
+      },
+    }];
+    this.categoryMap = {};
+    this.columns = [{
+      title: '题型',
+      dataIndex: 'type',
+      render: (text, record) => {
+        return TextbookTypeMap[record.question.type] || text;
+      },
+    }, {
+      title: '练习册',
+      dataIndex: 'paper',
+      render: (text) => {
+        return text.title;
+      },
+    }, {
+      title: '题目ID',
+      dataIndex: 'title',
+    }, {
+      title: '修改时间',
+      dataIndex: 'updateTime',
+      render: (text, record) => {
+        return formatDate(record.question.updateTime);
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <Link to={`/subject/text/question/${record.id}`}>编辑</Link>
+          )}
+        </div>;
+      },
+    }];
+  }
+
+  init() {
+    bindSearch(filterForm, 'paperId', this, (search) => {
+      return Exercise.listPaper(search);
+    }, (row) => {
+      return {
+        title: row.title,
+        value: row.id,
+      };
+    }, this.state.search.paperId ? Number(this.state.search.paperId) : null, null);
+    bindSearch(filterForm, 'questionNoId', this, (search) => {
+      return Question.searchNo(search);
+    }, (row) => {
+      return {
+        title: row.no,
+        value: row.id,
+      };
+    }, this.state.search.questionNoId ? Number(this.state.search.questionNoId) : null, null);
+  }
+
+  initData() {
+    const { search } = this.state;
+    const data = Object.assign({}, search);
+    Exercise.listQuestion(data).then(result => {
+      this.setTableData(result.list, result.total || 1);
+    });
+  }
+
   renderView() {
-    return <Block flex />;
+    return <Block flex>
+      <FilterLayout
+        show
+        itemList={filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      {/* {this.state.detail && <Association {...this.state.detail} />} */}
+    </Block>;
   }
 }

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

@@ -1,3 +1,39 @@
 @charset "utf-8";
 
-#subject-textbook-question {}
+#subject-textbook-question {
+
+  .ant-row {
+    .anticon-minus-circle-o {
+      position: absolute;
+      right: 10px;
+      top: 11px;
+    }
+
+    .ant-form-item-children>.anticon-minus-circle-o {
+      position: absolute;
+      right: 10px;
+      top: 1px;
+    }
+
+    .ant-checkbox-wrapper {
+      position: absolute;
+      top: 8px;
+    }
+  }
+
+  .drag {
+    .ant-list-item {
+      padding: 0;
+    }
+
+    .ant-list-item-action {
+      width: 100px;
+      padding-bottom: 25px;
+      padding-right: 20px;
+    }
+
+    .ant-col-4 {
+      text-align: center;
+    }
+  }
+}

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

@@ -1,23 +1,36 @@
 import React from 'react';
-import { Form, Input, Tabs, DatePicker } from 'antd';
+import { Form, Input, Tabs, Row, Col, Button, DatePicker, List, Icon, Checkbox } from 'antd';
 import './index.less';
+import DragList from '@src/components/DragList';
+import Editor from '@src/components/Editor';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import Select from '@src/components/Select';
 // import FileUpload from '@src/components/FileUpload';
-import { formatFormError, generateSearch } from '@src/services/Tools';
+import { formatFormError, generateSearch, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
+import { TextbookType, QuestionStyleType } from '../../../../Constant';
 import { Preview } from '../../../stores/preview';
-import { Exercise } from '../../../stores/exercise';
-import { User } from '../../../stores/user';
+import { Textbook } from '../../../stores/textbook';
+import { System } from '../../../stores/system';
 import config from './index';
 
+const QuestionStyleTypeMap = getMap(QuestionStyleType, 'value', 'label');
+
 export default class extends Page {
-  init() {
-    Exercise.allStruct().then(result => {
-      result = result.filter(row => row.level === 2).map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
-      this.setState({ exercise: result });
-    });
+  constructor(props) {
+    super(props);
+    this.placeList = [];
+    this.placeSetting = null;
+    this.uuid = [];
+
+    const { id } = this.params;
+
+    if (id) {
+      config.title = '编辑机经题目';
+    } else {
+      config.title = '添加机经题目';
+    }
   }
 
   initData() {
@@ -25,36 +38,125 @@ export default class extends Page {
     const { form } = this.props;
     let handler;
     if (id) {
-      config.title = '编辑预习作业';
       handler = Preview.get({ id });
     } else {
-      config.title = '添加预习作业';
-      handler = Promise.resolve({});
+      handler = Promise.resolve({ question: { content: { number: 1, type: 'single', typeset: 'one', questions: [], steps: [] } } });
     }
     handler
       .then(result => {
+        const { questionNoIds } = result;
+        result.time = [result.startTime, result.endTime];
+        this.uuid[0] = -1;
+        result.question.content.questions.forEach((row, index) => {
+          const keys = [];
+          this.uuid[index] = 0;
+          if (row.select && row.select.length > 0) {
+            for (; this.uuid[index] < row.select.length; this.uuid[index] += 1) {
+              keys.push(this.uuid[index]);
+              form.getFieldDecorator(`question.content.questions[${index}].select[${this.uuid}]`);
+              form.getFieldDecorator(`question.content.questions[${index}].answer[${this.uuid}]`);
+            }
+            const answerMap = {};
+            row.answer.forEach(r => {
+              answerMap[r] = true;
+            });
+            row.answer = row.select.map(r => answerMap[r] || false);
+          } else if (row.answer && row.answer.length > 0) {
+            for (; this.uuid[index] < row.answer.length; this.uuid[index] += 1) {
+              keys.push(this.uuid);
+              form.getFieldDecorator(`question.content.questions[${index}].answer[${this.uuid}]`);
+            }
+          }
+          form.getFieldDecorator(`question.content.questions[${index}].keys`);
+          row.keys = keys;
+          return row;
+        });
+        result.question.content.steps.forEach((row, index) => {
+          form.getFieldDecorator(`question.content.steps[${index}].title`);
+          form.getFieldDecorator(`question.content.steps[${index}].stem`);
+        });
+
+        form.getFieldDecorator('question.content.step');
+        form.getFieldDecorator('question.content.number');
+        form.getFieldDecorator('question.content.type');
+        form.getFieldDecorator('question.content.typeset');
         form.setFieldsValue(result);
-        generateSearch('userIds', { mode: 'multiple' }, this, (search) => {
-          return User.list(search);
+        generateSearch('setId', {}, this, (search) => {
+          return System.listRank(search);
         }, (row) => {
           return {
-            title: `${row.nickname}(${row.mobile})`,
+            title: row.title,
             value: row.id,
           };
-        }, result.userIds || [], null);
+        }, result.setId, null);
+        this.setState({ questionNoIds });
       });
   }
 
+  refreshPlace(type) {
+    let handler = null;
+    if (this.placeSetting) {
+      handler = Promise.resolve(this.placeSetting);
+    } else {
+      handler = System.getPlace();
+    }
+    handler.then(result => {
+      this.placeSetting = result;
+      this.placeList = result[type] || [];
+    });
+  }
+
+  removeQuestion(index, k) {
+    const { form } = this.props;
+    const keys = form.getFieldValue(`question.content.questions[${index}].keys`);
+    if (keys.length === 1) {
+      return;
+    }
+    form.setFieldsValue({
+      [`question.content.questions[${index}].keys`]: keys.filter(key => key !== k),
+    });
+  }
+
+  addQuestion(index) {
+    const { form } = this.props;
+    const keys = form.getFieldValue(`question.content.questions[${index}].keys`) || [];
+    this.uuid[index] += 1;
+    const nextKeys = keys.concat(this.uuid[index]);
+    form.setFieldsValue({
+      [`question.content.questions[${index}].keys`]: nextKeys,
+    });
+  }
+
+  orderQuestion(index, oldIndex, newIndex) {
+    const { form } = this.props;
+    const keys = form.getFieldValue(`question.content.questions[${index}].keys`) || [];
+    const tmp = keys[oldIndex];
+    keys[oldIndex] = keys[newIndex];
+    keys[newIndex] = tmp;
+    form.setFieldsValue({
+      [`question.content.questions[${index}].keys`]: keys,
+    });
+  }
+
+  changeQuestion(index, k, value) {
+    const { form } = this.props;
+    let answer = form.getFieldValue(`question.content.answer[${index}].single`) || [];
+    answer = answer.map(() => !value);
+    answer[k] = !!value;
+    form.setFieldsValue({ [`question.content.answer[${index}].single`]: answer });
+  }
+
   submit() {
     const { form } = this.props;
     form.validateFields((err) => {
       if (!err) {
         const data = form.getFieldsValue();
+        [data.startTime, data.endTime] = data.time;
         let handler;
         if (data.id) {
-          handler = Preview.edit(data);
+          handler = Textbook.editQuestion(data);
         } else {
-          handler = Preview.add(data);
+          handler = Textbook.addQuestion(data);
         }
         handler.then(() => {
           asyncSMessage('保存成功');
@@ -65,24 +167,12 @@ export default class extends Page {
     });
   }
 
-  searchQuestion(values) {
-    console.log(values);
-  }
-
-  renderBase() {
+  renderAttr() {
     const { getFieldDecorator } = this.props.form;
-    return <Block>
+    return <Block flex>
+      <h1>基本信息</h1>
       <Form>
         {getFieldDecorator('id')(<input hidden />)}
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='选择课程'>
-          {getFieldDecorator('category', {
-            rules: [
-              { required: true, message: '请选择课程' },
-            ],
-          })(
-            <Select select={this.state.exercise} placeholder='请选择课程' />,
-          )}
-        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='起止时间'>
           {getFieldDecorator('time', {
             rules: [
@@ -92,35 +182,179 @@ export default class extends Page {
             <DatePicker.RangePicker />,
           )}
         </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='作业标题'>
-          {getFieldDecorator('title', {
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='换库表'>
+          {getFieldDecorator('setId', {
             rules: [
-              { required: true, message: '请输入作业标题' },
+              { required: true, message: '请选择换库表' },
             ],
           })(
-            <Input placeholder='请输入作业标题' />,
+            <Select {...this.state.setId} placeholder='请选择换库表' />,
           )}
         </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='指定做题人'>
-          {getFieldDecorator('userIds', {
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
+          {getFieldDecorator('question.questionType', {
             rules: [
-              { required: true, message: '请指定做题人' },
+              { required: true, message: '请选择题型' },
             ],
           })(
-            <Select {...this.state.userIds} placeholder='请指定做题人' />,
+            <Select select={TextbookType} placeholder='请选择题型' onChange={(v) => {
+              this.refreshPlace(v);
+            }} />,
           )}
         </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='选择作业题'>
-          {getFieldDecorator('questionIds', {
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='考点'>
+          {getFieldDecorator('question.place', {
             rules: [
-              { required: true, message: '请选择作业题' },
+              { required: true, message: '请选择考点' },
             ],
           })(
-            <Select select={[]} mode='tags' maxTagCount={200} notFoundContent={null} placeholder='输入题目id, 逗号分隔' tokenSeparators={[',', ',']} onSelect={(values) => {
-              this.searchQuestion(values);
+            <Select select={this.placeList} placeholder='请选择考点' onChange={(v) => {
+              this.refreshPart(v);
             }} />,
           )}
         </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目id'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入题目id' },
+            ],
+          })(
+            <Input placeholder='请输入题目id' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderBase() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <h1>题干信息</h1>
+      <Form>
+        {getFieldDecorator('question.id')(<input hidden />)}
+        {getFieldDecorator('question.stem', {
+        })(
+          <Editor modules={{
+            toolbar: {
+              container: [
+                ['image'],
+                [{ header: '1' }, { header: '2' }],
+                ['bold', 'underline', 'blockquote'],
+                [{ list: 'ordered' }, { list: 'bullet' }, { indent: '-1' }, { indent: '+1' }],
+              ],
+              handlers: {
+              },
+            },
+          }} placeholder='请输入内容' onUpload={(file) => System.uploadImage(file)} />,
+        )}
+
+        {getFieldDecorator('question.content.type')(<input hidden />)}
+        {getFieldDecorator('question.content.number')(<input hidden />)}
+        {getFieldDecorator('question.content.typeset')(<input hidden />)}
+      </Form>
+    </Block>;
+  }
+
+  renderSelect() {
+    const { getFieldDecorator, getFieldValue } = this.props.form;
+    const number = getFieldValue('question.content.number');
+    const type = getFieldValue('question.content.type');
+    const result = [];
+    let handler = null;
+    switch (type) {
+      case 'single':
+        handler = (index) => this.renderSelectSingle(index);
+        break;
+      default:
+    }
+    for (let index = 0; index < Number(number); index += 1) {
+      result.push(<Block flex className={type}>
+        <h1>选项信息({QuestionStyleTypeMap[type]})</h1>
+        <Form>
+          {type !== 'inline' && (
+            <Form.Item>
+              {getFieldDecorator(`question.content.questions[${index}].description`, {
+              })(
+                <Editor placeholder='选项问题说明' />,
+              )}
+            </Form.Item>
+          )}
+          {handler(index)}
+        </Form>
+      </Block>);
+    }
+    return result;
+  }
+
+  renderSelectSingle(index) {
+    const { getFieldDecorator, getFieldValue } = this.props.form;
+    getFieldDecorator(`question.content.questions[${index}].keys`);
+    const keys = getFieldValue(`question.content.questions[${index}].keys`) || [];
+    return [
+      <DragList
+        loading={false}
+        dataSource={keys || []}
+        handle={'.icon'}
+        onMove={(oldIndex, newIndex) => {
+          this.orderQuestion(index, oldIndex, newIndex);
+        }}
+        renderItem={(k) => (
+          <List.Item actions={[<Icon type='bars' className='icon' />]}>
+            <Row key={k} style={{ width: '100%' }}>
+              <Col span={1}>
+                {getFieldDecorator(`question.answer.questions[${index}].single[${k}]`, {
+                  valuePropName: 'checked',
+                })(
+                  <Checkbox onChange={(value) => {
+                    this.changeQuestion(index, k, value);
+                  }} />,
+                )}
+              </Col>
+              <Col span={23}>
+                <Form.Item
+                  key={k}
+                  hidden
+                >
+                  {getFieldDecorator(`question.content.questions[${index}].select[${k}]`, {
+                    rules: [{
+                      required: true,
+                      whitespace: true,
+                      message: '请填写选项信息',
+                    }],
+                  })(
+                    <Input />,
+                  )}
+                  {keys.length > 1 ? (
+                    <Icon
+                      type='minus-circle-o'
+                      disabled={keys.length === 1}
+                      onClick={() => this.removeQuestion(index, k)}
+                    />
+                  ) : null}
+                </Form.Item>
+              </Col>
+            </Row>
+          </List.Item>
+        )}
+      />,
+      <Form.Item>
+        <Button type='dashed' onClick={() => this.addQuestion(index)} >
+          <Icon type='plus' /> 新增
+      </Button>
+      </Form.Item>,
+    ];
+  }
+
+  renderQX() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='千行解析'>
+          {getFieldDecorator('qxContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
       </Form>
     </Block>;
   }
@@ -146,6 +380,17 @@ export default class extends Page {
   renderView() {
     return <div flex >
       {this.renderTab()}
+      {this.renderAttr()}
+      {this.renderBase()}
+      {this.renderSelect()}
+      {this.renderQX()}
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
     </div>;
   }
 }

+ 21 - 4
front/project/admin/routes/user/ask/page.js

@@ -7,6 +7,7 @@ import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
 import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget } from '../../../../Constant';
 import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
@@ -16,6 +17,12 @@ const AskStatusMap = getMap(AskStatus, 'value', 'label');
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
 export default class extends Page {
   init() {
+    this.actionList = [{
+      key: 'ignore',
+      type: 'danger',
+      name: '批量忽略',
+      needSelect: 1,
+    }];
     this.filterForm = [{
       key: 'type',
       type: 'select',
@@ -120,22 +127,22 @@ export default class extends Page {
         },
       },
     ];
-    bindSearch(this.filterForm, 'user_id', this, (search) => {
+    bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);
     }, (row) => {
       return {
         title: `${row.nickname}(${row.mobile})`,
         value: row.id,
       };
-    }, this.state.search.user_id ? [Number(this.state.search.user_id)] : [], null);
-    bindSearch(this.filterForm, 'question_no_id', this, (search) => {
+    }, this.state.search.userId ? Number(this.state.search.userId) : [], null);
+    bindSearch(this.filterForm, 'questionNoId', this, (search) => {
       return Question.searchNo(search);
     }, (row) => {
       return {
         title: row.no,
         value: row.id,
       };
-    }, this.state.search.question_no_id ? [Number(this.state.search.question_no_id)] : [], null);
+    }, this.state.search.questionNoId ? Number(this.state.search.questionNoId) : [], null);
   }
 
   initData() {
@@ -144,6 +151,16 @@ export default class extends Page {
     });
   }
 
+  ignoreAction() {
+    const { selectedKeys } = this.state;
+    asyncDelConfirm('忽略确认', '是否忽略选中提问?', () => {
+      return Promise.all(selectedKeys.map(row => User.editAsk({ id: row, answerStatus: 2 })));
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.refresh();
+    });
+  }
+
   renderView() {
     return <Block flex>
       <FilterLayout

+ 26 - 6
front/project/admin/routes/user/askDetail/page.js

@@ -42,11 +42,25 @@ export default class extends Page {
 
   orderQuestion(oldIndex, newIndex) {
     const { data } = this.state;
-    const { other = [] } = data;
-    const tmp = other[oldIndex];
-    other[oldIndex] = other[newIndex];
-    other[newIndex] = tmp;
-    this.setState({ other });
+    const { others = [] } = data;
+    const tmp = others[oldIndex];
+    others[oldIndex] = others[newIndex];
+    others[newIndex] = tmp;
+    this.setState({ others });
+  }
+
+  addOrder() {
+    const { data } = this.state;
+    const { others } = data;
+    others.push(data);
+    this.setState({ data });
+  }
+
+  removeOrder() {
+    const { data } = this.state;
+    const { others } = data;
+    data.others = others.filter(row => row.id !== data.id);
+    this.setState({ data });
   }
 
   submit() {
@@ -140,7 +154,13 @@ export default class extends Page {
               {getFieldDecorator('showStatus', {
                 valuePropName: 'checked',
               })(
-                <Switch checkedChildren='on' unCheckedChildren='off' />,
+                <Switch onChange={(value) => {
+                  if (value) {
+                    this.addOrder();
+                  } else {
+                    this.removeOrder();
+                  }
+                }} checkedChildren='on' unCheckedChildren='off' />,
               )}
             </Form.Item>
           </Col>

+ 15 - 0
front/project/admin/routes/user/examination/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/user/examination',
+  key: 'user-examination',
+  title: '模考记录',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/user/examination/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#user-examination {}

+ 10 - 0
front/project/admin/routes/user/examination/page.js

@@ -0,0 +1,10 @@
+import React from 'react';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+
+export default class extends Page {
+  renderView() {
+    return <Block flex />;
+  }
+}

+ 180 - 1
front/project/admin/routes/user/feedback/page.js

@@ -1,10 +1,189 @@
 import React from 'react';
+import { Modal, Button } from 'antd';
 import './index.less';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, formatDate } from '@src/services/Tools';
+import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
+import { FeedbackStatus, FeedbackModule } from '../../../../Constant';
+import { User } from '../../../stores/user';
 
+const FeedbackStatusMap = getMap(FeedbackStatus, 'value', 'label');
+const FeedbackModuleMap = getMap(FeedbackModule, 'value', 'label');
 export default class extends Page {
+  init() {
+    this.actionList = [{
+      key: 'handle',
+      type: 'danger',
+      name: '批量处理',
+      needSelect: 1,
+    }, {
+      key: 'ignore',
+      type: 'danger',
+      name: '批量忽略',
+      needSelect: 1,
+    }];
+    this.filterForm = [{
+      key: 'module',
+      type: 'select',
+      allowClear: true,
+      name: '类型',
+      select: FeedbackModule,
+      placeholder: '请选择',
+    }, {
+      key: 'status',
+      type: 'select',
+      allowClear: true,
+      name: '状态',
+      select: FeedbackStatus,
+    }, {
+      key: 'title',
+      type: 'input',
+      name: '材料名称',
+      allowClear: true,
+      placeholder: '输入名称搜索',
+    }];
+    this.columns = [
+      {
+        title: '类型',
+        dataIndex: 'module',
+        render: (text) => {
+          return FeedbackModuleMap[text];
+        },
+      },
+      {
+        title: '提交时间',
+        dataIndex: 'createTime',
+        render: (text) => {
+          return formatDate(text);
+        },
+      },
+      {
+        title: '提问者',
+        dataIndex: 'user.nickname',
+      },
+      {
+        title: '材料名称',
+        dataIndex: 'title',
+      }, {
+        title: '处理状态',
+        dataIndex: 'status',
+        render: (text) => {
+          return FeedbackStatusMap[text] || text;
+        },
+      }, {
+        title: '操作',
+        dataIndex: 'handler',
+        render: (text, record) => {
+          return <div className="table-button">
+            {(
+              <a onClick={() => {
+                this.detailAction(record);
+              }}>编辑</a>
+            )}
+          </div>;
+        },
+      },
+    ];
+  }
+
+  initData() {
+    User.listFeedbackError(this.state.search).then(result => {
+      result.list = result.list.map(row => {
+        row.position = row.position.split(',');
+        return row;
+      });
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  detailAction(row) {
+    this.setState({ detail: row });
+  }
+
+  handleDetail() {
+    const { detail } = this.state;
+    asyncDelConfirm('处理确认', '是否处理选中记录?', () => {
+      return User.editFeedbackError({ id: detail.id, status: 1 });
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.setState({ detail: null });
+      this.refresh();
+    });
+  }
+
+  ignoreDetail() {
+    const { detail } = this.state;
+    asyncDelConfirm('忽略确认', '是否忽略选中记录?', () => {
+      return User.editFeedbackError({ id: detail.id, status: 2 });
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.setState({ detail: null });
+      this.refresh();
+    });
+  }
+
+  handleAction() {
+    const { selectedKeys } = this.state;
+    asyncDelConfirm('处理确认', '是否处理选中记录?', () => {
+      return Promise.all(selectedKeys.map(row => User.editFeedbackError({ id: row, status: 1 })));
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.refresh();
+    });
+  }
+
+  ignoreAction() {
+    const { selectedKeys } = this.state;
+    asyncDelConfirm('忽略确认', '是否忽略选中记录?', () => {
+      return Promise.all(selectedKeys.map(row => User.editFeedbackError({ id: row, status: 2 })));
+    }).then(() => {
+      asyncSMessage('操作成功!');
+      this.refresh();
+    });
+  }
+
   renderView() {
-    return <Block flex />;
+    return <Block flex>
+      <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      {this.state.detail && <Modal visible title='勘误详情' footer={null} closable onCancel={() => {
+        this.setState({ detail: null });
+      }}>
+        <p>类型:{FeedbackModuleMap[this.state.detail.module]}</p>
+        <p>材料名称:{this.state.detail.title}</p>
+        {this.state.detail.position.length > 0 && <p>错误位置:{this.state.detail.position[0]}页,{this.state.detail.position[1]}行</p>}
+        <p>错误内容:{this.state.detail.originContent}</p>
+        <p>应修改为:{this.state.detail.content}</p>
+        <p><Button type="primary" onClick={() => {
+          this.handleDetail();
+        }}>已处理</Button><Button type="ghost" onClick={() => {
+          this.ignoreDetail();
+        }}>忽略</Button></p>
+      </Modal>}
+    </Block>;
   }
 }

+ 3 - 1
front/project/admin/routes/user/index.js

@@ -4,7 +4,9 @@ import ask from './ask';
 import askDetail from './askDetail';
 import preview from './preview';
 import exercise from './exercise';
+import examination from './examination';
+import student from './student';
 import pay from './pay';
 import feedback from './feedback';
 
-export default [list, detail, ask, askDetail, preview, exercise, pay, feedback];
+export default [list, detail, ask, askDetail, preview, exercise, examination, student, pay, feedback];

+ 4 - 4
front/project/admin/routes/user/preview/page.js

@@ -58,13 +58,13 @@ export default class extends Page {
     ];
     this.columns = [{
       title: '用户id',
-      dataIndex: 'user_id',
+      dataIndex: 'userId',
       render: (text, record) => {
         return record.user.id;
       },
     }, {
       title: '用户名称',
-      dataIndex: 'user_realname',
+      dataIndex: 'user.realName',
       render: (text, record) => {
         return record.user.realName;
       },
@@ -120,14 +120,14 @@ export default class extends Page {
       this.categoryMap = getMap(this.filterForm[0].select, 'id', 'title');
       this.setState({ exercise: result });
     });
-    bindSearch(this.filterForm, 'user_id', this, (search) => {
+    bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);
     }, (row) => {
       return {
         title: `${row.nickname}(${row.mobile})`,
         value: row.id,
       };
-    }, this.state.search.user_id ? [Number(this.state.search.user_id)] : [], null);
+    }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
     this.refreshPreview();
   }
 

+ 15 - 0
front/project/admin/routes/user/student/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/user/student',
+  key: 'user-student',
+  title: '学员管理',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/user/student/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#user-student {}

+ 132 - 0
front/project/admin/routes/user/student/page.js

@@ -0,0 +1,132 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+// import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, formatMoney } from '@src/services/Tools';
+import { SwitchSelect, ServiceKey } from '../../../../Constant';
+import { User } from '../../../stores/user';
+
+const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
+const ServiceKeyMap = getMap(ServiceKey, 'value', 'label');
+export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.filterF = null;
+  }
+
+  init() {
+    this.filterForm = [
+      {
+        key: 'keyword',
+        type: 'input',
+        name: 'ID/手机号',
+        placeholder: '请输入',
+      },
+      {
+        key: 'real',
+        type: 'select',
+        allowClear: true,
+        name: '实名认证',
+        select: SwitchSelect,
+        placeholder: '请选择',
+        number: true,
+      },
+    ];
+    this.columns = [
+      {
+        title: 'ID',
+        dataIndex: 'id',
+      },
+      {
+        title: '手机号',
+        dataIndex: 'mobile',
+      },
+      {
+        title: '注册时间',
+        dataIndex: 'createTime',
+      },
+      {
+        title: '实名认证',
+        dataIndex: 'realStatus',
+        render: (text) => {
+          return SwitchSelectMap[text ? 1 : 0];
+        },
+      },
+      {
+        title: '备考信息',
+        dataIndex: 'prepareStatus',
+        render: (text) => {
+          return SwitchSelectMap[text ? 1 : 0];
+        },
+      }, {
+        title: '邀请人数',
+        dataIndex: 'inviteNumber',
+      }, {
+        title: '学习时长',
+        dataIndex: 'time',
+      }, {
+        title: '服务中',
+        dataIndex: 'services',
+        render: (text) => {
+          return (text || []).map(row => ServiceKeyMap[row.service]).join(', ');
+        },
+      }, {
+        title: '消费金额',
+        dataIndex: 'totalMoney',
+        render: (text) => {
+          return formatMoney(text);
+        },
+      }, {
+        title: '操作',
+        dataIndex: 'handler',
+        render: (text, record) => {
+          return <div className="table-button">
+            {(
+              <Link to={`/user/detail/${record.id}`}>查看</Link>
+            )}
+          </div>;
+        },
+      },
+    ];
+  }
+
+  initData() {
+    User.list(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  renderView() {
+    return <Block flex>
+      <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }}
+        ref={(ref) => {
+          if (ref) this.filterF = ref;
+        }} />
+      {/* <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      /> */}
+      <TableLayout
+        // select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+    </Block>;
+  }
+}

+ 8 - 4
front/project/admin/stores/system.js

@@ -78,19 +78,23 @@ export default class SystemStore extends BaseStore {
   }
 
   listRank(params) {
-    return this.apiGet('/rank/list', params);
+    return this.apiGet('/setting/rank/list', params);
   }
 
   addRank(params) {
-    return this.apiPost('/rank/add', params);
+    return this.apiPost('/setting/rank/add', params);
   }
 
   editRank(params) {
-    return this.apiPut('/rank/edit', params);
+    return this.apiPut('/setting/rank/edit', params);
   }
 
   delRank(params) {
-    return this.apiDel('/rank/delete', params);
+    return this.apiDel('/setting/rank/delete', params);
+  }
+
+  importRank(params) {
+    return this.apiForm('/setting/rank/import', params);
   }
 
   uploadImage(file) {

+ 33 - 0
front/project/admin/stores/textbook.js

@@ -0,0 +1,33 @@
+import BaseStore from '@src/stores/base';
+
+export default class TextbookStore extends BaseStore {
+  listQuestion(params) {
+    return this.apiGet('/textbook/question/list', params);
+  }
+
+  getQuestion(params) {
+    return this.apiGet('/textbook/question/detail', params);
+  }
+
+  addQuestion(params) {
+    return this.apiPost('/textbook/question/add', params);
+  }
+
+  editQuestion(params) {
+    return this.apiPut('/textbook/question/edit', params);
+  }
+
+  delQuestion(params) {
+    return this.apiDel('/textbook/question/delete', params);
+  }
+
+  searchNo(params) {
+    return this.apiPost('/textbook/search/no', params);
+  }
+
+  listPaper(params) {
+    return this.apiGet('/textbook/paper/list', params);
+  }
+}
+
+export const Textbook = new TextbookStore({ key: 'textbook' });

+ 14 - 2
front/src/services/AsyncTools.js

@@ -57,8 +57,20 @@ export function asyncDelConfirm(title, content, cb) {
   return asyncModalConfirm({ title, content, okType: 'danger', maskClosable: true }, cb);
 }
 
-export function asyncSMessage(title) {
+export function asyncSMessage(title, type = 'success') {
   return getAsyncAntd().then(({ Message }) => {
-    Message.success(title);
+    switch (type) {
+      case 'warn':
+      case 'warning':
+        Message.warning(title);
+        break;
+      case 'error':
+        Message.error(title);
+        break;
+      case 'success':
+      default:
+        Message.success(title);
+        break;
+    }
   });
 }

+ 10 - 1
front/src/services/Tools.js

@@ -359,7 +359,11 @@ export function bindSearch(targetList, field, Component, listFunc, render, def,
   };
   targetList[index] = Object.assign(targetList[index], item);
   if (def) {
-    searchFunc({ ids: def, page: 1, number: def.length });
+    if (targetList[index].type === 'multiple') {
+      searchFunc({ ids: def, page: 1, number: def.length });
+    } else {
+      searchFunc({ ids: [def], page: 1, number: 1 });
+    }
   } else {
     item.onSearch();
   }
@@ -394,6 +398,11 @@ export function generateSearch(field, prop, Component, listFunc, render, def, no
   };
   item = Object.assign(prop || {}, item);
   if (def) {
+    if (item.type === 'multiple') {
+      searchFunc({ ids: def, page: 1, number: def.length });
+    } else {
+      searchFunc({ ids: [def], page: 1, number: 1 });
+    }
     searchFunc({ ids: def, page: 1, number: def.length });
   } else {
     item.onSearch();

+ 27 - 6
server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionGroup.java

@@ -4,14 +4,12 @@ package com.qxgmat.data.constants.enums;
  * Created by gaojie on 2017/11/19.
  */
 public enum QuestionGroup {
-    SC("sc", "语法"),
-    RC("rc", "阅读"),
-    CR("cr","逻辑"),
-    PS("ps", "数学"),
-    DS("ds", "数学"),
+    VERBAL("verbal", "语文"),
+    QUANT("quant", "数学"),
     IR("ir", "综合推理"),
     AWA("awa", "作文");
-    final static public String message = "题目类型";
+
+    final static public String message = "考试结构:学科";
 
     public String key;
     public String title;
@@ -24,4 +22,27 @@ public enum QuestionGroup {
         if (name == null) return null;
         return QuestionGroup.valueOf(name.toUpperCase());
     }
+
+    /**
+     * 通过题型获取到学科
+     * @param type
+     * @return
+     */
+    public static QuestionGroup FromType(QuestionType type){
+        switch(type){
+            case SC:
+            case RC:
+            case CR:
+                return VERBAL;
+            case PS:
+            case DS:
+                return QUANT;
+            case IR:
+                return IR;
+            case AWA:
+                return AWA;
+            default:
+                return null;
+        }
+    }
 }

+ 2 - 2
server/data/src/main/java/com/qxgmat/data/constants/enums/QuestionType.java

@@ -7,8 +7,8 @@ public enum QuestionType {
     SC("sc", "语法"),
     RC("rc", "阅读"),
     CR("cr","逻辑"),
-    PS("ps", "数学"),
-    DS("ds", "数学"),
+    PS("ps", "数学PS"),
+    DS("ds", "数学DS"),
     IR("ir", "综合推理"),
     AWA("awa", "作文");
     final static public String message = "题目类型";

+ 1 - 16
server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java

@@ -17,6 +17,7 @@ public enum SettingKey {
     EXERCISE_PAPER_AUTO("exercise_paper_auto"), // 自动组卷设置
     EXERCISE_PAPER_STATUS("exercise_paper_status"), // 练习自动组卷状态:process进度,finish时间
     PREPARE_INFO("prepare_info"), // 备考统计信息
+    SENTENCE_TIME("sentence_time"), // 长难句题目时间
 
     TIPS("tips"); // 页面提示信息
 
@@ -26,20 +27,4 @@ public enum SettingKey {
     private SettingKey(String key){
         this.key = key;
     }
-
-    /**
-     * 根据组卷模块获取对应时间
-     * @param module
-     * @return
-     */
-    public static SettingKey getTimeByPaperModule(PaperModule module){
-        switch (module){
-            case EXAMINATION:
-                return EXAMINATION_TIME;
-            case EXERCISE:
-                return EXERCISE_TIME;
-            default:
-                return null;
-        }
-    }
 }

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

@@ -0,0 +1,14 @@
+package com.qxgmat.data.constants.enums.logic;
+
+public enum TextbookLogic {
+    DS("ds"), PS("ps"), DS_PS("ds+ps");
+    public String key;
+    private TextbookLogic(String key){
+        this.key = key;
+    }
+
+    public static TextbookLogic ValueOf(String name){
+        if (name == null) return null;
+        return TextbookLogic.valueOf(name.toUpperCase());
+    }
+}

+ 16 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/module/FeedbackModule.java

@@ -0,0 +1,16 @@
+package com.qxgmat.data.constants.enums.module;
+
+public enum FeedbackModule {
+    QUESTION("question"),
+    DATA("data"),
+    ;
+    public String key;
+    private FeedbackModule(String key){
+        this.key = key;
+    }
+
+    public static FeedbackModule ValueOf(String name){
+        if (name == null) return null;
+        return FeedbackModule.valueOf(name.toUpperCase());
+    }
+}

+ 25 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/status/FeedbackStatus.java

@@ -0,0 +1,25 @@
+package com.qxgmat.data.constants.enums.status;
+
+
+public enum FeedbackStatus {
+    NEW(0), HANDLE(1), IGNORE(2);
+    final static public String message = "状态:0新增,1处理,2忽略";
+
+    public int index;
+    private FeedbackStatus(int index){
+        this.index = index;
+    }
+    public static FeedbackStatus ValueOf(Integer index){
+        if (index == null) return null;
+        switch (index){
+            case 0:
+                return NEW;
+            case 1:
+                return HANDLE;
+            case 2:
+                return IGNORE;
+            default:
+                return null;
+        }
+    }
+}

+ 13 - 2
server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayChannel.java

@@ -4,11 +4,22 @@ package com.qxgmat.data.constants.enums.trade;
  * Created by gaojie on 2017/11/20.
  */
 public enum PayChannel {
-    OFFLINE("offline"), ALIPAY("alipay"), WECHAT("wechat");
-    final static public String message = "支付类型";
+    OFFLINE("offline"),
+    ALIPAY_QR("alipay_qr"),
+    ALIPAY_APP("alipay_app"),
+    WECHAT_QR("wechat_qr"),
+    WECHAT_APP("wechat_app"),
+    WECHAT_JS("wechat_js"),
+    ;
+    final static public String message = "支付渠道";
 
     public String key ;
     private PayChannel(String value){
         this.key = value;
     }
+
+    public static PayChannel ValueOf(String name){
+        if (name == null) return null;
+        return PayChannel.valueOf(name.toUpperCase());
+    }
 }

+ 28 - 5
server/data/src/main/java/com/qxgmat/data/constants/enums/trade/PayType.java

@@ -4,11 +4,34 @@ package com.qxgmat.data.constants.enums.trade;
  * Created by gaojie on 2017/11/20.
  */
 public enum PayType {
-    ACCOUNT(1), ALIPAY(2), WECHAT(3);
-    final static public String message = "工具类型: 1账户, 2支付宝, 3微信";
+    CASH("cash"),
+    ALIPAY("alipay"),
+    WECHAT("wechat")
+    ;
+    final static public String message = "支付类型";
 
-    public int index ;
-    private PayType(int value){
-        this.index = value;
+    public String key ;
+    private PayType(String value){
+        this.key = value;
+    }
+
+    public static PayType ValueOf(String name){
+        if (name == null) return null;
+        return PayType.valueOf(name.toUpperCase());
+    }
+
+    public static PayType FromChannel(PayChannel channel){
+        if (channel == null) return null;
+        switch (channel){
+            case ALIPAY_APP:
+            case ALIPAY_QR:
+                return PayType.ALIPAY;
+            case WECHAT_APP:
+            case WECHAT_QR:
+                return PayType.WECHAT;
+            case OFFLINE:
+            default:
+                return PayType.CASH;
+        }
     }
 }

+ 7 - 0
server/data/src/main/java/com/qxgmat/data/dao/ClassCommentMapper.java

@@ -0,0 +1,7 @@
+package com.qxgmat.data.dao;
+
+import com.nuliji.tools.mybatis.Mapper;
+import com.qxgmat.data.dao.entity.ClassComment;
+
+public interface ClassCommentMapper extends Mapper<ClassComment> {
+}

+ 7 - 0
server/data/src/main/java/com/qxgmat/data/dao/ClassCourseNoMapper.java

@@ -0,0 +1,7 @@
+package com.qxgmat.data.dao;
+
+import com.nuliji.tools.mybatis.Mapper;
+import com.qxgmat.data.dao.entity.ClassCourseNo;
+
+public interface ClassCourseNoMapper extends Mapper<ClassCourseNo> {
+}

+ 7 - 0
server/data/src/main/java/com/qxgmat/data/dao/ClassFaqMapper.java

@@ -0,0 +1,7 @@
+package com.qxgmat.data.dao;
+
+import com.nuliji.tools.mybatis.Mapper;
+import com.qxgmat.data.dao.entity.ClassFaq;
+
+public interface ClassFaqMapper extends Mapper<ClassFaq> {
+}

+ 7 - 0
server/data/src/main/java/com/qxgmat/data/dao/UserCourseMapper.java

@@ -0,0 +1,7 @@
+package com.qxgmat.data.dao;
+
+import com.nuliji.tools.mybatis.Mapper;
+import com.qxgmat.data.dao.entity.UserCourse;
+
+public interface UserCourseMapper extends Mapper<UserCourse> {
+}

+ 63 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ClassComment.java

@@ -0,0 +1,63 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import javax.persistence.*;
+
+@Table(name = "class_comment")
+public class ClassComment implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ClassComment.Builder builder() {
+        return new ClassComment.Builder();
+    }
+
+    public static class Builder {
+        private ClassComment obj;
+
+        public Builder() {
+            this.obj = new ClassComment();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        public ClassComment build() {
+            return this.obj;
+        }
+    }
+}

+ 63 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ClassCourseNo.java

@@ -0,0 +1,63 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import javax.persistence.*;
+
+@Table(name = "class_course_no")
+public class ClassCourseNo implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ClassCourseNo.Builder builder() {
+        return new ClassCourseNo.Builder();
+    }
+
+    public static class Builder {
+        private ClassCourseNo obj;
+
+        public Builder() {
+            this.obj = new ClassCourseNo();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        public ClassCourseNo build() {
+            return this.obj;
+        }
+    }
+}

+ 168 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ClassFaq.java

@@ -0,0 +1,168 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import javax.persistence.*;
+
+@Table(name = "class_faq")
+public class ClassFaq implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    /**
+     * 是否精选:0不是精选,1是精选
+     */
+    @Column(name = "`is_special`")
+    private Integer isSpecial;
+
+    /**
+     * 问答状态:0未回答,1回答,忽略
+     */
+    @Column(name = "`status`")
+    private Integer status;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取课程id
+     *
+     * @return course_id - 课程id
+     */
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    /**
+     * 设置课程id
+     *
+     * @param courseId 课程id
+     */
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    /**
+     * 获取是否精选:0不是精选,1是精选
+     *
+     * @return is_special - 是否精选:0不是精选,1是精选
+     */
+    public Integer getIsSpecial() {
+        return isSpecial;
+    }
+
+    /**
+     * 设置是否精选:0不是精选,1是精选
+     *
+     * @param isSpecial 是否精选:0不是精选,1是精选
+     */
+    public void setIsSpecial(Integer isSpecial) {
+        this.isSpecial = isSpecial;
+    }
+
+    /**
+     * 获取问答状态:0未回答,1回答,忽略
+     *
+     * @return status - 问答状态:0未回答,1回答,忽略
+     */
+    public Integer getStatus() {
+        return status;
+    }
+
+    /**
+     * 设置问答状态:0未回答,1回答,忽略
+     *
+     * @param status 问答状态:0未回答,1回答,忽略
+     */
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", courseId=").append(courseId);
+        sb.append(", isSpecial=").append(isSpecial);
+        sb.append(", status=").append(status);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ClassFaq.Builder builder() {
+        return new ClassFaq.Builder();
+    }
+
+    public static class Builder {
+        private ClassFaq obj;
+
+        public Builder() {
+            this.obj = new ClassFaq();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置课程id
+         *
+         * @param courseId 课程id
+         */
+        public Builder courseId(Integer courseId) {
+            obj.setCourseId(courseId);
+            return this;
+        }
+
+        /**
+         * 设置是否精选:0不是精选,1是精选
+         *
+         * @param isSpecial 是否精选:0不是精选,1是精选
+         */
+        public Builder isSpecial(Integer isSpecial) {
+            obj.setIsSpecial(isSpecial);
+            return this;
+        }
+
+        /**
+         * 设置问答状态:0未回答,1回答,忽略
+         *
+         * @param status 问答状态:0未回答,1回答,忽略
+         */
+        public Builder status(Integer status) {
+            obj.setStatus(status);
+            return this;
+        }
+
+        public ClassFaq build() {
+            return this.obj;
+        }
+    }
+}

+ 243 - 59
server/data/src/main/java/com/qxgmat/data/dao/entity/ExaminationPaper.java

@@ -10,26 +10,29 @@ public class ExaminationPaper implements Serializable {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
-    @Column(name = "`struct_id`")
-    private Integer structId;
+    /**
+     * 试卷组
+     */
+    @Column(name = "`struct_two`")
+    private Integer structTwo;
 
     /**
-     * 标题
+     * 考卷
      */
-    @Column(name = "`title`")
-    private String title;
+    @Column(name = "`struct_three`")
+    private Integer structThree;
 
     /**
-     * 题目数量
+     * 是否适应难度
      */
-    @Column(name = "`question_number`")
-    private Integer questionNumber;
+    @Column(name = "`is_adapt`")
+    private Integer isAdapt;
 
     /**
-     * 题目编号ids:json
+     * 
      */
-    @Column(name = "`question_no_ids`")
-    private Integer[] questionNoIds;
+    @Column(name = "`title`")
+    private String title;
 
     /**
      * 开放状态:0关闭,1开启
@@ -37,6 +40,36 @@ public class ExaminationPaper implements Serializable {
     @Column(name = "`status`")
     private Integer status;
 
+    /**
+     * 总分
+     */
+    @Column(name = "`total_score`")
+    private Integer totalScore;
+
+    /**
+     * 总做卷次数
+     */
+    @Column(name = "`total_times`")
+    private Integer totalTimes;
+
+    /**
+     * 总Q分
+     */
+    @Column(name = "`quant_score`")
+    private Integer quantScore;
+
+    /**
+     * 总V分
+     */
+    @Column(name = "`verbal_score`")
+    private Integer verbalScore;
+
+    /**
+     * 总ir分
+     */
+    @Column(name = "`ir_score`")
+    private Integer irScore;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -54,71 +87,75 @@ public class ExaminationPaper implements Serializable {
     }
 
     /**
-     * @return struct_id
+     * 获取试卷组
+     *
+     * @return struct_two - 试卷组
      */
-    public Integer getStructId() {
-        return structId;
+    public Integer getStructTwo() {
+        return structTwo;
     }
 
     /**
-     * @param structId
+     * 设置试卷组
+     *
+     * @param structTwo 试卷组
      */
-    public void setStructId(Integer structId) {
-        this.structId = structId;
+    public void setStructTwo(Integer structTwo) {
+        this.structTwo = structTwo;
     }
 
     /**
-     * 获取标题
+     * 获取考卷
      *
-     * @return title - 标题
+     * @return struct_three - 考卷
      */
-    public String getTitle() {
-        return title;
+    public Integer getStructThree() {
+        return structThree;
     }
 
     /**
-     * 设置标题
+     * 设置考卷
      *
-     * @param title 标题
+     * @param structThree 考卷
      */
-    public void setTitle(String title) {
-        this.title = title;
+    public void setStructThree(Integer structThree) {
+        this.structThree = structThree;
     }
 
     /**
-     * 获取题目数量
+     * 获取是否适应难度
      *
-     * @return question_number - 题目数量
+     * @return is_adapt - 是否适应难度
      */
-    public Integer getQuestionNumber() {
-        return questionNumber;
+    public Integer getIsAdapt() {
+        return isAdapt;
     }
 
     /**
-     * 设置题目数量
+     * 设置是否适应难度
      *
-     * @param questionNumber 题目数量
+     * @param isAdapt 是否适应难度
      */
-    public void setQuestionNumber(Integer questionNumber) {
-        this.questionNumber = questionNumber;
+    public void setIsAdapt(Integer isAdapt) {
+        this.isAdapt = isAdapt;
     }
 
     /**
-     * 获取题目编号ids:json
+     * 获取
      *
-     * @return question_no_ids - 题目编号ids:json
+     * @return title - 标题
      */
-    public Integer[] getQuestionNoIds() {
-        return questionNoIds;
+    public String getTitle() {
+        return title;
     }
 
     /**
-     * 设置题目编号ids:json
+     * 设置
      *
-     * @param questionNoIds 题目编号ids:json
+     * @param title 标题
      */
-    public void setQuestionNoIds(Integer[] questionNoIds) {
-        this.questionNoIds = questionNoIds;
+    public void setTitle(String title) {
+        this.title = title;
     }
 
     /**
@@ -139,6 +176,96 @@ public class ExaminationPaper implements Serializable {
         this.status = status;
     }
 
+    /**
+     * 获取总分
+     *
+     * @return total_score - 总分
+     */
+    public Integer getTotalScore() {
+        return totalScore;
+    }
+
+    /**
+     * 设置总分
+     *
+     * @param totalScore 总分
+     */
+    public void setTotalScore(Integer totalScore) {
+        this.totalScore = totalScore;
+    }
+
+    /**
+     * 获取总做卷次数
+     *
+     * @return total_times - 总做卷次数
+     */
+    public Integer getTotalTimes() {
+        return totalTimes;
+    }
+
+    /**
+     * 设置总做卷次数
+     *
+     * @param totalTimes 总做卷次数
+     */
+    public void setTotalTimes(Integer totalTimes) {
+        this.totalTimes = totalTimes;
+    }
+
+    /**
+     * 获取总Q分
+     *
+     * @return quant_score - 总Q分
+     */
+    public Integer getQuantScore() {
+        return quantScore;
+    }
+
+    /**
+     * 设置总Q分
+     *
+     * @param quantScore 总Q分
+     */
+    public void setQuantScore(Integer quantScore) {
+        this.quantScore = quantScore;
+    }
+
+    /**
+     * 获取总V分
+     *
+     * @return verbal_score - 总V分
+     */
+    public Integer getVerbalScore() {
+        return verbalScore;
+    }
+
+    /**
+     * 设置总V分
+     *
+     * @param verbalScore 总V分
+     */
+    public void setVerbalScore(Integer verbalScore) {
+        this.verbalScore = verbalScore;
+    }
+
+    /**
+     * 获取总ir分
+     *
+     * @return ir_score - 总ir分
+     */
+    public Integer getIrScore() {
+        return irScore;
+    }
+
+    /**
+     * 设置总ir分
+     *
+     * @param irScore 总ir分
+     */
+    public void setIrScore(Integer irScore) {
+        this.irScore = irScore;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -146,11 +273,16 @@ public class ExaminationPaper implements Serializable {
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
-        sb.append(", structId=").append(structId);
+        sb.append(", structTwo=").append(structTwo);
+        sb.append(", structThree=").append(structThree);
+        sb.append(", isAdapt=").append(isAdapt);
         sb.append(", title=").append(title);
-        sb.append(", questionNumber=").append(questionNumber);
-        sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", status=").append(status);
+        sb.append(", totalScore=").append(totalScore);
+        sb.append(", totalTimes=").append(totalTimes);
+        sb.append(", quantScore=").append(quantScore);
+        sb.append(", verbalScore=").append(verbalScore);
+        sb.append(", irScore=").append(irScore);
         sb.append("]");
         return sb.toString();
     }
@@ -175,40 +307,42 @@ public class ExaminationPaper implements Serializable {
         }
 
         /**
-         * @param structId
+         * 设置试卷组
+         *
+         * @param structTwo 试卷组
          */
-        public Builder structId(Integer structId) {
-            obj.setStructId(structId);
+        public Builder structTwo(Integer structTwo) {
+            obj.setStructTwo(structTwo);
             return this;
         }
 
         /**
-         * 设置标题
+         * 设置考卷
          *
-         * @param title 标题
+         * @param structThree 考卷
          */
-        public Builder title(String title) {
-            obj.setTitle(title);
+        public Builder structThree(Integer structThree) {
+            obj.setStructThree(structThree);
             return this;
         }
 
         /**
-         * 设置题目数量
+         * 设置是否适应难度
          *
-         * @param questionNumber 题目数量
+         * @param isAdapt 是否适应难度
          */
-        public Builder questionNumber(Integer questionNumber) {
-            obj.setQuestionNumber(questionNumber);
+        public Builder isAdapt(Integer isAdapt) {
+            obj.setIsAdapt(isAdapt);
             return this;
         }
 
         /**
-         * 设置题目编号ids:json
+         * 设置
          *
-         * @param questionNoIds 题目编号ids:json
+         * @param title 标题
          */
-        public Builder questionNoIds(Integer[] questionNoIds) {
-            obj.setQuestionNoIds(questionNoIds);
+        public Builder title(String title) {
+            obj.setTitle(title);
             return this;
         }
 
@@ -222,6 +356,56 @@ public class ExaminationPaper implements Serializable {
             return this;
         }
 
+        /**
+         * 设置总分
+         *
+         * @param totalScore 总分
+         */
+        public Builder totalScore(Integer totalScore) {
+            obj.setTotalScore(totalScore);
+            return this;
+        }
+
+        /**
+         * 设置总做卷次数
+         *
+         * @param totalTimes 总做卷次数
+         */
+        public Builder totalTimes(Integer totalTimes) {
+            obj.setTotalTimes(totalTimes);
+            return this;
+        }
+
+        /**
+         * 设置总Q分
+         *
+         * @param quantScore 总Q分
+         */
+        public Builder quantScore(Integer quantScore) {
+            obj.setQuantScore(quantScore);
+            return this;
+        }
+
+        /**
+         * 设置总V分
+         *
+         * @param verbalScore 总V分
+         */
+        public Builder verbalScore(Integer verbalScore) {
+            obj.setVerbalScore(verbalScore);
+            return this;
+        }
+
+        /**
+         * 设置总ir分
+         *
+         * @param irScore 总ir分
+         */
+        public Builder irScore(Integer irScore) {
+            obj.setIrScore(irScore);
+            return this;
+        }
+
         public ExaminationPaper build() {
             return this.obj;
         }

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

@@ -41,6 +41,18 @@ public class ExaminationStruct implements Serializable {
     private Integer level;
 
     /**
+     * 难度适应性:0非难度适应性,1难度适应性
+     */
+    @Column(name = "`is_adapt`")
+    private Integer isAdapt;
+
+    /**
+     * 对应服务
+     */
+    @Column(name = "`extend`")
+    private String extend;
+
+    /**
      * 说明
      */
     @Column(name = "`description`")
@@ -153,6 +165,42 @@ public class ExaminationStruct implements Serializable {
     }
 
     /**
+     * 获取难度适应性:0非难度适应性,1难度适应性
+     *
+     * @return is_adapt - 难度适应性:0非难度适应性,1难度适应性
+     */
+    public Integer getIsAdapt() {
+        return isAdapt;
+    }
+
+    /**
+     * 设置难度适应性:0非难度适应性,1难度适应性
+     *
+     * @param isAdapt 难度适应性:0非难度适应性,1难度适应性
+     */
+    public void setIsAdapt(Integer isAdapt) {
+        this.isAdapt = isAdapt;
+    }
+
+    /**
+     * 获取对应服务
+     *
+     * @return extend - 对应服务
+     */
+    public String getExtend() {
+        return extend;
+    }
+
+    /**
+     * 设置对应服务
+     *
+     * @param extend 对应服务
+     */
+    public void setExtend(String extend) {
+        this.extend = extend;
+    }
+
+    /**
      * 获取说明
      *
      * @return description - 说明
@@ -182,6 +230,8 @@ public class ExaminationStruct implements Serializable {
         sb.append(", parentId=").append(parentId);
         sb.append(", order=").append(order);
         sb.append(", level=").append(level);
+        sb.append(", isAdapt=").append(isAdapt);
+        sb.append(", extend=").append(extend);
         sb.append(", description=").append(description);
         sb.append("]");
         return sb.toString();
@@ -257,6 +307,26 @@ public class ExaminationStruct implements Serializable {
         }
 
         /**
+         * 设置难度适应性:0非难度适应性,1难度适应性
+         *
+         * @param isAdapt 难度适应性:0非难度适应性,1难度适应性
+         */
+        public Builder isAdapt(Integer isAdapt) {
+            obj.setIsAdapt(isAdapt);
+            return this;
+        }
+
+        /**
+         * 设置对应服务
+         *
+         * @param extend 对应服务
+         */
+        public Builder extend(String extend) {
+            obj.setExtend(extend);
+            return this;
+        }
+
+        /**
          * 设置说明
          *
          * @param description 说明

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

@@ -41,16 +41,16 @@ public class ExercisePaper implements Serializable {
     private String logicExtend;
 
     /**
-     * 分册
+     * 教材
      */
-    @Column(name = "`struct_id`")
-    private Integer structId;
+    @Column(name = "`struct_three`")
+    private Integer structThree;
 
     /**
-     * 所有父级id,逗号分隔
+     * 分册
      */
-    @Column(name = "`struct_parent`")
-    private Integer[] structParent;
+    @Column(name = "`struct_four`")
+    private Integer structFour;
 
     /**
      * 题目数量
@@ -177,39 +177,39 @@ public class ExercisePaper implements Serializable {
     }
 
     /**
-     * 获取分册
+     * 获取教材
      *
-     * @return struct_id - 分册
+     * @return struct_three - 教材
      */
-    public Integer getStructId() {
-        return structId;
+    public Integer getStructThree() {
+        return structThree;
     }
 
     /**
-     * 设置分册
+     * 设置教材
      *
-     * @param structId 分册
+     * @param structThree 教材
      */
-    public void setStructId(Integer structId) {
-        this.structId = structId;
+    public void setStructThree(Integer structThree) {
+        this.structThree = structThree;
     }
 
     /**
-     * 获取所有父级id,逗号分隔
+     * 获取分册
      *
-     * @return struct_parent - 所有父级id,逗号分隔
+     * @return struct_four - 分册
      */
-    public Integer[] getStructParent() {
-        return structParent;
+    public Integer getStructFour() {
+        return structFour;
     }
 
     /**
-     * 设置所有父级id,逗号分隔
+     * 设置分册
      *
-     * @param structParent 所有父级id,逗号分隔
+     * @param structFour 分册
      */
-    public void setStructParent(Integer[] structParent) {
-        this.structParent = structParent;
+    public void setStructFour(Integer structFour) {
+        this.structFour = structFour;
     }
 
     /**
@@ -278,8 +278,8 @@ public class ExercisePaper implements Serializable {
         sb.append(", no=").append(no);
         sb.append(", logic=").append(logic);
         sb.append(", logicExtend=").append(logicExtend);
-        sb.append(", structId=").append(structId);
-        sb.append(", structParent=").append(structParent);
+        sb.append(", structThree=").append(structThree);
+        sb.append(", structFour=").append(structFour);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", status=").append(status);
@@ -357,22 +357,22 @@ public class ExercisePaper implements Serializable {
         }
 
         /**
-         * 设置分册
+         * 设置教材
          *
-         * @param structId 分册
+         * @param structThree 教材
          */
-        public Builder structId(Integer structId) {
-            obj.setStructId(structId);
+        public Builder structThree(Integer structThree) {
+            obj.setStructThree(structThree);
             return this;
         }
 
         /**
-         * 设置所有父级id,逗号分隔
+         * 设置分册
          *
-         * @param structParent 所有父级id,逗号分隔
+         * @param structFour 分册
          */
-        public Builder structParent(Integer[] structParent) {
-            obj.setStructParent(structParent);
+        public Builder structFour(Integer structFour) {
+            obj.setStructFour(structFour);
             return this;
         }
 

+ 56 - 65
server/data/src/main/java/com/qxgmat/data/dao/entity/ExerciseStruct.java

@@ -41,18 +41,6 @@ public class ExerciseStruct implements Serializable {
     private Integer level;
 
     /**
-     * 第二层绑定题型
-     */
-    @Column(name = "`type`")
-    private String type;
-
-    /**
-     * 题目模块:sentence,base,textbook
-     */
-    @Column(name = "`module`")
-    private String module;
-
-    /**
      * 提问状态:0关闭,1开启
      */
     @Column(name = "`question_status`")
@@ -65,6 +53,15 @@ public class ExerciseStruct implements Serializable {
     private Integer isSentence;
 
     /**
+     * 是否是考试:每一层都继承
+     */
+    @Column(name = "`is_examination`")
+    private Integer isExamination;
+
+    @Column(name = "`extend`")
+    private String extend;
+
+    /**
      * 描述
      */
     @Column(name = "`description`")
@@ -177,75 +174,71 @@ public class ExerciseStruct implements Serializable {
     }
 
     /**
-     * 获取第二层绑定题型
+     * 获取提问状态:0关闭,1开启
      *
-     * @return type - 第二层绑定题型
+     * @return question_status - 提问状态:0关闭,1开启
      */
-    public String getType() {
-        return type;
+    public Integer getQuestionStatus() {
+        return questionStatus;
     }
 
     /**
-     * 设置第二层绑定题型
+     * 设置提问状态:0关闭,1开启
      *
-     * @param type 第二层绑定题型
+     * @param questionStatus 提问状态:0关闭,1开启
      */
-    public void setType(String type) {
-        this.type = type;
+    public void setQuestionStatus(Integer questionStatus) {
+        this.questionStatus = questionStatus;
     }
 
     /**
-     * 获取题目模块:sentence,base,textbook
+     * 获取是否是长难句:每一层都继承
      *
-     * @return module - 题目模块:sentence,base,textbook
+     * @return is_sentence - 是否是长难句:每一层都继承
      */
-    public String getModule() {
-        return module;
+    public Integer getIsSentence() {
+        return isSentence;
     }
 
     /**
-     * 设置题目模块:sentence,base,textbook
+     * 设置是否是长难句:每一层都继承
      *
-     * @param module 题目模块:sentence,base,textbook
+     * @param isSentence 是否是长难句:每一层都继承
      */
-    public void setModule(String module) {
-        this.module = module;
+    public void setIsSentence(Integer isSentence) {
+        this.isSentence = isSentence;
     }
 
     /**
-     * 获取提问状态:0关闭,1开启
+     * 获取是否是考试:每一层都继承
      *
-     * @return question_status - 提问状态:0关闭,1开启
+     * @return is_examination - 是否是考试:每一层都继承
      */
-    public Integer getQuestionStatus() {
-        return questionStatus;
+    public Integer getIsExamination() {
+        return isExamination;
     }
 
     /**
-     * 设置提问状态:0关闭,1开启
+     * 设置是否是考试:每一层都继承
      *
-     * @param questionStatus 提问状态:0关闭,1开启
+     * @param isExamination 是否是考试:每一层都继承
      */
-    public void setQuestionStatus(Integer questionStatus) {
-        this.questionStatus = questionStatus;
+    public void setIsExamination(Integer isExamination) {
+        this.isExamination = isExamination;
     }
 
     /**
-     * 获取是否是长难句:每一层都继承
-     *
-     * @return is_sentence - 是否是长难句:每一层都继承
+     * @return extend
      */
-    public Integer getIsSentence() {
-        return isSentence;
+    public String getExtend() {
+        return extend;
     }
 
     /**
-     * 设置是否是长难句:每一层都继承
-     *
-     * @param isSentence 是否是长难句:每一层都继承
+     * @param extend
      */
-    public void setIsSentence(Integer isSentence) {
-        this.isSentence = isSentence;
+    public void setExtend(String extend) {
+        this.extend = extend;
     }
 
     /**
@@ -278,10 +271,10 @@ public class ExerciseStruct implements Serializable {
         sb.append(", parentId=").append(parentId);
         sb.append(", order=").append(order);
         sb.append(", level=").append(level);
-        sb.append(", type=").append(type);
-        sb.append(", module=").append(module);
         sb.append(", questionStatus=").append(questionStatus);
         sb.append(", isSentence=").append(isSentence);
+        sb.append(", isExamination=").append(isExamination);
+        sb.append(", extend=").append(extend);
         sb.append(", description=").append(description);
         sb.append("]");
         return sb.toString();
@@ -357,42 +350,40 @@ public class ExerciseStruct implements Serializable {
         }
 
         /**
-         * 设置第二层绑定题型
+         * 设置提问状态:0关闭,1开启
          *
-         * @param type 第二层绑定题型
+         * @param questionStatus 提问状态:0关闭,1开启
          */
-        public Builder type(String type) {
-            obj.setType(type);
+        public Builder questionStatus(Integer questionStatus) {
+            obj.setQuestionStatus(questionStatus);
             return this;
         }
 
         /**
-         * 设置题目模块:sentence,base,textbook
+         * 设置是否是长难句:每一层都继承
          *
-         * @param module 题目模块:sentence,base,textbook
+         * @param isSentence 是否是长难句:每一层都继承
          */
-        public Builder module(String module) {
-            obj.setModule(module);
+        public Builder isSentence(Integer isSentence) {
+            obj.setIsSentence(isSentence);
             return this;
         }
 
         /**
-         * 设置提问状态:0关闭,1开启
+         * 设置是否是考试:每一层都继承
          *
-         * @param questionStatus 提问状态:0关闭,1开启
+         * @param isExamination 是否是考试:每一层都继承
          */
-        public Builder questionStatus(Integer questionStatus) {
-            obj.setQuestionStatus(questionStatus);
+        public Builder isExamination(Integer isExamination) {
+            obj.setIsExamination(isExamination);
             return this;
         }
 
         /**
-         * 设置是否是长难句:每一层都继承
-         *
-         * @param isSentence 是否是长难句:每一层都继承
+         * @param extend
          */
-        public Builder isSentence(Integer isSentence) {
-            obj.setIsSentence(isSentence);
+        public Builder extend(String extend) {
+            obj.setExtend(extend);
             return this;
         }
 

+ 46 - 11
server/data/src/main/java/com/qxgmat/data/dao/entity/Pay.java

@@ -19,6 +19,12 @@ public class Pay implements Serializable {
     private String no;
 
     /**
+     * 用户ID
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
      * 支付渠道
      */
     @Column(name = "`channel`")
@@ -91,10 +97,10 @@ public class Pay implements Serializable {
     private Date payTime;
 
     /**
-     * 工具类型: 1账户, 2支付宝, 3微信
+     * 支付类型
      */
     @Column(name = "`pay_type`")
-    private Integer payType;
+    private String payType;
 
     /**
      * 创建时间
@@ -155,6 +161,24 @@ public class Pay implements Serializable {
     }
 
     /**
+     * 获取用户ID
+     *
+     * @return user_id - 用户ID
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户ID
+     *
+     * @param userId 用户ID
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
      * 获取支付渠道
      *
      * @return channel - 支付渠道
@@ -371,20 +395,20 @@ public class Pay implements Serializable {
     }
 
     /**
-     * 获取工具类型: 1账户, 2支付宝, 3微信
+     * 获取支付类型
      *
-     * @return pay_type - 工具类型: 1账户, 2支付宝, 3微信
+     * @return pay_type - 支付类型
      */
-    public Integer getPayType() {
+    public String getPayType() {
         return payType;
     }
 
     /**
-     * 设置工具类型: 1账户, 2支付宝, 3微信
+     * 设置支付类型
      *
-     * @param payType 工具类型: 1账户, 2支付宝, 3微信
+     * @param payType 支付类型
      */
-    public void setPayType(Integer payType) {
+    public void setPayType(String payType) {
         this.payType = payType;
     }
 
@@ -468,6 +492,7 @@ public class Pay implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", no=").append(no);
+        sb.append(", userId=").append(userId);
         sb.append(", channel=").append(channel);
         sb.append(", pid=").append(pid);
         sb.append(", clientIp=").append(clientIp);
@@ -519,6 +544,16 @@ public class Pay implements Serializable {
         }
 
         /**
+         * 设置用户ID
+         *
+         * @param userId 用户ID
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
          * 设置支付渠道
          *
          * @param channel 支付渠道
@@ -639,11 +674,11 @@ public class Pay implements Serializable {
         }
 
         /**
-         * 设置工具类型: 1账户, 2支付宝, 3微信
+         * 设置支付类型
          *
-         * @param payType 工具类型: 1账户, 2支付宝, 3微信
+         * @param payType 支付类型
          */
-        public Builder payType(Integer payType) {
+        public Builder payType(String payType) {
             obj.setPayType(payType);
             return this;
         }

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

@@ -24,6 +24,12 @@ public class PreviewPaper implements Serializable {
     private Integer courseId;
 
     /**
+     * 课程课时
+     */
+    @Column(name = "`course_no`")
+    private Integer courseNo;
+
+    /**
      * 题目编号id:json
      */
     @Column(name = "`question_no_ids`")
@@ -124,6 +130,24 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
+     * 获取课程课时
+     *
+     * @return course_no - 课程课时
+     */
+    public Integer getCourseNo() {
+        return courseNo;
+    }
+
+    /**
+     * 设置课程课时
+     *
+     * @param courseNo 课程课时
+     */
+    public void setCourseNo(Integer courseNo) {
+        this.courseNo = courseNo;
+    }
+
+    /**
      * 获取题目编号id:json
      *
      * @return question_no_ids - 题目编号id:json
@@ -286,6 +310,7 @@ public class PreviewPaper implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", title=").append(title);
         sb.append(", courseId=").append(courseId);
+        sb.append(", courseNo=").append(courseNo);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", mode=").append(mode);
         sb.append(", questionModule=").append(questionModule);
@@ -339,6 +364,16 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
+         * 设置课程课时
+         *
+         * @param courseNo 课程课时
+         */
+        public Builder courseNo(Integer courseNo) {
+            obj.setCourseNo(courseNo);
+            return this;
+        }
+
+        /**
          * 设置题目编号id:json
          *
          * @param questionNoIds 题目编号id:json

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

@@ -97,6 +97,12 @@ public class Question implements Serializable {
     private Date updateTime;
 
     /**
+     * 答案分布
+     */
+    @Column(name = "`answer_distributed`")
+    private JSONObject answerDistributed;
+
+    /**
      * 题干
      */
     @Column(name = "`stem`")
@@ -407,6 +413,24 @@ public class Question implements Serializable {
     }
 
     /**
+     * 获取答案分布
+     *
+     * @return answer_distributed - 答案分布
+     */
+    public JSONObject getAnswerDistributed() {
+        return answerDistributed;
+    }
+
+    /**
+     * 设置答案分布
+     *
+     * @param answerDistributed 答案分布
+     */
+    public void setAnswerDistributed(JSONObject answerDistributed) {
+        this.answerDistributed = answerDistributed;
+    }
+
+    /**
      * 获取题干
      *
      * @return stem - 题干
@@ -476,6 +500,7 @@ public class Question implements Serializable {
         sb.append(", totalCorrect=").append(totalCorrect);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
+        sb.append(", answerDistributed=").append(answerDistributed);
         sb.append(", stem=").append(stem);
         sb.append(", qxContent=").append(qxContent);
         sb.append(", officialContent=").append(officialContent);
@@ -573,6 +598,16 @@ public class Question implements Serializable {
         }
 
         /**
+         * 设置答案分布
+         *
+         * @param answerDistributed 答案分布
+         */
+        public Builder answerDistributed(JSONObject answerDistributed) {
+            obj.setAnswerDistributed(answerDistributed);
+            return this;
+        }
+
+        /**
          * @param questionTime
          */
         public Builder questionTime(Date questionTime) {

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

@@ -24,7 +24,7 @@ public class QuestionNo implements Serializable {
     private Integer questionId;
 
     /**
-     * 模块:examination, exercise,sentence
+     * 模块:examination, exercise, sentence, textbook
      */
     @Column(name = "`module`")
     private String module;
@@ -109,18 +109,18 @@ public class QuestionNo implements Serializable {
     }
 
     /**
-     * 获取模块:examination, exercise,sentence
+     * 获取模块:examination, exercise, sentence, textbook
      *
-     * @return module - 模块:examination, exercise,sentence
+     * @return module - 模块:examination, exercise, sentence, textbook
      */
     public String getModule() {
         return module;
     }
 
     /**
-     * 设置模块:examination, exercise,sentence
+     * 设置模块:examination, exercise, sentence, textbook
      *
-     * @param module 模块:examination, exercise,sentence
+     * @param module 模块:examination, exercise, sentence, textbook
      */
     public void setModule(String module) {
         this.module = module;
@@ -271,9 +271,9 @@ public class QuestionNo implements Serializable {
         }
 
         /**
-         * 设置模块:examination, exercise,sentence
+         * 设置模块:examination, exercise, sentence, textbook
          *
-         * @param module 模块:examination, exercise,sentence
+         * @param module 模块:examination, exercise, sentence, textbook
          */
         public Builder module(String module) {
             obj.setModule(module);

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

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "sentence_paper")
@@ -46,6 +47,9 @@ public class SentencePaper implements Serializable {
     @Column(name = "`status`")
     private Integer status;
 
+    @Column(name = "`create_time`")
+    private Date createTime;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -170,6 +174,20 @@ public class SentencePaper implements Serializable {
         this.status = status;
     }
 
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -183,6 +201,7 @@ public class SentencePaper implements Serializable {
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", status=").append(status);
+        sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
     }
@@ -266,6 +285,14 @@ public class SentencePaper implements Serializable {
             return this;
         }
 
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
         public SentencePaper build() {
             return this.obj;
         }

+ 54 - 28
server/data/src/main/java/com/qxgmat/data/dao/entity/SentenceQuestion.java

@@ -23,10 +23,10 @@ public class SentenceQuestion implements Serializable {
     private Integer isTrail;
 
     /**
-     * 组卷id
+     * 是否教材:1教材题,1用于作业
      */
-    @Column(name = "`paper_id`")
-    private Integer paperId;
+    @Column(name = "`is_custom`")
+    private Integer isCustom;
 
     /**
      * 组卷序号
@@ -41,6 +41,12 @@ public class SentenceQuestion implements Serializable {
     private Integer questionId;
 
     /**
+     * 题目编号id
+     */
+    @Column(name = "`question_no_id`")
+    private Integer questionNoId;
+
+    /**
      * 总作答时间
      */
     @Column(name = "`total_time`")
@@ -58,9 +64,6 @@ public class SentenceQuestion implements Serializable {
     @Column(name = "`total_correct`")
     private Integer totalCorrect;
 
-    /**
-     * 中文语义
-     */
     @Column(name = "`chinese`")
     private String chinese;
 
@@ -117,21 +120,21 @@ public class SentenceQuestion implements Serializable {
     }
 
     /**
-     * 获取组卷id
+     * 获取是否教材:1教材题,1用于作业
      *
-     * @return paper_id - 组卷id
+     * @return is_custom - 是否教材:1教材题,1用于作业
      */
-    public Integer getPaperId() {
-        return paperId;
+    public Integer getIsCustom() {
+        return isCustom;
     }
 
     /**
-     * 设置组卷id
+     * 设置是否教材:1教材题,1用于作业
      *
-     * @param paperId 组卷id
+     * @param isCustom 是否教材:1教材题,1用于作业
      */
-    public void setPaperId(Integer paperId) {
-        this.paperId = paperId;
+    public void setIsCustom(Integer isCustom) {
+        this.isCustom = isCustom;
     }
 
     /**
@@ -171,6 +174,24 @@ public class SentenceQuestion implements Serializable {
     }
 
     /**
+     * 获取题目编号id
+     *
+     * @return question_no_id - 题目编号id
+     */
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    /**
+     * 设置题目编号id
+     *
+     * @param questionNoId 题目编号id
+     */
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
+
+    /**
      * 获取总作答时间
      *
      * @return total_time - 总作答时间
@@ -225,18 +246,14 @@ public class SentenceQuestion implements Serializable {
     }
 
     /**
-     * 获取中文语义
-     *
-     * @return chinese - 中文语义
+     * @return chinese
      */
     public String getChinese() {
         return chinese;
     }
 
     /**
-     * 设置中文语义
-     *
-     * @param chinese 中文语义
+     * @param chinese
      */
     public void setChinese(String chinese) {
         this.chinese = chinese;
@@ -251,9 +268,10 @@ public class SentenceQuestion implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", title=").append(title);
         sb.append(", isTrail=").append(isTrail);
-        sb.append(", paperId=").append(paperId);
+        sb.append(", isCustom=").append(isCustom);
         sb.append(", no=").append(no);
         sb.append(", questionId=").append(questionId);
+        sb.append(", questionNoId=").append(questionNoId);
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalNumber=").append(totalNumber);
         sb.append(", totalCorrect=").append(totalCorrect);
@@ -302,12 +320,12 @@ public class SentenceQuestion implements Serializable {
         }
 
         /**
-         * 设置组卷id
+         * 设置是否教材:1教材题,1用于作业
          *
-         * @param paperId 组卷id
+         * @param isCustom 是否教材:1教材题,1用于作业
          */
-        public Builder paperId(Integer paperId) {
-            obj.setPaperId(paperId);
+        public Builder isCustom(Integer isCustom) {
+            obj.setIsCustom(isCustom);
             return this;
         }
 
@@ -332,6 +350,16 @@ public class SentenceQuestion implements Serializable {
         }
 
         /**
+         * 设置题目编号id
+         *
+         * @param questionNoId 题目编号id
+         */
+        public Builder questionNoId(Integer questionNoId) {
+            obj.setQuestionNoId(questionNoId);
+            return this;
+        }
+
+        /**
          * 设置总作答时间
          *
          * @param totalTime 总作答时间
@@ -362,9 +390,7 @@ public class SentenceQuestion implements Serializable {
         }
 
         /**
-         * 设置中文语义
-         *
-         * @param chinese 中文语义
+         * @param chinese
          */
         public Builder chinese(String chinese) {
             obj.setChinese(chinese);

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

@@ -18,12 +18,24 @@ public class TextbookPaper implements Serializable {
     private Integer year;
 
     /**
+     * 标题
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
      * 组卷逻辑:ps、ds、ps+ds
      */
     @Column(name = "`logic`")
     private String logic;
 
     /**
+     * 序号
+     */
+    @Column(name = "`no`")
+    private Integer no;
+
+    /**
      * 换库id
      */
     @Column(name = "`set_id`")
@@ -41,6 +53,12 @@ public class TextbookPaper implements Serializable {
     @Column(name = "`create_time`")
     private Date createTime;
 
+    /**
+     * 开放状态:0关闭,1开启
+     */
+    @Column(name = "`status`")
+    private Integer status;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -76,6 +94,24 @@ public class TextbookPaper implements Serializable {
     }
 
     /**
+     * 获取标题
+     *
+     * @return title - 标题
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置标题
+     *
+     * @param title 标题
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
      * 获取组卷逻辑:ps、ds、ps+ds
      *
      * @return logic - 组卷逻辑:ps、ds、ps+ds
@@ -94,6 +130,24 @@ public class TextbookPaper implements Serializable {
     }
 
     /**
+     * 获取序号
+     *
+     * @return no - 序号
+     */
+    public Integer getNo() {
+        return no;
+    }
+
+    /**
+     * 设置序号
+     *
+     * @param no 序号
+     */
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    /**
      * 获取换库id
      *
      * @return set_id - 换库id
@@ -157,6 +211,24 @@ public class TextbookPaper implements Serializable {
         this.createTime = createTime;
     }
 
+    /**
+     * 获取开放状态:0关闭,1开启
+     *
+     * @return status - 开放状态:0关闭,1开启
+     */
+    public Integer getStatus() {
+        return status;
+    }
+
+    /**
+     * 设置开放状态:0关闭,1开启
+     *
+     * @param status 开放状态:0关闭,1开启
+     */
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -165,11 +237,14 @@ public class TextbookPaper implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", year=").append(year);
+        sb.append(", title=").append(title);
         sb.append(", logic=").append(logic);
+        sb.append(", no=").append(no);
         sb.append(", setId=").append(setId);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", createTime=").append(createTime);
+        sb.append(", status=").append(status);
         sb.append("]");
         return sb.toString();
     }
@@ -204,6 +279,16 @@ public class TextbookPaper implements Serializable {
         }
 
         /**
+         * 设置标题
+         *
+         * @param title 标题
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
          * 设置组卷逻辑:ps、ds、ps+ds
          *
          * @param logic 组卷逻辑:ps、ds、ps+ds
@@ -214,6 +299,16 @@ public class TextbookPaper implements Serializable {
         }
 
         /**
+         * 设置序号
+         *
+         * @param no 序号
+         */
+        public Builder no(Integer no) {
+            obj.setNo(no);
+            return this;
+        }
+
+        /**
          * 设置换库id
          *
          * @param setId 换库id
@@ -249,6 +344,16 @@ public class TextbookPaper implements Serializable {
             return this;
         }
 
+        /**
+         * 设置开放状态:0关闭,1开启
+         *
+         * @param status 开放状态:0关闭,1开启
+         */
+        public Builder status(Integer status) {
+            obj.setStatus(status);
+            return this;
+        }
+
         public TextbookPaper build() {
             return this.obj;
         }

+ 69 - 16
server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookQuestion.java

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "textbook_question")
@@ -35,10 +36,10 @@ public class TextbookQuestion implements Serializable {
     private Integer questionId;
 
     /**
-     * 题
+     * 题目编号id
      */
-    @Column(name = "`question_type`")
-    private String questionType;
+    @Column(name = "`question_no_id`")
+    private Integer questionNoId;
 
     /**
      * 总做题时间
@@ -64,6 +65,12 @@ public class TextbookQuestion implements Serializable {
     @Column(name = "`is_custom`")
     private Integer isCustom;
 
+    @Column(name = "`start_time`")
+    private Date startTime;
+
+    @Column(name = "`end_time`")
+    private Date endTime;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -153,21 +160,21 @@ public class TextbookQuestion implements Serializable {
     }
 
     /**
-     * 获取题
+     * 获取题目编号id
      *
-     * @return question_type - 题型
+     * @return question_no_id - 题目编号id
      */
-    public String getQuestionType() {
-        return questionType;
+    public Integer getQuestionNoId() {
+        return questionNoId;
     }
 
     /**
-     * 设置题
+     * 设置题目编号id
      *
-     * @param questionType 题型
+     * @param questionNoId 题目编号id
      */
-    public void setQuestionType(String questionType) {
-        this.questionType = questionType;
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
     }
 
     /**
@@ -242,6 +249,34 @@ public class TextbookQuestion implements Serializable {
         this.isCustom = isCustom;
     }
 
+    /**
+     * @return start_time
+     */
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * @param startTime
+     */
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    /**
+     * @return end_time
+     */
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    /**
+     * @param endTime
+     */
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -253,11 +288,13 @@ public class TextbookQuestion implements Serializable {
         sb.append(", no=").append(no);
         sb.append(", setId=").append(setId);
         sb.append(", questionId=").append(questionId);
-        sb.append(", questionType=").append(questionType);
+        sb.append(", questionNoId=").append(questionNoId);
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalNumber=").append(totalNumber);
         sb.append(", totalCorrect=").append(totalCorrect);
         sb.append(", isCustom=").append(isCustom);
+        sb.append(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
         sb.append("]");
         return sb.toString();
     }
@@ -322,12 +359,12 @@ public class TextbookQuestion implements Serializable {
         }
 
         /**
-         * 设置题
+         * 设置题目编号id
          *
-         * @param questionType 题型
+         * @param questionNoId 题目编号id
          */
-        public Builder questionType(String questionType) {
-            obj.setQuestionType(questionType);
+        public Builder questionNoId(Integer questionNoId) {
+            obj.setQuestionNoId(questionNoId);
             return this;
         }
 
@@ -371,6 +408,22 @@ public class TextbookQuestion implements Serializable {
             return this;
         }
 
+        /**
+         * @param startTime
+         */
+        public Builder startTime(Date startTime) {
+            obj.setStartTime(startTime);
+            return this;
+        }
+
+        /**
+         * @param endTime
+         */
+        public Builder endTime(Date endTime) {
+            obj.setEndTime(endTime);
+            return this;
+        }
+
         public TextbookQuestion build() {
             return this.obj;
         }

+ 133 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourse.java

@@ -0,0 +1,133 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import javax.persistence.*;
+
+@Table(name = "user_course")
+public class UserCourse implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取用户id
+     *
+     * @return user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * 获取课程id
+     *
+     * @return course_id - 课程id
+     */
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    /**
+     * 设置课程id
+     *
+     * @param courseId 课程id
+     */
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", userId=").append(userId);
+        sb.append(", courseId=").append(courseId);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static UserCourse.Builder builder() {
+        return new UserCourse.Builder();
+    }
+
+    public static class Builder {
+        private UserCourse obj;
+
+        public Builder() {
+            this.obj = new UserCourse();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * 设置课程id
+         *
+         * @param courseId 课程id
+         */
+        public Builder courseId(Integer courseId) {
+            obj.setCourseId(courseId);
+            return this;
+        }
+
+        public UserCourse build() {
+            return this.obj;
+        }
+    }
+}

+ 219 - 35
server/data/src/main/java/com/qxgmat/data/dao/entity/UserFeedbackError.java

@@ -24,20 +24,53 @@ public class UserFeedbackError implements Serializable {
     private String module;
 
     /**
-     * 题目id
+     * 对应模块id
      */
-    @Column(name = "`question_id`")
-    private Integer questionId;
+    @Column(name = "`module_id`")
+    private Integer moduleId;
 
     /**
-     * 题目编号id
+     * 处理人id
      */
-    @Column(name = "`question_no_id`")
-    private Integer questionNoId;
+    @Column(name = "`manager_id`")
+    private Integer managerId;
+
+    /**
+     * 内容名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 错误位置,逗号链接的字符串,服务端不解析
+     */
+    @Column(name = "`position`")
+    private String position;
 
     @Column(name = "`create_time`")
     private Date createTime;
 
+    /**
+     * 处理状态:0未处理,1已处理,2已忽略
+     */
+    @Column(name = "`status`")
+    private Integer status;
+
+    /**
+     * 处理时间
+     */
+    @Column(name = "`handle_time`")
+    private Date handleTime;
+
+    /**
+     * 错误内容
+     */
+    @Column(name = "`origin_content`")
+    private String originContent;
+
+    /**
+     * 正确内容
+     */
     @Column(name = "`content`")
     private String content;
 
@@ -94,39 +127,75 @@ public class UserFeedbackError implements Serializable {
     }
 
     /**
-     * 获取题目id
+     * 获取对应模块id
+     *
+     * @return module_id - 对应模块id
+     */
+    public Integer getModuleId() {
+        return moduleId;
+    }
+
+    /**
+     * 设置对应模块id
+     *
+     * @param moduleId 对应模块id
+     */
+    public void setModuleId(Integer moduleId) {
+        this.moduleId = moduleId;
+    }
+
+    /**
+     * 获取处理人id
+     *
+     * @return manager_id - 处理人id
+     */
+    public Integer getManagerId() {
+        return managerId;
+    }
+
+    /**
+     * 设置处理人id
      *
-     * @return question_id - 题目id
+     * @param managerId 处理人id
      */
-    public Integer getQuestionId() {
-        return questionId;
+    public void setManagerId(Integer managerId) {
+        this.managerId = managerId;
     }
 
     /**
-     * 设置题目id
+     * 获取内容名称
      *
-     * @param questionId 题目id
+     * @return title - 内容名称
      */
-    public void setQuestionId(Integer questionId) {
-        this.questionId = questionId;
+    public String getTitle() {
+        return title;
     }
 
     /**
-     * 获取题目编号id
+     * 设置内容名称
      *
-     * @return question_no_id - 题目编号id
+     * @param title 内容名称
      */
-    public Integer getQuestionNoId() {
-        return questionNoId;
+    public void setTitle(String title) {
+        this.title = title;
     }
 
     /**
-     * 设置题目编号id
+     * 获取错误位置,逗号链接的字符串,服务端不解析
      *
-     * @param questionNoId 题目编号id
+     * @return position - 错误位置,逗号链接的字符串,服务端不解析
      */
-    public void setQuestionNoId(Integer questionNoId) {
-        this.questionNoId = questionNoId;
+    public String getPosition() {
+        return position;
+    }
+
+    /**
+     * 设置错误位置,逗号链接的字符串,服务端不解析
+     *
+     * @param position 错误位置,逗号链接的字符串,服务端不解析
+     */
+    public void setPosition(String position) {
+        this.position = position;
     }
 
     /**
@@ -144,14 +213,72 @@ public class UserFeedbackError implements Serializable {
     }
 
     /**
-     * @return content
+     * 获取处理状态:0未处理,1已处理,2已忽略
+     *
+     * @return status - 处理状态:0未处理,1已处理,2已忽略
+     */
+    public Integer getStatus() {
+        return status;
+    }
+
+    /**
+     * 设置处理状态:0未处理,1已处理,2已忽略
+     *
+     * @param status 处理状态:0未处理,1已处理,2已忽略
+     */
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    /**
+     * 获取处理时间
+     *
+     * @return handle_time - 处理时间
+     */
+    public Date getHandleTime() {
+        return handleTime;
+    }
+
+    /**
+     * 设置处理时间
+     *
+     * @param handleTime 处理时间
+     */
+    public void setHandleTime(Date handleTime) {
+        this.handleTime = handleTime;
+    }
+
+    /**
+     * 获取错误内容
+     *
+     * @return origin_content - 错误内容
+     */
+    public String getOriginContent() {
+        return originContent;
+    }
+
+    /**
+     * 设置错误内容
+     *
+     * @param originContent 错误内容
+     */
+    public void setOriginContent(String originContent) {
+        this.originContent = originContent;
+    }
+
+    /**
+     * 获取正确内容
+     *
+     * @return content - 正确内容
      */
     public String getContent() {
         return content;
     }
 
     /**
-     * @param content
+     * 设置正确内容
+     *
+     * @param content 正确内容
      */
     public void setContent(String content) {
         this.content = content;
@@ -166,9 +293,14 @@ public class UserFeedbackError implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", module=").append(module);
-        sb.append(", questionId=").append(questionId);
-        sb.append(", questionNoId=").append(questionNoId);
+        sb.append(", moduleId=").append(moduleId);
+        sb.append(", managerId=").append(managerId);
+        sb.append(", title=").append(title);
+        sb.append(", position=").append(position);
         sb.append(", createTime=").append(createTime);
+        sb.append(", status=").append(status);
+        sb.append(", handleTime=").append(handleTime);
+        sb.append(", originContent=").append(originContent);
         sb.append(", content=").append(content);
         sb.append("]");
         return sb.toString();
@@ -214,22 +346,42 @@ public class UserFeedbackError implements Serializable {
         }
 
         /**
-         * 设置题目id
+         * 设置对应模块id
+         *
+         * @param moduleId 对应模块id
+         */
+        public Builder moduleId(Integer moduleId) {
+            obj.setModuleId(moduleId);
+            return this;
+        }
+
+        /**
+         * 设置处理人id
          *
-         * @param questionId 题目id
+         * @param managerId 处理人id
          */
-        public Builder questionId(Integer questionId) {
-            obj.setQuestionId(questionId);
+        public Builder managerId(Integer managerId) {
+            obj.setManagerId(managerId);
             return this;
         }
 
         /**
-         * 设置题目编号id
+         * 设置内容名称
          *
-         * @param questionNoId 题目编号id
+         * @param title 内容名称
          */
-        public Builder questionNoId(Integer questionNoId) {
-            obj.setQuestionNoId(questionNoId);
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置错误位置,逗号链接的字符串,服务端不解析
+         *
+         * @param position 错误位置,逗号链接的字符串,服务端不解析
+         */
+        public Builder position(String position) {
+            obj.setPosition(position);
             return this;
         }
 
@@ -242,7 +394,39 @@ public class UserFeedbackError implements Serializable {
         }
 
         /**
-         * @param content
+         * 设置处理状态:0未处理,1已处理,2已忽略
+         *
+         * @param status 处理状态:0未处理,1已处理,2已忽略
+         */
+        public Builder status(Integer status) {
+            obj.setStatus(status);
+            return this;
+        }
+
+        /**
+         * 设置处理时间
+         *
+         * @param handleTime 处理时间
+         */
+        public Builder handleTime(Date handleTime) {
+            obj.setHandleTime(handleTime);
+            return this;
+        }
+
+        /**
+         * 设置错误内容
+         *
+         * @param originContent 错误内容
+         */
+        public Builder originContent(String originContent) {
+            obj.setOriginContent(originContent);
+            return this;
+        }
+
+        /**
+         * 设置正确内容
+         *
+         * @param content 正确内容
          */
         public Builder content(String content) {
             obj.setContent(content);

+ 43 - 17
server/data/src/main/java/com/qxgmat/data/dao/entity/UserPay.java

@@ -29,8 +29,8 @@ public class UserPay implements Serializable {
     @Column(name = "`module_extend`")
     private String moduleExtend;
 
-    @Column(name = "`create_time`")
-    private Date createTime;
+    @Column(name = "`module_id`")
+    private Integer moduleId;
 
     /**
      * 使用状态:0未使用,1已使用
@@ -50,6 +50,9 @@ public class UserPay implements Serializable {
     @Column(name = "`expire_time`")
     private Date expireTime;
 
+    @Column(name = "`create_time`")
+    private Date createTime;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -121,17 +124,17 @@ public class UserPay implements Serializable {
     }
 
     /**
-     * @return create_time
+     * @return module_id
      */
-    public Date getCreateTime() {
-        return createTime;
+    public Integer getModuleId() {
+        return moduleId;
     }
 
     /**
-     * @param createTime
+     * @param moduleId
      */
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
+    public void setModuleId(Integer moduleId) {
+        this.moduleId = moduleId;
     }
 
     /**
@@ -198,6 +201,20 @@ public class UserPay implements Serializable {
         this.expireTime = expireTime;
     }
 
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -208,11 +225,12 @@ public class UserPay implements Serializable {
         sb.append(", userId=").append(userId);
         sb.append(", module=").append(module);
         sb.append(", moduleExtend=").append(moduleExtend);
-        sb.append(", createTime=").append(createTime);
+        sb.append(", moduleId=").append(moduleId);
         sb.append(", isUse=").append(isUse);
         sb.append(", useTime=").append(useTime);
         sb.append(", startTime=").append(startTime);
         sb.append(", expireTime=").append(expireTime);
+        sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
     }
@@ -257,20 +275,20 @@ public class UserPay implements Serializable {
         }
 
         /**
-         * 设置模块扩展信息
-         *
-         * @param moduleExtend 模块扩展信息
+         * @param moduleId
          */
-        public Builder moduleExtend(String moduleExtend) {
-            obj.setModuleExtend(moduleExtend);
+        public Builder moduleId(Integer moduleId) {
+            obj.setModuleId(moduleId);
             return this;
         }
 
         /**
-         * @param createTime
+         * 设置模块扩展信息
+         *
+         * @param moduleExtend 模块扩展信息
          */
-        public Builder createTime(Date createTime) {
-            obj.setCreateTime(createTime);
+        public Builder moduleExtend(String moduleExtend) {
+            obj.setModuleExtend(moduleExtend);
             return this;
         }
 
@@ -310,6 +328,14 @@ public class UserPay implements Serializable {
             return this;
         }
 
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
         public UserPay build() {
             return this.obj;
         }

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

@@ -54,9 +54,6 @@ public class UserQuestion implements Serializable {
     @Column(name = "`user_time`")
     private Integer userTime;
 
-    @Column(name = "`create_time`")
-    private Date createTime;
-
     /**
      * 用户答案:json
      */
@@ -75,6 +72,9 @@ public class UserQuestion implements Serializable {
     @Column(name = "`detail`")
     private JSONObject detail;
 
+    @Column(name = "`create_time`")
+    private Date createTime;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -218,20 +218,6 @@ public class UserQuestion implements Serializable {
     }
 
     /**
-     * @return create_time
-     */
-    public Date getCreateTime() {
-        return createTime;
-    }
-
-    /**
-     * @param createTime
-     */
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
-
-    /**
      * 获取用户答案:json
      *
      * @return user_answer - 用户答案:json
@@ -285,6 +271,20 @@ public class UserQuestion implements Serializable {
         this.detail = detail;
     }
 
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -299,10 +299,10 @@ public class UserQuestion implements Serializable {
         sb.append(", no=").append(no);
         sb.append(", time=").append(time);
         sb.append(", userTime=").append(userTime);
-        sb.append(", createTime=").append(createTime);
         sb.append(", userAnswer=").append(userAnswer);
         sb.append(", isCorrect=").append(isCorrect);
         sb.append(", detail=").append(detail);
+        sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
     }
@@ -397,14 +397,6 @@ public class UserQuestion implements Serializable {
         }
 
         /**
-         * @param createTime
-         */
-        public Builder createTime(Date createTime) {
-            obj.setCreateTime(createTime);
-            return this;
-        }
-
-        /**
          * 设置用户答案:json
          *
          * @param userAnswer 用户答案:json
@@ -434,6 +426,14 @@ public class UserQuestion implements Serializable {
             return this;
         }
 
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
         public UserQuestion build() {
             return this.obj;
         }

+ 1 - 1
server/data/src/main/java/com/qxgmat/data/dao/entity/UserReport.java

@@ -25,7 +25,7 @@ public class UserReport implements Serializable {
     private Integer paperId;
 
     /**
-     * 对应模块:exercise,examination,sentence, preview
+     * 对应模块:exercise,examination,sentence, homework_preview
      */
     @Column(name = "`paper_module`")
     private String paperModule;

+ 10 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassCommentMapper.xml

@@ -0,0 +1,10 @@
+<?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.dao.ClassCommentMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ClassComment">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+</mapper>

+ 10 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassCourseNoMapper.xml

@@ -0,0 +1,10 @@
+<?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.dao.ClassCourseNoMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ClassCourseNo">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+</mapper>

+ 19 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ClassFaqMapper.xml

@@ -0,0 +1,19 @@
+<?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.dao.ClassFaqMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ClassFaq">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="is_special" jdbcType="INTEGER" property="isSpecial" />
+    <result column="status" jdbcType="INTEGER" property="status" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `course_id`, `is_special`, `status`
+  </sql>
+</mapper>

+ 10 - 4
server/data/src/main/java/com/qxgmat/data/dao/mapping/ExaminationPaperMapper.xml

@@ -6,16 +6,22 @@
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
-    <result column="struct_id" jdbcType="INTEGER" property="structId" />
+    <result column="struct_two" jdbcType="INTEGER" property="structTwo" />
+    <result column="struct_three" jdbcType="INTEGER" property="structThree" />
+    <result column="is_adapt" jdbcType="INTEGER" property="isAdapt" />
     <result column="title" jdbcType="VARCHAR" property="title" />
-    <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" />
+    <result column="total_score" jdbcType="INTEGER" property="totalScore" />
+    <result column="total_times" jdbcType="INTEGER" property="totalTimes" />
+    <result column="quant_score" jdbcType="INTEGER" property="quantScore" />
+    <result column="verbal_score" jdbcType="INTEGER" property="verbalScore" />
+    <result column="ir_score" jdbcType="INTEGER" property="irScore" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `struct_id`, `title`, `question_number`, `question_no_ids`, `status`
+    `id`, `struct_two`, `struct_three`, `is_adapt`, `title`, `status`, `total_score`, 
+    `total_times`, `quant_score`, `verbal_score`, `ir_score`
   </sql>
 </mapper>

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

@@ -11,6 +11,8 @@
     <result column="parent_id" jdbcType="INTEGER" property="parentId" />
     <result column="order" jdbcType="INTEGER" property="order" />
     <result column="level" jdbcType="INTEGER" property="level" />
+    <result column="is_adapt" jdbcType="INTEGER" property="isAdapt" />
+    <result column="extend" jdbcType="VARCHAR" property="extend" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.ExaminationStruct">
     <!--
@@ -22,7 +24,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`
+    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `is_adapt`, `extend`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -11,8 +11,8 @@
     <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" />
-    <result column="struct_parent" jdbcType="VARCHAR" property="structParent" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayHandler" />
+    <result column="struct_three" jdbcType="INTEGER" property="structThree" />
+    <result column="struct_four" jdbcType="INTEGER" property="structFour" />
     <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" />
@@ -21,7 +21,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `question_type`, `title`, `no`, `logic`, `logic_extend`, `struct_id`, `struct_parent`, 
+    `id`, `question_type`, `title`, `no`, `logic`, `logic_extend`, `struct_three`, `struct_four`, 
     `question_number`, `question_no_ids`, `status`
   </sql>
 </mapper>

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

@@ -11,10 +11,10 @@
     <result column="parent_id" jdbcType="INTEGER" property="parentId" />
     <result column="order" jdbcType="INTEGER" property="order" />
     <result column="level" jdbcType="INTEGER" property="level" />
-    <result column="type" jdbcType="VARCHAR" property="type" />
-    <result column="module" jdbcType="VARCHAR" property="module" />
     <result column="question_status" jdbcType="INTEGER" property="questionStatus" />
     <result column="is_sentence" jdbcType="INTEGER" property="isSentence" />
+    <result column="is_examination" jdbcType="INTEGER" property="isExamination" />
+    <result column="extend" jdbcType="VARCHAR" property="extend" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.ExerciseStruct">
     <!--
@@ -26,8 +26,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `type`, `module`, `question_status`, 
-    `is_sentence`
+    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `question_status`, `is_sentence`, 
+    `is_examination`, `extend`
   </sql>
   <sql id="Blob_Column_List">
     <!--

+ 5 - 4
server/data/src/main/java/com/qxgmat/data/dao/mapping/PayMapper.xml

@@ -7,6 +7,7 @@
     -->
     <id column="id" jdbcType="BIGINT" property="id" />
     <result column="no" jdbcType="VARCHAR" property="no" />
+    <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="channel" jdbcType="VARCHAR" property="channel" />
     <result column="pid" jdbcType="VARCHAR" property="pid" />
     <result column="client_ip" jdbcType="VARCHAR" property="clientIp" />
@@ -19,7 +20,7 @@
     <result column="currency" jdbcType="VARCHAR" property="currency" />
     <result column="trade_status" jdbcType="INTEGER" property="tradeStatus" />
     <result column="pay_time" jdbcType="TIMESTAMP" property="payTime" />
-    <result column="pay_type" jdbcType="INTEGER" property="payType" />
+    <result column="pay_type" jdbcType="VARCHAR" property="payType" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
@@ -34,9 +35,9 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `no`, `channel`, `pid`, `client_ip`, `money`, `module`, `module_extend`, `subject`, 
-    `body`, `transaction_no`, `currency`, `trade_status`, `pay_time`, `pay_type`, `create_time`, 
-    `update_time`
+    `id`, `no`, `user_id`, `channel`, `pid`, `client_ip`, `money`, `module`, `module_extend`, 
+    `subject`, `body`, `transaction_no`, `currency`, `trade_status`, `pay_time`, `pay_type`, 
+    `create_time`, `update_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -8,6 +8,7 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="course_no" jdbcType="INTEGER" property="courseNo" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="mode" jdbcType="INTEGER" property="mode" />
     <result column="question_module" jdbcType="VARCHAR" property="questionModule" />
@@ -22,7 +23,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `course_id`, `question_no_ids`, `mode`, `question_module`, `user_ids`, 
-    `start_time`, `end_time`, `finish`, `create_time`, `update_time`
+    `id`, `title`, `course_id`, `course_no`, `question_no_ids`, `mode`, `question_module`, 
+    `user_ids`, `start_time`, `end_time`, `finish`, `create_time`, `update_time`
   </sql>
 </mapper>

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

@@ -23,6 +23,7 @@
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+    <result column="answer_distributed" jdbcType="VARCHAR" property="answerDistributed" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.Question">
     <!--
@@ -38,7 +39,7 @@
     -->
     `id`, `keyword`, `question_type`, `place`, `difficult`, `description`, `content`, 
     `answer`, `question_time`, `qx_time`, `official_time`, `association_time`, `association_content`, 
-    `total_time`, `total_number`, `total_correct`, `create_time`, `update_time`
+    `total_time`, `total_number`, `total_correct`, `create_time`, `update_time`, `answer_distributed`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -12,11 +12,12 @@
     <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" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `no`, `logic`, `question_number`, `question_no_ids`, `status`
+    `id`, `title`, `no`, `logic`, `question_number`, `question_no_ids`, `status`, `create_time`
   </sql>
 </mapper>

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

@@ -8,9 +8,10 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="is_trail" jdbcType="INTEGER" property="isTrail" />
-    <result column="paper_id" jdbcType="INTEGER" property="paperId" />
+    <result column="is_custom" jdbcType="INTEGER" property="isCustom" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
+    <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
@@ -25,8 +26,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `is_trail`, `paper_id`, `no`, `question_id`, `total_time`, `total_number`, 
-    `total_correct`
+    `id`, `title`, `is_trail`, `is_custom`, `no`, `question_id`, `question_no_id`, `total_time`, 
+    `total_number`, `total_correct`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -7,16 +7,20 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="year" jdbcType="INTEGER" property="year" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="logic" jdbcType="VARCHAR" property="logic" />
+    <result column="no" jdbcType="INTEGER" property="no" />
     <result column="set_id" jdbcType="INTEGER" property="setId" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="status" jdbcType="INTEGER" property="status" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `year`, `logic`, `set_id`, `question_no_ids`, `question_number`, `create_time`
+    `id`, `year`, `title`, `logic`, `no`, `set_id`, `question_no_ids`, `question_number`, 
+    `create_time`, `status`
   </sql>
 </mapper>

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

@@ -10,17 +10,19 @@
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="set_id" jdbcType="INTEGER" property="setId" />
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
-    <result column="question_type" jdbcType="VARCHAR" property="questionType" />
+    <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
     <result column="is_custom" jdbcType="INTEGER" property="isCustom" />
+    <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
+    <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `no`, `set_id`, `question_id`, `question_type`, `total_time`, `total_number`, 
-    `total_correct`, `is_custom`
+    `id`, `title`, `no`, `set_id`, `question_id`, `question_no_id`, `total_time`, `total_number`, 
+    `total_correct`, `is_custom`, `start_time`, `end_time`
   </sql>
 </mapper>

+ 18 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseMapper.xml

@@ -0,0 +1,18 @@
+<?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.dao.UserCourseMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.UserCourse">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `user_id`, `course_id`
+  </sql>
+</mapper>

+ 10 - 4
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserFeedbackErrorMapper.xml

@@ -8,26 +8,32 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="module" jdbcType="VARCHAR" property="module" />
-    <result column="question_id" jdbcType="INTEGER" property="questionId" />
-    <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
+    <result column="module_id" jdbcType="INTEGER" property="moduleId" />
+    <result column="manager_id" jdbcType="INTEGER" property="managerId" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="position" jdbcType="VARCHAR" property="position" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="status" jdbcType="INTEGER" property="status" />
+    <result column="handle_time" jdbcType="TIMESTAMP" property="handleTime" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserFeedbackError">
     <!--
       WARNING - @mbg.generated
     -->
+    <result column="origin_content" jdbcType="LONGVARCHAR" property="originContent" />
     <result column="content" jdbcType="LONGVARCHAR" property="content" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `module`, `question_id`, `question_no_id`, `create_time`
+    `id`, `user_id`, `module`, `module_id`, `manager_id`, `title`, `position`, `create_time`, 
+    `status`, `handle_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `content`
+    `origin_content`, `content`
   </sql>
 </mapper>

+ 4 - 3
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPayMapper.xml

@@ -9,17 +9,18 @@
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="module" jdbcType="VARCHAR" property="module" />
     <result column="module_extend" jdbcType="VARCHAR" property="moduleExtend" />
-    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="module_id" jdbcType="INTEGER" property="moduleId" />
     <result column="is_use" jdbcType="INTEGER" property="isUse" />
     <result column="use_time" jdbcType="TIMESTAMP" property="useTime" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `module`, `module_extend`, `create_time`, `is_use`, `use_time`, 
-    `start_time`, `expire_time`
+    `id`, `user_id`, `module`, `module_extend`, `module_id`, `is_use`, `use_time`, `start_time`, 
+    `expire_time`, `create_time`
   </sql>
 </mapper>

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

@@ -13,16 +13,16 @@
     <result column="no" jdbcType="INTEGER" property="no" />
     <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="user_answer" jdbcType="VARCHAR" property="userAnswer" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="is_correct" jdbcType="INTEGER" property="isCorrect" />
     <result column="detail" jdbcType="VARCHAR" property="detail" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `report_id`, `question_id`, `question_no_id`, `no`, `time`, `user_time`, 
-    `create_time`, `user_answer`, `is_correct`, `detail`
+    `user_answer`, `is_correct`, `detail`, `create_time`
   </sql>
 </mapper>

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

@@ -10,7 +10,7 @@ import java.util.List;
  */
 public interface ExerciseQuestionRelationMapper {
     List<ExercisePaperQuestion> listAdmin(
-            @Param("type") String type,
+            @Param("questionType") String questionType,
             @Param("structId") Number structId,
             @Param("questionNoId") Number questionNoId,
             @Param("paperId") Number paperId,

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

@@ -0,0 +1,27 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.TextbookQuestion;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface TextbookQuestionRelationMapper {
+
+    void accumulation(
+            @Param("id") Number textbookQuestionId,
+            @Param("number") Integer number,
+            @Param("time") Integer time,
+            @Param("current") Integer current
+    );
+
+    List<TextbookQuestion> listAdmin(
+            @Param("questionType") String questionType,
+            @Param("paperId") Number paperId,
+            @Param("questionNoId") Number questionNoId,
+            @Param("order") String order,
+            @Param("direction") String direction
+    );
+}

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

@@ -14,7 +14,7 @@ public interface UserCollectQuestionRelationMapper {
     List<UserCollectQuestion> list(
             @Param("userId") Number userId,
             @Param("module") String module,
-            @Param("type") String type,
+            @Param("questionType") String questionType,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
             @Param("order") String order,

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

@@ -13,7 +13,7 @@ public interface UserNoteQuestionRelationMapper {
     List<UserNoteQuestion> list(
             @Param("userId") Number userId,
             @Param("module") String module,
-            @Param("type") String type,
+            @Param("questionType") String questionType,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
             @Param("order") String order,

+ 16 - 0
server/data/src/main/java/com/qxgmat/data/relation/entity/TextbookQuestionRelation.java

@@ -0,0 +1,16 @@
+package com.qxgmat.data.relation.entity;
+
+import com.qxgmat.data.dao.entity.Question;
+import com.qxgmat.data.dao.entity.TextbookQuestion;
+
+public class TextbookQuestionRelation extends TextbookQuestion {
+    private Question question;
+
+    public Question getQuestion() {
+        return question;
+    }
+
+    public void setQuestion(Question question) {
+        this.question = question;
+    }
+}

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

@@ -34,8 +34,8 @@
     <if test="questionNoId != null">
       and qn.`id` =#{questionNoId,jdbcType=VARCHAR}
     </if>
-    <if test="type != null">
-      and q.`type` =#{type,jdbcType=VARCHAR}
+    <if test="questionType != null">
+      and q.`question_type` =#{questionType,jdbcType=VARCHAR}
     </if>
     <if test="place != null">
       and q.`place` =#{place,jdbcType=VARCHAR}

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

@@ -0,0 +1,48 @@
+<?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.TextbookQuestionRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.TextbookQuestion">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    sq.`id`
+  </sql>
+
+  <!--累加做题记录-->
+  <update id="accumulation">
+    UPDATE `textbook_question`
+    <trim prefix="set" suffixOverrides=",">
+      `total_number`=`total_number`+#{number, jdbcType=INTEGER},
+      `total_time`=`total_time`+#{time, jdbcType=INTEGER},
+      `total_correct`=`total_correct`+#{correct, jdbcType=INTEGER},
+    </trim>
+    WHERE `id` = #{id, jdbcType=VARCHAR}
+  </update>
+
+  <select id="listAdmin" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `textbook_question` tq
+    <if test="paperId != null">
+      left join `textbook_paper` tp on find_in_set(tq.`id`, qn.`question_no_ids`)
+      and tp.`id` = #{paperId,jdbcType=VARCHAR}
+    </if>
+    where 1
+    <if test="paperId != null">
+      and tp.`id` != null
+    </if>
+    <if test="questionNoId != null">
+      and tq.`id` =#{questionNoId,jdbcType=VARCHAR}
+    </if>
+    <if test="questionType != null">
+      and tq.`question_type` =#{questionType,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+</mapper>

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

@@ -26,8 +26,8 @@
         and qn.`module` = #{module,jdbcType=VARCHAR}
       </if>
     left join `question` q on q.`id` = ucq.`question_id`
-      <if test="type != null">
-        and q.`type` = #{type,jdbcType=VARCHAR}
+      <if test="questionType != null">
+        and q.`question_type` = #{questionType,jdbcType=VARCHAR}
       </if>
     where
     qn.`id` != null

+ 17 - 15
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserNoteQuestionRelationMapper.xml

@@ -15,32 +15,34 @@
   </sql>
 
   <!--
-    用户预习作业列表: 后台
-    https://blog.csdn.net/t_1007/article/details/52369261
+    用户笔记题目列表
   -->
   <select id="list" resultMap="IdMap">
     select
     <include refid="Id_Column_List" />
-    from `user_paper` up
-    left join `homework_preview` hp on hp.`id` = up.`module_id`
-      and up.`module` = "homework_preview"
-      <if test="previewId != null">
-        and hp.`id` = #{previewId,jdbcType=VARCHAR}
-      </if>
-      <if test="category != null">
-        and hp.`category` = #{category,jdbcType=VARCHAR}
-      </if>
+    from `user_note_question` ucq
+    left join `question_no` qn on qn.`id` = ucq.`question_no_id`
+    <if test="module != null">
+      and qn.`module` = #{module,jdbcType=VARCHAR}
+    </if>
+    left join `question` q on q.`id` = ucq.`question_id`
+    <if test="questionType != null">
+      and q.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
     where
-    hp.`id` != null
+    qn.`id` != null
+    and q.`id` != null
     <if test="userId != null">
-      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      and ucq.`user_id` = #{userId,jdbcType=VARCHAR}
     </if>
     <if test="startTime != null">
-      and up.`createTime` &gt; #{startTime,jdbcType=VARCHAR}
+      and ucq.`createTime` &gt; #{startTime,jdbcType=VARCHAR}
     </if>
     <if test="endTime != null">
-      and up.`createTime` &lt; #{endTime,jdbcType=VARCHAR}
+      and ucq.`createTime` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
+
+    order by ${order} ${direction}
   </select>
 
 </mapper>

+ 24 - 1
server/data/src/main/resources/db/migration/V1__init_table.sql

@@ -8,4 +8,27 @@ CREATE TABLE manager (
   delete_time datetime DEFAULT NULL,
   PRIMARY KEY (id),
   UNIQUE KEY username (username,delete_time)
-) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='管理员账号';
+) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='管理员账号';
+
+INSERT INTO `exercise_struct` (`id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `question_status`, `is_sentence`, `is_examination`, `description`, `extend`)
+VALUES
+	(1, '长难句', '', 0, 0, 1, 0, 1, 0, '', 'sentence'),
+	(2, '语文', 'Verbial', 0, 0, 1, 0, 0, 1, '', 'verbial'),
+	(3, '数学', 'Quant', 0, 0, 1, 0, 0, 1, '', 'quant'),
+	(4, '综合推理', 'IR', 0, 0, 1, 0, 0, 1, '', 'ir'),
+	(5, '作文', 'AWA', 0, 0, 1, 0, 0, 1, '', 'awa'),
+	(6, '句改', 'SC', 2, 0, 2, 0, 0, 1, NULL, 'sc'),
+	(7, '阅读', 'RC', 2, 0, 2, 0, 0, 1, NULL, 'rc'),
+	(8, '逻辑', 'CR', 2, 0, 2, 0, 0, 1, NULL, 'cr'),
+	(9, '充分性分析', 'DS', 3, 0, 2, 0, 0, 1, NULL, 'ds'),
+	(10, '问题求解', 'PS', 3, 0, 2, 0, 0, 1, NULL, 'ps'),
+	(11, '综合推理', 'IR', 4, 0, 2, 0, 0, 1, NULL, 'ir'),
+	(12, '写作', 'AWA', 5, 0, 2, 0, 0, 1, NULL, 'awa');
+
+INSERT INTO `examination_struct` (`id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `is_adapt`, `extend`, `description`)
+VALUES
+	(1, 'CAT 难度适应性', '', 0, 0, 1, 1, 'base', NULL),
+	(2, '非难度适应性', '', 0, 0, 1, 0, 'base', NULL),
+	(3, '千行CAT', '', 1, 0, 2, 1, 'qx_cat', NULL),
+	(4, '净化版PREP-CAT', '', 1, 0, 2, 1, NULL, NULL),
+	(5, 'GWD-CAT', '', 1, 0, 2, 1, NULL, NULL);

+ 1 - 1
server/data/src/main/resources/mybatis-generator.xml

@@ -100,7 +100,6 @@
         </table>
         <table schema="qianxing" tableName="exercise_paper" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" delimitAllColumns="true">
             <generatedKey column="id" sqlStatement="Mysql" identity="true"/>
-            <columnOverride column="struct_parent" javaType="Integer[]" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayHandler"/>
             <columnOverride column="question_no_ids" javaType="Integer[]" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler"/>
         </table>
         <table schema="qianxing" tableName="examination_paper" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" delimitAllColumns="true">
@@ -130,6 +129,7 @@
             <columnOverride column="answer" javaType="com.alibaba.fastjson.JSONObject" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler"/>
             <columnOverride column="content" javaType="com.alibaba.fastjson.JSONObject" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler"/>
             <columnOverride column="association_content" javaType="Integer[]" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler"/>
+            <columnOverride column="answer_distributed" javaType="com.alibaba.fastjson.JSONObject" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler"/>
         </table>
         <table schema="qianxing" tableName="question_no" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" delimitAllColumns="true">
             <generatedKey column="id" sqlStatement="Mysql" identity="true"/>

+ 4 - 0
server/gateway-api/build.gradle

@@ -22,6 +22,10 @@ dependencies {
 
     compileClasspath 'com.github.penggle:kaptcha:2.3.2'
 
+    // https://mvnrepository.com/artifact/org.apache.poi/poi
+    compile group: 'org.apache.poi', name: 'poi', version: '3.17'
+
+
 //    compile group: 'commons-lang', name: 'commons-lang', version:'2.6'
 //    compile group: 'commons-fileupload', name: 'commons-fileupload', version:'1.3.3'
 //    compile group: 'commons-io', name: 'commons-io', version:'2.6'

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

@@ -25,3 +25,8 @@ public class Application {
         SpringApplication.run(Application.class, args);
     }
 }
+
+// 练习结构扩展 - 后台限定编辑功能,不同层级设定不同,第一第二层固定存在,写入数据库
+// 模考时间设定 - 读取练习结构
+// 预习作业添加模式:用于主动发送用户
+// 课程与预习作业关系,分册进度

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

@@ -32,7 +32,7 @@ public class ExaminationController {
     @ApiOperation(value = "添加模考层级", httpMethod = "POST")
     public Response<ExaminationStruct> add(@RequestBody @Validated ExaminationStructDto dto, HttpServletRequest request) {
         ExaminationStruct entity = Transform.dtoToEntity(dto);
-        entity = examinationStructService.edit(entity);
+        entity = examinationStructService.addPaper(entity);
         managerLogService.log(request);
         return ResponseHelp.success(entity);
     }
@@ -40,7 +40,7 @@ public class ExaminationController {
     @ApiOperation(value = "编辑模考层级", httpMethod = "PUT")
     public Response<Boolean> edit(@RequestBody @Validated ExaminationStructDto dto, HttpServletRequest request) {
         ExaminationStruct entity = Transform.dtoToEntity(dto);
-        entity = examinationStructService.edit(entity);
+        entity = examinationStructService.editPaper(entity);
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }
@@ -48,8 +48,9 @@ public class ExaminationController {
     @RequestMapping(value = "/struct/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除模考层级", httpMethod = "DELETE")
     public Response<Boolean> delete(@RequestParam int id, HttpServletRequest request) {
+        boolean result = examinationStructService.deletePaper(id);
         managerLogService.log(request);
-        return ResponseHelp.success(examinationStructService.delete(id));
+        return ResponseHelp.success(result);
     }
 
     @RequestMapping(value = "/struct/all", method = RequestMethod.GET)

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

@@ -36,6 +36,7 @@ import java.util.List;
 @RequestMapping("/admin/exercise")
 @Api(tags = "练习接口", description = "练习相关", produces = MediaType.APPLICATION_JSON_VALUE)
 public class ExerciseController {
+
     @Autowired
     private ManagerLogService managerLogService;
 
@@ -85,7 +86,6 @@ public class ExerciseController {
         return ResponseHelp.success(exerciseStructService.delete(id));
     }
 
-
     @RequestMapping(value = "/struct/all", method = RequestMethod.GET)
     @ApiOperation(value = "所有练习层级", httpMethod = "GET")
     public Response<List<ExerciseStruct>> all(HttpSession session) {
@@ -93,7 +93,6 @@ public class ExerciseController {
         return ResponseHelp.success(p);
     }
 
-
     @RequestMapping(value = "/paper/list", method = RequestMethod.GET)
     @ApiOperation(value = "练习册列表", httpMethod = "GET")
     public Response<PageMessage<ExercisePaperListDto>> listPaper(

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

@@ -12,13 +12,24 @@ import com.qxgmat.service.inline.RankService;
 import com.qxgmat.service.inline.SettingService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.apache.poi.hssf.usermodel.HSSFCell;
+import org.apache.poi.hssf.usermodel.HSSFRow;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
 
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
 import java.util.List;
 
 
@@ -130,13 +141,30 @@ public class SettingController {
     }
 
     @RequestMapping(value = "/filter_time", method = RequestMethod.GET)
-    @ApiOperation(value = "获取做题时间配置", httpMethod = "GET")
+    @ApiOperation(value = "获取剔除时间配置", httpMethod = "GET")
     private Response<JSONObject> getFilterTime(){
         Setting entity = settingService.getByKey(SettingKey.FILTER_TIME);
 
         return ResponseHelp.success(entity.getValue());
     }
 
+    @RequestMapping(value = "/sentence_time", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改长难句时间设置", httpMethod = "PUT")
+    private Response<Boolean> editSentenceTime(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.SENTENCE_TIME);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/sentence_time", method = RequestMethod.GET)
+    @ApiOperation(value = "获取长难句时间配置", httpMethod = "GET")
+    private Response<JSONObject> getSentenceTime(){
+        Setting entity = settingService.getByKey(SettingKey.SENTENCE_TIME);
+
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/tips", method = RequestMethod.PUT)
     @ApiOperation(value = "修改结构说明", httpMethod = "PUT")
     private Response<Boolean> editTips(@RequestBody @Validated JSONObject dto){
@@ -183,4 +211,46 @@ public class SettingController {
         List<Rank> rankList = rankService.all();
         return ResponseHelp.success(rankList);
     }
+
+    @RequestMapping(value = "/rank/import", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE, method = RequestMethod.POST)
+    @ApiOperation(value = "导入排行数据", httpMethod = "POST")
+    private Response<Boolean> importRank(@RequestParam("file") MultipartFile multipartFile) throws IOException {
+        // 删除所有排行数据, 并导入excel数据
+        // 读取文件
+        InputStream is = new FileInputStream("002.xls");
+        // 将文件流解析成 POI 文档
+        POIFSFileSystem fs = new POIFSFileSystem(is);
+        // 再将 POI 文档解析成 Excel 工作簿
+        HSSFWorkbook wb = new HSSFWorkbook(fs);
+        HSSFRow row = null;
+        HSSFCell cell = null;
+        // 得到第 1 个工作簿
+        HSSFSheet sheet = wb.getSheetAt(0);
+        // 得到这一行一共有多少列
+        int totalColumns = sheet.getRow(0).getPhysicalNumberOfCells();
+        // 得到最后一行的坐标
+        Integer lastRowNum = sheet.getLastRowNum();
+        System.out.println("lastRowNum => " + lastRowNum);
+
+        List<Rank> rankList = new ArrayList<>();
+        Rank rank = null;
+        String cellValue = null;
+
+        // 从第 2 行开始读
+        for(int i=1;i<=lastRowNum;i++){
+            row = sheet.getRow(i);
+            rank = new Rank();
+            for(int j=0;j<totalColumns;j++){
+                cell = row.getCell(j);
+                if(cell!=null){
+                    cellValue = cell.getStringCellValue();
+                }else {
+                    cellValue = "【没有数据】";
+                }
+            }
+            rankList.add(rank);
+        }
+        rankService.replaceAll(rankList);
+        return ResponseHelp.success(true);
+    }
 }

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

@@ -0,0 +1,125 @@
+package com.qxgmat.controller.admin;
+
+
+import com.alibaba.fastjson.JSONObject;
+import com.github.pagehelper.Page;
+import com.nuliji.tools.*;
+import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.constants.enums.QuestionType;
+import com.qxgmat.data.constants.enums.SettingKey;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
+import com.qxgmat.dto.admin.extend.ExercisePaperExtendDto;
+import com.qxgmat.dto.admin.extend.QuestionExtendDto;
+import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
+import com.qxgmat.dto.admin.request.ExerciseStructDto;
+import com.qxgmat.dto.admin.request.QuestionNoSearchDto;
+import com.qxgmat.dto.admin.response.ExercisePaperListDto;
+import com.qxgmat.dto.admin.response.ExerciseQuestionListDto;
+import com.qxgmat.dto.admin.response.TextbookPaperListDto;
+import com.qxgmat.dto.admin.response.TextbookQuestionListDto;
+import com.qxgmat.service.ExercisePaperService;
+import com.qxgmat.service.TextbookPaperService;
+import com.qxgmat.service.inline.*;
+import com.qxgmat.task.AsyncTask;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.util.Collection;
+import java.util.List;
+
+@RestController("AdminTextbookController")
+@RequestMapping("/admin/textbookl")
+@Api(tags = "机经接口", description = "机经相关", produces = MediaType.APPLICATION_JSON_VALUE)
+public class TextbookController {
+
+    @Autowired
+    private ManagerLogService managerLogService;
+
+    @Autowired
+    private TextbookQuestionService textbookQuestionService;
+
+    @Autowired
+    private TextbookPaperService textbookPaperService;
+
+    @Autowired
+    private AsyncTask asyncTask;
+
+    @RequestMapping(value = "/question/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加机经题目", httpMethod = "POST")
+    public Response<TextbookQuestion> addQuestion(@RequestBody @Validated TextbookQuestionRelation dto, HttpServletRequest request) {
+//        SentenceQuestion entity = Transform.dtoToEntity(dto);
+        TextbookQuestion entity = textbookPaperService.addQuestion(dto);
+        managerLogService.log(request);
+        return ResponseHelp.success(entity);
+    }
+    @RequestMapping(value = "/question/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改机经题目", httpMethod = "PUT")
+    public Response<Boolean> editQuestion(@RequestBody @Validated TextbookQuestionRelation dto, HttpServletRequest request) {
+//        SentenceQuestion entity = Transform.dtoToEntity(dto);
+        TextbookQuestion entity = textbookPaperService.editQuestion(dto);
+        managerLogService.log(request);
+        return ResponseHelp.success(true);
+    }
+
+//    @RequestMapping(value = "/question/delete", method = RequestMethod.DELETE)
+//    @ApiOperation(value = "删除机经题目", httpMethod = "DELETE")
+//    public Response<Boolean> deleteQuestion(@RequestParam int id, HttpServletRequest request) {
+//        managerLogService.log(request);
+//        return ResponseHelp.success(sentenceQuestionService.delete(id));
+//    }
+
+    @RequestMapping(value = "/question/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "获取机经题目", httpMethod = "GET")
+    public Response<TextbookQuestionRelation> detailQuestion(@RequestParam int id, HttpSession session) {
+        TextbookQuestion entity = textbookQuestionService.get(id);
+        TextbookQuestionRelation relation = textbookQuestionService.relation(entity);
+        return ResponseHelp.success(relation);
+    }
+
+    @RequestMapping(value = "/question/list", method = RequestMethod.GET)
+    @ApiOperation(value = "试题列表", httpMethod = "GET")
+    public Response<PageMessage<TextbookQuestionListDto>> listQuestion(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String type,
+            @RequestParam(required = false) Integer paperId,
+            @RequestParam(required = false) Integer questionNoId,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction,
+            HttpSession session) {
+        Page<TextbookQuestion> p = textbookQuestionService.listAdmin(page, size, type, paperId, questionNoId, order, DirectionStatus.ValueOf(direction));
+        List<TextbookQuestionListDto> pr = Transform.convert(p, TextbookQuestionListDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/search/no", method = RequestMethod.POST)
+    @ApiOperation(value = "搜索题目编号列表:题目编号搜索", httpMethod = "POST")
+    public Response<PageMessage<TextbookQuestionListDto>> searchNo(@RequestBody @Validated QuestionNoSearchDto dto, HttpServletRequest request) {
+        PageResult<TextbookQuestionRelation> p = textbookQuestionService.searchNo(dto.getPage(), dto.getSize(), dto.getNo());
+        List<TextbookQuestionListDto> pr = Transform.convert(p, TextbookQuestionListDto.class);
+
+        return ResponseHelp.success(pr, dto.getPage(), dto.getSize(), p.getTotal());
+    }
+
+    @RequestMapping(value = "/paper/list", method = RequestMethod.GET)
+    @ApiOperation(value = "练习册列表", httpMethod = "GET")
+    public Response<PageMessage<TextbookPaperListDto>> listPaper(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false, defaultValue = "") String keyword,
+            HttpSession session) {
+        Page<TextbookPaper> p = textbookPaperService.select(page, size, keyword);
+        List<TextbookPaperListDto> pr = Transform.convert(p, TextbookPaperListDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+}

+ 10 - 14
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserAskController.java

@@ -62,30 +62,26 @@ public class UserAskController {
     @ApiOperation(value = "修改提问信息", httpMethod = "PUT")
     public Response<Boolean> edit(@RequestBody @Validated UserAskDto dto, HttpServletRequest request) {
         UserAskQuestion entity = Transform.dtoToEntity(dto);
-        if(!entity.getAnswer().isEmpty()){
-
+        UserAskQuestion in = userAskQuestionService.get(entity.getId());
+        // 调整回答
+        if(!entity.getAnswer().isEmpty() || !in.getAnswer().equals(entity.getAnswer())){
             entity.setAnswerTime(new Date());
             entity.setAnswerStatus(AskStatus.ANSWER.index);
+            Manager manager = shiroHelp.getLoginManager();
+            entity.setManagerId(manager.getId());
         }
 
-        Manager manager = shiroHelp.getLoginManager();
-        entity.setManagerId(manager.getId());
         entity = userAskQuestionService.edit(entity);
 
-        // 更新回答排序
-        userAskQuestionService.updateOrder(dto.getOther());
+        if (dto.getOther() !=null && dto.getOther().length > 0){
+            // 更新回答排序
+            userAskQuestionService.updateOrder(dto.getOther());
+        }
 
         managerLogService.log(request);
         return ResponseHelp.success(true);
     }
 
-//    @RequestMapping(value = "/order", method = RequestMethod.PUT)
-//    @ApiOperation(value = "修改提问排序", httpMethod = "PUT")
-//    public Response<Boolean> order(@RequestBody @Validated UserAskOrderDto dto, HttpServletRequest request) {
-//        userAskQuestionService.order(dto.getId(), dto.getOrder());
-//        return ResponseHelp.success(true);
-//    }
-
     @RequestMapping(value = "/detail", method = RequestMethod.GET)
     @ApiOperation(value = "提问详情", httpMethod = "GET")
     public Response<UserAskDetailDto> detail(@RequestParam int id, HttpServletRequest request) {
@@ -108,7 +104,7 @@ public class UserAskController {
         dto.setQuestionNo(Transform.convert(questionNo, QuestionNoExtendDto.class));
 
         // 所有回答
-        List<UserAskQuestion> userAskList = userAskQuestionService.listByQuestion(entity.getQuestionId(), null);
+        List<UserAskQuestion> userAskList = userAskQuestionService.listByQuestion(entity.getQuestionId(), true);
         dto.setOthers(Transform.convert(userAskList, UserAskExtendDto.class));
         return ResponseHelp.success(dto);
     }

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

@@ -112,6 +112,29 @@ public class UserController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/members", method = RequestMethod.GET)
+    @ApiOperation(value = "会员列表", httpMethod = "GET")
+    public Response<PageMessage<UserListDto>> members(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false, defaultValue = "") String keyword,
+            @RequestParam(required = false) Boolean real,
+            @RequestParam(required = false) String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction,
+            HttpSession session) {
+        // 已经购买过课程的用户
+        Page<User> p = usersService.select(page, size, keyword, real, order, DirectionStatus.ValueOf(direction));
+        List<UserListDto> pr = Transform.convert(p, UserListDto.class);
+
+        Collection userIds = Transform.getIds(p, User.class, "id");
+
+        // 绑定用户课程
+        Map<Object, Collection<UserClass>> classByUser = userClassService.mapByUser(userIds);
+        Transform.combine(pr, classByUser, UserListDto.class, "id", "classes", UserClassExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/pay/list", method = RequestMethod.GET)
     @ApiOperation(value = "用户消费列表", httpMethod = "GET")
     public Response<PageMessage<UserListDto>> listPay(

+ 33 - 2
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserFeedbackErrorController.java

@@ -5,11 +5,16 @@ import com.nuliji.tools.PageMessage;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.module.FeedbackModule;
+import com.qxgmat.data.constants.enums.status.AskStatus;
+import com.qxgmat.data.constants.enums.status.FeedbackStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
+import com.qxgmat.dto.admin.request.UserFeedbackErrorDto;
 import com.qxgmat.dto.admin.response.UserFeedbackErrorDetailDto;
 import com.qxgmat.dto.admin.response.UserFeedbackErrorListDto;
 import com.qxgmat.dto.admin.response.UserAskListDto;
+import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.UserFeedbackErrorService;
 import com.qxgmat.service.inline.ManagerLogService;
@@ -17,11 +22,13 @@ import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
 import java.util.Collection;
+import java.util.Date;
 import java.util.List;
 
 @RestController("AdminFeedbackErrorController")
@@ -30,6 +37,8 @@ import java.util.List;
 public class UserFeedbackErrorController {
     @Autowired
     private ManagerLogService managerLogService;
+    @Autowired
+    private ShiroHelp shiroHelp;
 
     @Autowired
     private UserFeedbackErrorService userFeedbackErrorService;
@@ -38,8 +47,27 @@ public class UserFeedbackErrorController {
     private UsersService usersService;
 
 
+    @RequestMapping(value = "/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改勘误信息", httpMethod = "PUT")
+    public Response<Boolean> edit(@RequestBody @Validated UserFeedbackErrorDto dto, HttpServletRequest request) {
+        UserFeedbackError entity = Transform.dtoToEntity(dto);
+        UserFeedbackError in = userFeedbackErrorService.get(entity.getId());
+
+        // 处理设定
+        if(in.getHandleTime() == null){
+            entity.setHandleTime(new Date());
+            Manager manager = shiroHelp.getLoginManager();
+            entity.setManagerId(manager.getId());
+        }
+
+        entity = userFeedbackErrorService.edit(entity);
+
+        managerLogService.log(request);
+        return ResponseHelp.success(true);
+    }
+
     @RequestMapping(value = "/detail", method = RequestMethod.GET)
-    @ApiOperation(value = "修改提问排序", httpMethod = "GET")
+    @ApiOperation(value = "勘误详情", httpMethod = "GET")
     public Response<UserFeedbackErrorDetailDto> detail(@RequestParam int id, HttpServletRequest request) {
         UserFeedbackError entity = userFeedbackErrorService.get(id);
         UserFeedbackErrorDetailDto dto = Transform.convert(entity, UserFeedbackErrorDetailDto.class);
@@ -52,8 +80,11 @@ public class UserFeedbackErrorController {
     public Response<PageMessage<UserFeedbackErrorListDto>> list(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String module,
+            @RequestParam(required = false) Integer status,
+            @RequestParam(required = false) String keyword,
             HttpSession session) {
-        Page<UserFeedbackError> p = userFeedbackErrorService.select(page, size);
+        Page<UserFeedbackError> p = userFeedbackErrorService.listAdmin(page, size, FeedbackModule.ValueOf(module), FeedbackStatus.ValueOf(status), keyword);
         List<UserFeedbackErrorListDto> pr = Transform.convert(p, UserFeedbackErrorListDto.class);
 
         // 绑定用户

+ 27 - 7
server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java

@@ -77,17 +77,37 @@ public class BaseController {
         return ResponseHelp.success(rank);
     }
 
-    @RequestMapping(value = "/exercise/struct", method = RequestMethod.GET)
+    @RequestMapping(value = "/exercise/main", method = RequestMethod.GET)
+    @ApiOperation(value = "所有练习头2层", httpMethod = "GET")
+    public Response<List<ExerciseStruct>> exerciseMain(HttpSession session) {
+        List<ExerciseStruct> p = exerciseStructService.main();
+        return ResponseHelp.success(p);
+    }
+
+    @RequestMapping(value = "/exercise/children", method = RequestMethod.GET)
     @ApiOperation(value = "所有练习层级", httpMethod = "GET")
-    public Response<List<ExerciseStruct>> exerciseStruct(HttpSession session) {
-        List<ExerciseStruct> p = exerciseStructService.all();
+    public Response<List<ExerciseStruct>> exerciseChildren(
+            @RequestParam(required = true) Integer id,
+            @RequestParam(required = false, defaultValue = "false") boolean children,
+            HttpSession session) {
+        List<ExerciseStruct> p = exerciseStructService.children(id, children);
         return ResponseHelp.success(p);
     }
 
-    @RequestMapping(value = "/examination/struct", method = RequestMethod.GET)
-    @ApiOperation(value = "所有模考层级", httpMethod = "GET")
-    public Response<List<ExaminationStruct>> examinationStruct(HttpSession session) {
-        List<ExaminationStruct> p = examinationStructService.all();
+    @RequestMapping(value = "/examination/main", method = RequestMethod.GET)
+    @ApiOperation(value = "所有模考头2层", httpMethod = "GET")
+    public Response<List<ExaminationStruct>> examinationMain(HttpSession session) {
+        List<ExaminationStruct> p = examinationStructService.main();
+        return ResponseHelp.success(p);
+    }
+
+    @RequestMapping(value = "/examination/children", method = RequestMethod.GET)
+    @ApiOperation(value = "所有练习层级", httpMethod = "GET")
+    public Response<List<ExaminationStruct>> examinationChildren(
+            @RequestParam(required = true) Integer id,
+            @RequestParam(required = false, defaultValue = "false") boolean children,
+            HttpSession session) {
+        List<ExaminationStruct> p = examinationStructService.children(id, children);
         return ResponseHelp.success(p);
     }
 }

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


Some files were not shown because too many files changed in this diff