Browse Source

feat(server): ready后台

Go 5 years ago
parent
commit
2eebcd3baf
96 changed files with 4210 additions and 591 deletions
  1. 4 2
      front/project/Constant.js
  2. 4 0
      front/project/admin/routes/course/data/page.js
  3. 15 0
      front/project/admin/routes/ready/article/index.js
  4. 3 0
      front/project/admin/routes/ready/article/index.less
  5. 60 17
      front/project/admin/routes/show/article/page.js
  6. 16 0
      front/project/admin/routes/ready/articleDetail/index.js
  7. 0 0
      front/project/admin/routes/ready/articleDetail/index.less
  8. 174 0
      front/project/admin/routes/ready/articleDetail/page.js
  9. 6 2
      front/project/admin/routes/ready/index.js
  10. 2 2
      front/project/admin/routes/show/article/index.js
  11. 1 1
      front/project/admin/routes/show/article/index.less
  12. 190 0
      front/project/admin/routes/ready/read/page.js
  13. 4 4
      front/project/admin/routes/show/articleDetail/index.js
  14. 3 0
      front/project/admin/routes/ready/readDetail/index.less
  15. 29 18
      front/project/admin/routes/show/articleDetail/page.js
  16. 15 0
      front/project/admin/routes/ready/room/index.js
  17. 3 0
      front/project/admin/routes/ready/room/index.less
  18. 199 0
      front/project/admin/routes/ready/room/page.js
  19. 15 0
      front/project/admin/routes/setting/contract/index.js
  20. 3 0
      front/project/admin/routes/setting/contract/index.less
  21. 54 0
      front/project/admin/routes/setting/contract/page.js
  22. 16 0
      front/project/admin/routes/setting/contractDetail/index.js
  23. 3 0
      front/project/admin/routes/setting/contractDetail/index.less
  24. 100 0
      front/project/admin/routes/setting/contractDetail/page.js
  25. 3 1
      front/project/admin/routes/setting/index.js
  26. 69 3
      front/project/admin/routes/setting/promote/page.js
  27. 1 3
      front/project/admin/routes/show/index.js
  28. 2 0
      front/project/admin/routes/user/orderDetail/page.js
  29. 2 1
      front/project/admin/stores/index.js
  30. 83 0
      front/project/admin/stores/ready.js
  31. 12 20
      front/project/admin/stores/system.js
  32. 20 0
      front/project/h5/stores/main.js
  33. 10 1
      front/project/www/routes/exercise/main/page.js
  34. 4 0
      front/project/www/routes/paper/report/index.less
  35. 157 60
      front/project/www/routes/paper/report/page.js
  36. 18 2
      front/project/www/stores/main.js
  37. 2 1
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  38. 1 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/trade/RecordSource.java
  39. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/ArticleMapper.java
  40. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ContractMapper.java
  41. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ReadyArticleCategoryMapper.java
  42. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ReadyArticleMapper.java
  43. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ReadyReadMapper.java
  44. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ReadyRoomAreaMapper.java
  45. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/ReadyRoomMapper.java
  46. 212 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/Contract.java
  47. 291 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyArticle.java
  48. 186 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyArticleCategory.java
  49. 23 58
      server/data/src/main/java/com/qxgmat/data/dao/entity/Article.java
  50. 326 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyRoom.java
  51. 167 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyRoomArea.java
  52. 5 6
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ArticleMapper.xml
  53. 20 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyArticleCategoryMapper.xml
  54. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyArticleMapper.xml
  55. 32 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyReadMapper.xml
  56. 20 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyRoomAreaMapper.xml
  57. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyRoomMapper.xml
  58. 4 4
      server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java
  59. 4 4
      server/data/src/main/java/com/qxgmat/data/relation/UserCollectQuestionRelationMapper.java
  60. 4 4
      server/data/src/main/java/com/qxgmat/data/relation/UserNoteQuestionRelationMapper.java
  61. 6 6
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java
  62. 4 4
      server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java
  63. 22 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml
  64. 30 8
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCollectQuestionRelationMapper.xml
  65. 22 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserNoteQuestionRelationMapper.xml
  66. 28 3
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml
  67. 28 6
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml
  68. 3 2
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  69. 204 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/ReadyController.java
  70. 42 47
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  71. 30 7
      server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java
  72. 22 22
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  73. 3 2
      server/gateway-api/src/main/java/com/qxgmat/controller/api/OrderController.java
  74. 55 11
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  75. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/ContractDto.java
  76. 0 7
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/QuestionNoSearchDto.java
  77. 78 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/ReadyArticleDto.java
  78. 8 18
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/ArticleDto.java
  79. 78 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/ReadyRoomDto.java
  80. 17 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/OrderConfirmDto.java
  81. 55 14
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionBaseDto.java
  82. 4 16
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java
  83. 4 16
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  84. 6 27
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  85. 4 18
      server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java
  86. 63 5
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  87. 63 5
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java
  88. 0 4
      server/gateway-api/src/main/java/com/qxgmat/service/inline/AdService.java
  89. 0 102
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ArticleService.java
  90. 103 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ContractService.java
  91. 103 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyArticleCategoryService.java
  92. 100 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyArticleService.java
  93. 93 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyReadService.java
  94. 82 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyRoomAreaService.java
  95. 100 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyRoomService.java
  96. 4 16
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java

File diff suppressed because it is too large
+ 4 - 2
front/project/Constant.js


+ 4 - 0
front/project/admin/routes/course/data/page.js

@@ -77,9 +77,13 @@ export default class extends Page {
       dataIndex: 'title',
     }, {
       title: '查看人数',
+      sorter: true,
+      sortDirections: ['ascend'],
       dataIndex: 'viewNumber',
     }, {
       title: '购买人数',
+      sorter: true,
+      sortDirections: ['descend'],
       dataIndex: 'saleNumber',
     }, {
       title: '更新时间',

+ 15 - 0
front/project/admin/routes/ready/article/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/ready/article',
+  key: 'ready-article',
+  title: '文章',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/ready/article/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#ready-article {}

+ 60 - 17
front/project/admin/routes/show/article/page.js

@@ -8,26 +8,34 @@ import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { formatDate, getMap } from '@src/services/Tools';
-import { ArticleChannel } from '../../../../Constant';
-import { System } from '../../../stores/system';
+import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
+// import { ArticleChannel } from '../../../../Constant';
+import { Ready } from '../../../stores/ready';
 
-const ArticleChannelMap = getMap(ArticleChannel, 'value', 'label');
+// const ArticleChannelMap = getMap(ArticleChannel, 'value', 'label');
 
 export default class extends Page {
   init() {
+    this.categoryMap = {};
+    this.categoryList = [];
     this.filterForm = [{
-      key: 'channel',
+      key: 'parentCategoryId',
       type: 'select',
       allowClear: true,
-      name: '频道',
-      select: ArticleChannel,
+      name: '一级标题',
       placeholder: '请选择',
+      select: [],
+      number: true,
+      onChange: (value) => {
+        this.onChangeSearch(this.filterForm, value);
+      },
     }, {
-      key: 'position',
+      key: 'categoryId',
       type: 'select',
       allowClear: true,
-      name: '位置',
+      name: '二级标题',
       select: [],
+      number: true,
       placeholder: '请选择',
     }];
     this.actionList = [{
@@ -35,18 +43,21 @@ export default class extends Page {
       type: 'primary',
       name: '创建',
       render: (item) => {
-        return <Link to='/show/article/detail'><Button>{item.name}</Button></Link>;
+        return <Link to='/ready/article/detail'><Button>{item.name}</Button></Link>;
       },
     }];
     this.columns = [{
-      title: '频道',
-      dataIndex: 'channel',
+      title: '一级标题',
+      dataIndex: 'parentCategoryId',
       render: (text) => {
-        return ArticleChannelMap[text] || '';
+        return this.categoryMap[text];
       },
     }, {
-      title: '位置',
-      dataIndex: 'position',
+      title: '二级标题',
+      dataIndex: 'categoryId',
+      render: (text) => {
+        return this.categoryMap[text];
+      },
     }, {
       title: '文章标题',
       dataIndex: 'title',
@@ -61,18 +72,51 @@ export default class extends Page {
       dataIndex: 'handler',
       render: (text, record) => {
         return <div className="table-button">
-          {<Link to={`/show/article/detail/${record.id}`}>编辑</Link>}
+          {<Link to={`/ready/article/detail/${record.id}`}>编辑</Link>}
+          {<a onClick={() => {
+            this.deleteAction(record);
+          }}>删除</a>}
         </div>;
       },
     }];
+    Ready.allCategory().then(result => {
+      this.categoryList = result.map(row => {
+        row.value = row.id;
+        return row;
+      });
+      this.categoryMap = getMap(result, 'id', 'title');
+      this.filterForm[0].select = this.categoryList.filter(row => row.parentId === 0);
+      this.onChangeSearch(this.filterForm, this.state.search.parentCategoryId);
+      this.initData();
+    });
+  }
+
+  onChangeSearch(list, value) {
+    if (value) {
+      list[1].disabled = false;
+      list[1].select = this.categoryList.filter(row => row.parentId === value);
+    } else {
+      list[1].disabled = true;
+      list[1].select = [];
+    }
   }
 
   initData() {
-    System.listArticle(this.state.search).then(result => {
+    Ready.listArticle(this.state.search).then(result => {
       this.setTableData(result.list, result.total);
     });
   }
 
+  deleteAction(row) {
+    asyncDelConfirm('删除确认', '是否删除选中?', () => {
+      const handler = Ready.delArticle({ id: row.id });
+      return handler.then(() => {
+        asyncSMessage('删除成功!');
+        this.refresh();
+      });
+    });
+  }
+
   renderView() {
     return <Block flex>
       <FilterLayout
@@ -88,7 +132,6 @@ export default class extends Page {
         onAction={key => this.onAction(key)}
       />
       <TableLayout
-        select
         columns={this.tableSort(this.columns)}
         list={this.state.list}
         pagination={this.state.page}

+ 16 - 0
front/project/admin/routes/ready/articleDetail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/ready/article/detail',
+  matchPath: '/ready/article/detail/:id?',
+  key: 'ready-article-detail',
+  title: '文章编辑',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'ready-article',
+  component() {
+    return import('./page');
+  },
+};

front/project/admin/routes/show/articleDetail/index.less → front/project/admin/routes/ready/articleDetail/index.less


+ 174 - 0
front/project/admin/routes/ready/articleDetail/page.js

@@ -0,0 +1,174 @@
+import React from 'react';
+import { Form, Input, Button, Row, Col } from 'antd';
+import './index.less';
+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, getMap } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { Ready } from '../../../stores/ready';
+
+export default class extends Page {
+  init() {
+    Ready.allCategory().then(result => {
+      this.categoryList = result.map(row => {
+        row.value = row.id;
+        return row;
+      });
+      this.categoryMap = getMap(result, 'id', 'title');
+      const select = this.categoryList.filter(row => row.parentId === 0);
+      select.push({ label: '其他', value: 0 });
+      this.setState({
+        parentCategoryId: {
+          select,
+        },
+      });
+      this.initData();
+    });
+  }
+
+  onChangeSearch(parentValue, value) {
+    const { setFieldsValue } = this.props.form;
+    const info = {};
+    let showParentCategory = false;
+    let showCategory = false;
+    if (parentValue) {
+      info.disabled = false;
+      info.select = this.categoryList.filter(row => row.parentId === parentValue);
+      info.select.push({ label: '其他', value: 0 });
+      if (value === 0) {
+        showCategory = true;
+      } else if (!value) {
+        setFieldsValue({ categoryId: null });
+      }
+    } else if (parentValue === 0) {
+      showParentCategory = true;
+      showCategory = true;
+      info.disabled = true;
+      info.select = [];
+      setFieldsValue({ categoryId: null });
+    } else {
+      info.disabled = true;
+      info.select = [];
+    }
+    this.setState({
+      showParentCategory,
+      showCategory,
+      categoryId: info,
+    });
+  }
+
+  initData() {
+    if (!this.categoryList) return;
+    const { id } = this.params;
+    const { form } = this.props;
+    let handler;
+    if (id) {
+      handler = Ready.getArticle({ id });
+    } else {
+      handler = Promise.resolve({});
+    }
+
+    handler
+      .then(result => {
+        form.setFieldsValue(result);
+        this.onChangeSearch(result.parentCategoryId, result.categoryId);
+      });
+  }
+
+  submit() {
+    const { form } = this.props;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        let handler;
+        if (data.id) {
+          handler = Ready.editArticle(data);
+        } else {
+          handler = Ready.addArticle(data);
+        }
+        handler.then(() => {
+          asyncSMessage('保存成功');
+          goBack();
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderBase() {
+    const { getFieldDecorator, getFieldValue } = this.props.form;
+    return <Block>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='一级标题'>
+          {getFieldDecorator('parentCategoryId', {
+            rules: [
+              { required: !this.state.showParentCategory, message: '请选择标题' },
+            ],
+          })(
+            <Select {...this.state.parentCategoryId} placeholder='请选择标题' onChange={(value) => {
+              this.onChangeSearch(value, null);
+            }} />,
+          )}
+          {this.state.showParentCategory && getFieldDecorator('parentCategory', {
+            rules: [
+              { required: true, message: '请输入标题' },
+            ],
+          })(
+            <Input placeholder='请输入标题' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='二级标题'>
+          {getFieldDecorator('categoryId', {
+            rules: [
+              { required: !this.state.showCategory, message: '请选择标题' },
+            ],
+          })(
+            <Select {...this.state.categoryId} placeholder='请选择标题' onChange={(value) => {
+              this.onChangeSearch(getFieldValue('parentCategoryId'), value);
+            }} />,
+          )}
+          {this.state.showCategory && getFieldDecorator('category', {
+            rules: [
+              { required: true, message: '请输入标题' },
+            ],
+          })(
+            <Input placeholder='请输入标题' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='文章标题'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入标题' },
+            ],
+          })(
+            <Input placeholder='请输入标题' />,
+          )}
+        </Form.Item>
+        <Form.Item label='正文'>
+          {getFieldDecorator('content', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderView() {
+    return <div flex>
+      {this.renderBase()}
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

+ 6 - 2
front/project/admin/routes/ready/index.js

@@ -1,3 +1,7 @@
+import article from './article';
+import articleDetail from './articleDetail';
+import room from './room';
+import read from './read';
+import readDetail from './readDetail';
 
-
-export default [];
+export default [article, articleDetail, room, read, readDetail];

+ 2 - 2
front/project/admin/routes/show/article/index.js

@@ -2,8 +2,8 @@ import module from '../../module';
 import group from '../group';
 
 export default {
-  path: '/show/article',
-  key: 'show-article',
+  path: '/ready/read',
+  key: 'ready-read',
   title: '推荐阅读',
   needLogin: true,
   module,

+ 1 - 1
front/project/admin/routes/show/article/index.less

@@ -1,3 +1,3 @@
 @charset "utf-8";
 
-#show-article {}
+#ready-read {}

+ 190 - 0
front/project/admin/routes/ready/read/page.js

@@ -0,0 +1,190 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button, Switch, Modal } from 'antd';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import EditTableCell from '@src/components/EditTableCell';
+// import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { formatDate, getMap } from '@src/services/Tools';
+import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
+// import { SwitchSelect } from '../../../../Constant';
+import { Ready } from '../../../stores/ready';
+
+export default class extends Page {
+  init() {
+    this.structMap = {};
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '创建',
+      render: (item) => {
+        return <Link to='/ready/read/detail'><Button>{item.name}</Button></Link>;
+      },
+    }, {
+      key: 'struct',
+      name: '管理板块',
+    }];
+    this.columns = [{
+      title: '板块',
+      dataIndex: 'plate',
+      render: (text) => {
+        return this.structMap[text] || '';
+      },
+    }, {
+      title: '文章标题',
+      dataIndex: 'title',
+    }, {
+      title: '更新时间',
+      dataIndex: 'updateTime',
+      render: (text) => {
+        return formatDate(text);
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/ready/read/detail/${record.id}`}>编辑</Link>}
+          {<a onClick={() => {
+            this.deleteAction(record);
+          }}>删除</a>}
+        </div>;
+      },
+    }];
+
+    this.structColumns = [{
+      title: '板块名称',
+      dataIndex: 'plate',
+      render: (text, record, index) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeStruct(index, 'plate', v);
+        }} />;
+      },
+    }, {
+      title: '增加跳转',
+      dataIndex: 'jump',
+      render: (text, record, index) => {
+        return <Switch onChange={(value) => {
+          this.changeStruct(index, 'jump', value ? 1 : 0);
+        }} checked={!!text} />;
+      },
+    }, {
+      title: '跳转地址',
+      dataIndex: 'link',
+      render: (text, record, index) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeStruct(index, 'link', v);
+        }} />;
+      },
+    }, {
+      title: '按钮名称',
+      dataIndex: 'title',
+      render: (text, record, index) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeStruct(index, 'title', v);
+        }} />;
+      },
+    }];
+    Ready.getReadyRead().then(result => {
+      return this.refreshStruct(result);
+    }).then(() => {
+      this.initData();
+    });
+  }
+
+  initData() {
+    Ready.listRead(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  refreshStruct(result) {
+    result = result || {};
+    result.plates = (result.plates || []).map((row, index) => { row.value = index + 1; return row; });
+    this.structMap = getMap(result.plates, 'value', 'plate');
+    this.setState({ struct: result });
+  }
+
+  structAction() {
+    const { struct = {} } = this.state;
+    this.open(struct);
+  }
+
+  changeStruct(index, field, value, other) {
+    const { detail } = this.state;
+    if (other !== undefined) {
+      detail.plates.forEach((row) => {
+        row[field] = other;
+      });
+    }
+    detail.plates[index][field] = value;
+    this.setState({ detail });
+  }
+
+  submitStruct() {
+    const { detail } = this.state;
+    Ready.setReadyRead(detail).then(() => {
+      asyncSMessage('保存成功');
+      this.close(false, 'detail');
+      return this.refreshStruct(detail);
+    }).then(() => {
+      return this.initData();
+    });
+  }
+
+  deleteAction(row) {
+    asyncDelConfirm('删除确认', '是否删除选中?', () => {
+      const handler = Ready.delRead({ id: row.id });
+      return handler.then(() => {
+        asyncSMessage('删除成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  renderView() {
+    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
+        columns={this.tableSort(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 closable title='编辑章节' onCancel={() => {
+        this.close(false, 'detail');
+      }} onOk={() => {
+        this.submitStruct();
+      }}>
+        <TableLayout
+          rowKey={'plate'}
+          columns={this.structColumns}
+          list={this.state.detail.plates || []}
+          pagination={false}
+        />
+        <Button onClick={() => {
+          const { detail } = this.state;
+          detail.plates.push({});
+          this.setState({ detail });
+        }}>增加板块</Button></Modal>}
+    </Block>;
+  }
+}

+ 4 - 4
front/project/admin/routes/show/articleDetail/index.js

@@ -2,14 +2,14 @@ import module from '../../module';
 import group from '../group';
 
 export default {
-  path: '/show/article/detail',
-  matchPath: '/show/article/detail/:id?',
-  key: 'show-article-detail',
+  path: '/ready/read/detail',
+  matchPath: '/ready/read/detail/:id?',
+  key: 'ready-read-detail',
   title: '推荐阅读',
   needLogin: true,
   module,
   group,
-  showKey: 'show-article',
+  showKey: 'ready-read',
   component() {
     return import('./page');
   },

+ 3 - 0
front/project/admin/routes/ready/readDetail/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#ready-read-detail {}

+ 29 - 18
front/project/admin/routes/show/articleDetail/page.js

@@ -6,18 +6,23 @@ 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 } from '@src/services/Tools';
+import { formatFormError, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { ArticleChannel } from '../../../../Constant';
-import { System } from '../../../stores/system';
+import { Ready } from '../../../stores/ready';
 
 export default class extends Page {
+  init() {
+    Ready.getReadyRead().then(result => {
+      return this.refreshStruct(result);
+    });
+  }
+
   initData() {
     const { id } = this.params;
     const { form } = this.props;
     let handler;
     if (id) {
-      handler = System.getArticle({ id });
+      handler = Ready.getRead({ id });
     } else {
       handler = Promise.resolve({});
     }
@@ -28,6 +33,21 @@ export default class extends Page {
       });
   }
 
+  refreshStruct(result) {
+    result = result || {};
+    result.plates = (result.plates || []).map((row, index) => { row.value = index + 1; return row; });
+    this.structMap = getMap(result.plates, 'value', 'plate');
+    this.setState({
+      struct: result,
+      plates: result.plates.map((row) => {
+        row.value = `${row.value}`;
+        row.label = row.plate;
+        row.title = '';
+        return row;
+      }),
+    });
+  }
+
   submit() {
     const { form } = this.props;
     form.validateFields((err) => {
@@ -35,9 +55,9 @@ export default class extends Page {
         const data = form.getFieldsValue();
         let handler;
         if (data.id) {
-          handler = System.editArticle(data);
+          handler = Ready.editRead(data);
         } else {
-          handler = System.addArticle(data);
+          handler = Ready.addRead(data);
         }
         handler.then(() => {
           asyncSMessage('保存成功');
@@ -54,22 +74,13 @@ export default class extends Page {
     return <Block>
       <Form>
         {getFieldDecorator('id')(<input hidden />)}
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='频道'>
-          {getFieldDecorator('channel', {
-            rules: [
-              { required: true, message: '请选择' },
-            ],
-          })(
-            <Select select={ArticleChannel} placeholder='请选择' />,
-          )}
-        </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='位置'>
-          {getFieldDecorator('userId', {
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='板块'>
+          {getFieldDecorator('plate', {
             rules: [
               { required: true, message: '请选择' },
             ],
           })(
-            <Select {...this.state.userId} placeholder='请选择' />,
+            <Select select={this.state.plates} placeholder='请选择' />,
           )}
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='文章标题'>

+ 15 - 0
front/project/admin/routes/ready/room/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/ready/room',
+  key: 'ready-room',
+  title: '考试地址',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/ready/room/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#ready-room {}

+ 199 - 0
front/project/admin/routes/ready/room/page.js

@@ -0,0 +1,199 @@
+import React from 'react';
+// import { Link } from 'react-router-dom';
+// import { 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 { asyncSMessage, asyncDelConfirm, asyncForm } from '@src/services/AsyncTools';
+import { getMap } from '@src/services/Tools';
+import { Ready } from '../../../stores/ready';
+import { RoomPosition } from '../../../../Constant';
+
+const RoomPositionMap = getMap(RoomPosition, 'value', 'label');
+
+export default class extends Page {
+  init() {
+    this.filterForm = [{
+      key: 'position',
+      type: 'select',
+      allowClear: true,
+      name: '区域',
+      placeholder: '请选择',
+      select: RoomPosition,
+      onChange: (text) => {
+        this.onChangeSearch(this.filterForm, this, text);
+      },
+    }, {
+      key: 'areaId',
+      type: 'select',
+      allowClear: true,
+      name: '省份',
+      select: [],
+      number: true,
+      placeholder: '请选择',
+    }];
+    this.formF = null;
+    this.itemList = [{
+      key: 'id',
+      type: 'hidden',
+    }, {
+      key: 'position',
+      type: 'select',
+      name: '区域',
+      select: RoomPosition,
+      onChange: (text) => {
+        this.onChangeSearch(this.itemList, this.formF, text, 2);
+      },
+      required: true,
+    }, {
+      key: 'areaId',
+      type: 'select',
+      name: '省份',
+      select: [],
+      required: true,
+    }, {
+      key: 'title',
+      type: 'input',
+      name: '考场',
+      required: true,
+    }, {
+      key: 'address',
+      type: 'input',
+      name: '地址',
+      required: true,
+    }, {
+      key: 'description',
+      type: 'textarea',
+      name: '详细说明',
+    }];
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '创建',
+    }];
+    this.columns = [{
+      title: '区域',
+      dataIndex: 'position',
+      render: (text) => {
+        return RoomPositionMap[text] || '';
+      },
+    }, {
+      title: '省份',
+      dataIndex: 'areaId',
+      render: (text) => {
+        return this.areaMap[text] || '';
+      },
+    }, {
+      title: '考场',
+      dataIndex: 'title',
+    }, {
+      title: '地址',
+      dataIndex: 'address',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<a onClick={() => {
+            this.editAction(record);
+          }}>编辑</a>}
+          {<a onClick={() => {
+            this.deleteAction(record);
+          }}>删除</a>}
+        </div>;
+      },
+    }];
+    Ready.allArea().then(result => {
+      this.areaList = result.map(row => {
+        row.value = row.id;
+        return row;
+      });
+      this.areaMap = getMap(result, 'id', 'title');
+      this.onChangeSearch(this.filterForm, this, this.state.search.position);
+    });
+  }
+
+  onChangeSearch(list, component, value, index = 1) {
+    if (value) {
+      list[index].select = this.areaList.filter(row => row.position === value);
+      list[index].disabled = list[index].select.length === 0;
+      list[index].required = list[index].select.length > 0;
+    } else {
+      list[index].disabled = true;
+      list[index].required = false;
+      list[index].select = [];
+    }
+    component.setState({ load: false });
+  }
+
+  initData() {
+    Ready.listRoom(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  addAction() {
+    asyncForm('创建', this.itemList, {}, data => {
+      data.isOverseas = data.position === 'overseas' ? 1 : 0;
+      return Ready.addRoom(data).then(() => {
+        asyncSMessage('添加成功!');
+        this.refresh();
+      });
+    }).then(component => {
+      this.formF = component;
+      this.onChangeSearch(this.itemList, this.formF, null, 2);
+    });
+  }
+
+  editAction(row) {
+    asyncForm('编辑', this.itemList, row, data => {
+      data.isOverseas = data.position === 'overseas' ? 1 : 0;
+      return Ready.editRoom(data).then(() => {
+        asyncSMessage('编辑成功!');
+        this.refresh();
+      });
+    }).then(component => {
+      this.formF = component;
+      this.onChangeSearch(this.itemList, this.formF, row.position, 2);
+    });
+  }
+
+  deleteAction(row) {
+    asyncDelConfirm('删除确认', '是否删除选中?', () => {
+      const handler = Ready.delRoom({ id: row.id });
+      return handler.then(() => {
+        asyncSMessage('删除成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  renderView() {
+    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
+        columns={this.tableSort(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>;
+  }
+}

+ 15 - 0
front/project/admin/routes/setting/contract/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/setting/contract',
+  key: 'setting-contract',
+  title: '合同配置',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/setting/contract/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#setting-explain {}

+ 54 - 0
front/project/admin/routes/setting/contract/page.js

@@ -0,0 +1,54 @@
+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 ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap } from '@src/services/Tools';
+import { System } from '../../../stores/system';
+import { ContractKey } from '../../../../Constant';
+
+const ContractKeyMap = getMap(ContractKey, 'value', 'label');
+
+export default class extends Page {
+  constructor(props) {
+    super(props);
+
+    this.columns = [{
+      title: '协议名称',
+      dataIndex: 'title',
+    }, {
+      title: '应用场景',
+      dataIndex: 'key',
+      render: (text) => {
+        return ContractKeyMap[text] || '';
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/setting/contract/detail/${record.key}`}>修改</Link>}
+        </div>;
+      },
+    }];
+  }
+
+  initData() {
+    System.allContract().then(result => {
+      this.setState({ list: result });
+    });
+  }
+
+  renderView() {
+    return <Block flex>
+      <TableLayout
+        columns={this.tableSort(this.columns)}
+        list={this.state.list}
+        pagination={false}
+        loading={this.props.core.loading}
+      />
+    </Block>;
+  }
+}

+ 16 - 0
front/project/admin/routes/setting/contractDetail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/setting/contract/detail',
+  matchPath: '/setting/contract/detail/:key?',
+  key: 'setting-contract-detail',
+  title: '合同详情',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'setting-contract',
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/setting/contractDetail/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#setting-contract-detail {}

+ 100 - 0
front/project/admin/routes/setting/contractDetail/page.js

@@ -0,0 +1,100 @@
+import React from 'react';
+import { Form, Input, Button, Row, Col } from 'antd';
+import './index.less';
+import Editor from '@src/components/Editor';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+// import FileUpload from '@src/components/FileUpload';
+import { formatFormError, getMap } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+// import {  } from '../../../../Constant';
+// import { User } from '../../../stores/user';
+import { System } from '../../../stores/system';
+import { ContractKey } from '../../../../Constant';
+
+const ContractKeyMap = getMap(ContractKey, 'value', 'label');
+
+export default class extends Page {
+  initData() {
+    const { key } = this.params;
+    const { form } = this.props;
+    let handler;
+    if (key) {
+      handler = System.getContract({ key });
+    } else {
+      handler = Promise.resolve({});
+    }
+
+    handler
+      .then(result => {
+        form.setFieldsValue(result);
+        this.setState({ data: result });
+      });
+  }
+
+  submit() {
+    const { form } = this.props;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        System.setContract(data).then(() => {
+          asyncSMessage('保存成功');
+          goBack();
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderBase() {
+    const { getFieldDecorator } = this.props.form;
+    const { data } = this.state;
+    return <Block>
+      <h1>协议基本信息</h1>
+      <Form>
+        {getFieldDecorator('key')(<input hidden />)}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='应用场景'>
+          {ContractKeyMap[data.key] || ''}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='协议标题'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入名称' },
+            ],
+          })(
+            <Input placeholder='请输入名称' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderContent() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <Form>
+        <Form.Item label='正文'>
+          {getFieldDecorator('content', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderView() {
+    return <div flex>
+      {this.renderBase()}
+      {this.renderContent()}
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

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

@@ -6,5 +6,7 @@ import struct from './struct';
 import time from './time';
 import place from './place';
 import rank from './rank';
+import contract from './contract';
+import contractDetail from './contractDetail';
 
-export default [service, promote, index, struct, time, place, rank];
+export default [service, promote, index, struct, time, place, rank, contract, contractDetail];

+ 69 - 3
front/project/admin/routes/setting/promote/page.js

@@ -9,7 +9,7 @@ import { System } from '../../../stores/system';
 
 export default class extends Page {
   initData() {
-    System.getCoursePromote().then(result => {
+    System.getPromote().then(result => {
       const { form } = this.props;
       (result.video_list || []).forEach((row, index) => {
         form.getFieldDecorator(`video_list[${index}].number`);
@@ -23,6 +23,11 @@ export default class extends Page {
         form.getFieldDecorator(`ask_time[${index}].money`);
         form.getFieldDecorator(`ask_time[${index}].hour`);
       });
+      (result.vs_record || []).forEach((row, index) => {
+        form.getFieldDecorator(`vs_record[${index}].money`);
+        form.getFieldDecorator(`vs_record[${index}].number`);
+      });
+      form.getFieldDecorator('coach.number');
       form.setFieldsValue(flattenObject(result));
       this.setState({ load: true, data: result });
     });
@@ -73,7 +78,7 @@ export default class extends Page {
         data.ask_time = (data.ask_time || []).map(row => {
           return { money: Number(row.money), hour: Number(row.hour) };
         });
-        System.setCoursePromote(data)
+        System.setPromote(data)
           .then(() => {
             this.setState(data);
             asyncSMessage('保存成功');
@@ -154,7 +159,7 @@ export default class extends Page {
   renderVs() {
     const { getFieldDecorator } = this.props.form;
     const { data } = this.state;
-    const vss = data.vs || [];
+    const vss = data.vs_list || [];
     return <Block>
       <h1>1v1课折扣</h1>
       <Form>
@@ -222,6 +227,7 @@ export default class extends Page {
     const { getFieldDecorator } = this.props.form;
     const { data } = this.state;
     const ask_time = data.ask_time || [];
+    const vs_record = data.vs_record || [];
     return <Block>
       <h1>课程赠品</h1>
       <Form>
@@ -264,6 +270,66 @@ export default class extends Page {
         <Button onClick={() => {
           this.addLength('ask_time', { money: 0, hour: 0 });
         }}><Icon type={'plus'} /></Button>
+
+        <Form.Item label='满额送1v1辅导' />
+        {vs_record.map((row, index) => {
+          return <Row>
+            <Col span={6}>
+              <Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label='实付金额'>
+                {getFieldDecorator(`vs_record[${index}].money`, {
+                  rules: [
+                    { required: true, message: '输入金额' },
+                  ],
+                })(
+                  <Input placeholder={'输入金额'} onChange={(value) => {
+                    this.changeMapValue('vs_record', index, 'money', value);
+                  }} />,
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={6}>
+              <Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label='赠送'>
+                {getFieldDecorator(`vs_record[${index}].number`, {
+                  rules: [
+                    { required: true, message: '输入课时' },
+                  ],
+                })(
+                  <Input placeholder={'输入课时'} onChange={(value) => {
+                    this.changeMapValue('vs_record', index, 'number', value);
+                  }} />,
+                )}
+              </Form.Item>
+            </Col>
+            <Col span={1} onClick={() => {
+              this.deleteLength('vs_record', index, 1);
+            }}>
+              <Button><Icon type="minus" /></Button>
+            </Col>
+          </Row>;
+        })}
+        <Button onClick={() => {
+          this.addLength('vs_record', { money: 0, number: 0 });
+        }}><Icon type={'plus'} /></Button>
+
+        <Form.Item label='满课时送复习辅导规划' />
+        <Row>
+          <Col span={6}>
+            <Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label='购买课时'>
+              {getFieldDecorator('coach.number', {
+                rules: [
+                  { required: true, message: '输入课时' },
+                ],
+              })(
+                <Input placeholder={'输入课时'} onChange={(value) => {
+                  this.changeValue('coach', 'number', value);
+                }} />,
+              )}
+            </Form.Item>
+          </Col>
+          <Col span={6}>
+            <Form.Item labelCol={{ span: 1 }}>赠送</Form.Item>
+          </Col>
+        </Row>
       </Form>
     </Block>;
   }

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

@@ -1,11 +1,9 @@
 
 import tips from './tips';
 import faq from './faq';
-import article from './article';
-import articleDetail from './articleDetail';
 import comment from './comment';
 import ad from './ad';
 import message from './message';
 import deploy from './deploy';
 
-export default [tips, faq, article, articleDetail, comment, ad, message, deploy];
+export default [tips, faq, comment, ad, message, deploy];

+ 2 - 0
front/project/admin/routes/user/orderDetail/page.js

@@ -41,6 +41,8 @@ export default class extends Page {
       <h1>包含商品</h1>
       <Form>
         {(checkouts || []).map(row => {
+          // 赠送过滤
+          if (row.source.indexOf('gift') >= 0) return null;
           let title = '';
           switch (row.productType) {
             case 'course':

+ 2 - 1
front/project/admin/stores/index.js

@@ -7,6 +7,7 @@ import { User } from './user';
 import { Sentence } from './sentence';
 import { Question } from './question';
 import { Course } from './course';
+import { Ready } from './ready';
 import { Slient } from './slient';
 
-export default [System, Examination, Exercise, Preview, Textbook, User, Sentence, Question, Course, Slient];
+export default [System, Examination, Exercise, Preview, Textbook, User, Sentence, Question, Course, Ready, Slient];

+ 83 - 0
front/project/admin/stores/ready.js

@@ -0,0 +1,83 @@
+
+
+import BaseStore from '@src/stores/base';
+
+export default class ReadyStore extends BaseStore {
+  getReadyRead() {
+    return this.apiGet('/setting/ready_read');
+  }
+
+  setReadyRead(params) {
+    return this.apiPut('/setting/ready_read', params);
+  }
+
+  allCategory(params) {
+    return this.apiGet('/ready/category/all', params);
+  }
+
+  listArticle(params) {
+    return this.apiGet('/ready/article/list', params);
+  }
+
+  addArticle(params) {
+    return this.apiPost('/ready/article/add', params);
+  }
+
+  editArticle(params) {
+    return this.apiPut('/ready/article/edit', params);
+  }
+
+  delArticle(params) {
+    return this.apiDel('/ready/article/delete', params);
+  }
+
+  getArticle(params) {
+    return this.apiGet('/ready/article/detail', params);
+  }
+
+  allArea(params) {
+    return this.apiGet('/ready/area/all', params);
+  }
+
+  listRoom(params) {
+    return this.apiGet('/ready/room/list', params);
+  }
+
+  addRoom(params) {
+    return this.apiPost('/ready/room/add', params);
+  }
+
+  editRoom(params) {
+    return this.apiPut('/ready/room/edit', params);
+  }
+
+  delRoom(params) {
+    return this.apiDel('/ready/room/delete', params);
+  }
+
+  getRoom(params) {
+    return this.apiGet('/ready/room/detail', params);
+  }
+
+  listRead(params) {
+    return this.apiGet('/ready/read/list', params);
+  }
+
+  addRead(params) {
+    return this.apiPost('/ready/read/add', params);
+  }
+
+  editRead(params) {
+    return this.apiPut('/ready/read/edit', params);
+  }
+
+  delRead(params) {
+    return this.apiDel('/ready/read/delete', params);
+  }
+
+  getRead(params) {
+    return this.apiGet('/ready/read/detail', params);
+  }
+}
+
+export const Ready = new ReadyStore({ key: 'ready' });

+ 12 - 20
front/project/admin/stores/system.js

@@ -173,6 +173,18 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/sentence_info', params);
   }
 
+  allContract(params) {
+    return this.apiGet('/setting/contract/all', params);
+  }
+
+  getContract(params) {
+    return this.apiGet('/setting/contract/detail', params);
+  }
+
+  setContract(params) {
+    return this.apiPut('/setting/contract/edit', params);
+  }
+
   listRank(params) {
     return this.apiGet('/setting/rank/list', params);
   }
@@ -241,26 +253,6 @@ export default class SystemStore extends BaseStore {
     return this.apiDel('/setting/message/delete', params);
   }
 
-  listArticle(params) {
-    return this.apiGet('/setting/article/list', params);
-  }
-
-  addArticle(params) {
-    return this.apiPost('/setting/article/add', params);
-  }
-
-  editArticle(params) {
-    return this.apiPut('/setting/article/edit', params);
-  }
-
-  delArticle(params) {
-    return this.apiDel('/setting/article/delete', params);
-  }
-
-  getArticle(params) {
-    return this.apiGet('/setting/article/detail', params);
-  }
-
   listAd(params) {
     return this.apiGet('/setting/ad/list', params);
   }

+ 20 - 0
front/project/h5/stores/main.js

@@ -117,6 +117,26 @@ export default class MainStore extends BaseStore {
   getService(service) {
     return this.apiGet('/base/service', { service });
   }
+
+  getContract(key) {
+    return this.apiGet('/base/contract', { key });
+  }
+
+  listFaq(page, size, channel, position) {
+    return this.apiGet('/base/faq/list', { page, size, channel, position });
+  }
+
+  listComment(page, size, channel, position) {
+    return this.apiGet('/base/comment/list', { page, size, channel, position });
+  }
+
+  readyInfo() {
+    return this.apiGet('/base/ready_info');
+  }
+
+  listRead(page, size, plate) {
+    return this.apiGet('/base/read/list', { page, size, plate });
+  }
 }
 
 export const Main = new MainStore({ key: 'main' });

+ 10 - 1
front/project/www/routes/exercise/main/page.js

@@ -34,6 +34,7 @@ const PREVIEW_COURSE = 'PREVIEW_COURSE';
 const PREVIEW_LIST = 'PREVIEW_LIST';
 
 const CourseModuleMap = getMap(CourseModule, 'value', 'label');
+const CourseSorted = getMap([{ value: 'sc', sort: 1 }, { value: 'rc', sort: 2 }, { value: 'cr', sort: 3 }], 'value', 'sort');
 
 const exerciseColumns = [{
   title: '练习册',
@@ -433,10 +434,18 @@ export default class extends Page {
     const [courseStruct] = courseStructs.filter(row => row.key === struct);
     Course.progress(tab.value, courseStruct ? courseStruct.id : null).then(result => {
       const courseMap = {};
+      // 排序:sc,rc,cr
+      result = result.map(row => {
+        row.sort = CourseSorted[row.course.extend] || 10;
+        return row;
+      });
+      result.sort((a, b) => {
+        return a.sort < b.sort ? -1 : (a.sort > b.sort ? 1 : 0);
+      });
       const now = new Date().getTime();
       courseMap.open = result.filter(row => !row.isUsed);
       courseMap.end = result.filter(row => row.isUsed && (!row.isStop || (row.isStop && row.restoreTime)) && new Date(row.useEndTime).getTime() < now);
-      // todo 排序:sc,rc,cr
+
       courseMap.process = result.filter(row => row.isUsed && (row.isStop || row.restoreTime) && new Date(row.useEndTime).getTime() >= now);
       this.setState({ courseMap });
     });

+ 4 - 0
front/project/www/routes/paper/report/index.less

@@ -243,6 +243,10 @@
         background: #ECEDEE;
         height: 60px;
         border: 1px solid #fff;
+
+        &.point {
+          cursor: pointer;
+        }
       }
 
       td {

+ 157 - 60
front/project/www/routes/paper/report/page.js

@@ -1,11 +1,12 @@
 import React from 'react';
+import { Link } from 'react-router-dom';
 import './index.less';
 import LineChart from '@src/components/LineChart';
 import BarChart from '@src/components/BarChart';
 import PieChart from '@src/components/PieChart';
 import Assets from '@src/components/Assets';
 import Page from '@src/containers/Page';
-import { formatDate, formatPercent, formatSeconds, formatMinute, formatSecond, getMap } from '@src/services/Tools';
+import { formatDate, formatPercent, formatSeconds, formatMinute, formatSecond, formatMinuteSecond, getMap } from '@src/services/Tools';
 import { Icon, Tooltip } from 'antd';
 import { Question } from '../../../stores/question';
 import { Button } from '../../../components/Button';
@@ -18,6 +19,7 @@ import {
 } from '../../../../Constant';
 
 const QuestionDifficultMap = getMap(QuestionDifficult, 'value', 'label');
+const QuestionDifficultSort = getMap(QuestionDifficult, 'value', 'sort');
 
 function BarOption3(titles, source, data1, data2, color1, color2) {
   return {
@@ -502,7 +504,7 @@ function pieOption2(title, value1, value2, value3) {
 
 export default class extends Page {
   initState() {
-    return { tab: 'main', report: { paperModule: 'sentence' } };
+    return { tab: 'main', report: { paperModule: '' } };
   }
 
   initData() {
@@ -530,6 +532,31 @@ export default class extends Page {
       case 'question':
         // 题目回顾列表
         Question.questionReport(id).then(result => {
+          switch (result.paperModule) {
+            case 'sentence':
+              result = result.map((row) => {
+                row.struct = row.detail.subject && row.detail.predicate && row.detail.object ? 0 : 1;
+                row.logic = row.detail.options ? 0 : 1;
+
+                row.note = row.note ? 1 : 0;
+                row.collect = row.collect ? 1 : 0;
+                return row;
+              });
+              break;
+            case 'textbook':
+            case 'exercise':
+              result = result.map((row) => {
+                row.correct = row.isCorrect ? 0 : 1;
+                row.diff = QuestionDifficultSort[row.question.difficult];
+
+                row.note = row.note ? 1 : 0;
+                row.collect = row.collect ? 1 : 0;
+                return row;
+              });
+              this.refreshExercise(result);
+              break;
+            default:
+          }
           this.setState({ list: result });
         });
         break;
@@ -569,15 +596,48 @@ export default class extends Page {
     }
   }
 
+  questionSort(field) {
+    let { order } = this.state;
+    const { list = [] } = this.state;
+    if (order === field) {
+      order = 'no';
+      // direction = 'asc';
+    } else {
+      order = field;
+      // direction = 'desc';
+    }
+    list.sort((a, b) => {
+      const aValue = a[order];
+      const bValue = a[order];
+      if (aValue === bValue) {
+        return a.no < b.no ? -1 : a.no > b.no ? 1 : 0;
+      }
+      return aValue > bValue ? -1 : 1;
+    });
+    // if (direction === 'desc') {
+    //   list.reverse();
+    // }
+    this.setState({ order, list });
+  }
+
   renderView() {
-    const { report = {} } = this.state;
-    console.log(report);
+    const { report = {}, search = {} } = this.state;
+    const { info } = search;
     switch (report.paperModule) {
       case 'sentence':
+        if (info === 'question') {
+          return this.renderSentenceQuestion();
+        }
         return this.renderSentence();
       case 'textbook':
+        if (info === 'question') {
+          return this.renderExerciseQuestion();
+        }
         return this.renderTextbook();
       case 'exercise':
+        if (info === 'question') {
+          return this.renderExerciseQuestion();
+        }
         return this.renderExercise();
       case 'examination':
         return this.renderExamination();
@@ -690,11 +750,14 @@ export default class extends Page {
   }
 
   renderSentenceQuestion() {
+    const { report, list, order } = this.state;
     return <div className='sentence question'>
       <div className='header'>
         <div className='content'>
           <div className='title'>题目回顾</div>
-          <Button className='back' radius>返回长难句报告</Button>
+          <Button className='back' radius onClick={() => {
+            linkTo(`/paper/report/${report.id}`);
+          }}>返回长难句报告</Button>
         </div>
       </div>
       <div className='body'>
@@ -704,63 +767,39 @@ export default class extends Page {
             <thead>
               <tr>
                 <th>序号</th>
-                <th width='360'>题目</th>
-                <th>句子结构<GIcon name='arrow-up' /></th>
-                <th>逻辑关系<GIcon name='arrow-down' /></th>
-                <th>用时<GIcon name='arrow-up' /></th>
-                <th>收藏<GIcon name='arrow-up' /></th>
-                <th>笔记<GIcon name='arrow-up' /></th>
+                <th width='420'>题目</th>
+                <th className="point" onClick={() => {
+                  this.questionSort('struct');
+                }}>句子结构<GIcon name={order === 'struct' ? 'arrow-down' : 'arrow-up'} active={order === 'struct'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('logic');
+                }}>逻辑关系<GIcon name={order === 'logic' ? 'arrow-down' : 'arrow-up'} active={order === 'logic'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('userTime');
+                }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('collect');
+                }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('note');
+                }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th>
               </tr>
             </thead>
             <tbody>
-              <tr>
-                <td>1</td>
-                <td>
-                  <div className='n'> OG18 #678</div>
-                  <div className='desc'>「图形」None of the attempts to specify the causes of crime explains why most of the people exposed to</div>
-                </td>
-                <td><GIcon name='error' noHover /></td>
-                <td><GIcon name='right' noHover /></td>
-                <td>1.3</td>
-                <td><GIcon name='star' noHover /></td>
-                <td><GIcon name='note' noHover /></td>
-              </tr>
-              <tr>
-                <td>1</td>
-                <td>
-                  <div className='n'> OG18 #678</div>
-                  <div className='desc'>「图形」None of the attempts to specify the causes of crime explains why most of the people exposed to</div>
-                </td>
-                <td><GIcon name='error' noHover /></td>
-                <td><GIcon name='right' noHover /></td>
-                <td>1.3</td>
-                <td><GIcon name='star' active /></td>
-                <td><GIcon name='note' active /></td>
-              </tr>
-              <tr>
-                <td>1</td>
-                <td>
-                  <div className='n'> OG18 #678</div>
-                  <div className='desc'>「图形」None of the attempts to specify the causes of crime explains why most of the people exposed to</div>
-                </td>
-                <td><GIcon name='error' noHover /></td>
-                <td><GIcon name='right' noHover /></td>
-                <td>1.3</td>
-                <td><GIcon name='star' noHover /></td>
-                <td><GIcon name='note' noHover /></td>
-              </tr>
-              <tr>
-                <td>1</td>
-                <td>
-                  <div className='n'> OG18 #678</div>
-                  <div className='desc'>「图形」None of the attempts to specify the causes of crime explains why most of the people exposed to</div>
-                </td>
-                <td><GIcon name='error' noHover /></td>
-                <td><GIcon name='right' noHover /></td>
-                <td>1.3</td>
-                <td><GIcon name='star' active /></td>
-                <td><GIcon name='note' active /></td>
-              </tr>
+              {(list || []).map(row => {
+                return <tr>
+                  <td>{row.no}</td>
+                  <td>
+                    <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div>
+                    <div className='desc'>{row.question.description}</div>
+                  </td>
+                  <td><GIcon name={row.detail.subject && row.detail.predicate && row.detail.object ? 'right' : 'error'} noHover /></td>
+                  <td><GIcon name={row.detail.options ? 'right' : 'error'} noHover /></td>
+                  <td>{formatMinuteSecond(row.userTime)}</td>
+                  <td><GIcon name='star' active={row.collect} noHover /></td>
+                  <td><GIcon name='note' active={row.note} noHover /></td>
+                </tr>;
+              })}
             </tbody>
           </table>
         </div>
@@ -830,7 +869,65 @@ export default class extends Page {
   }
 
   renderExerciseQuestion() {
-    return <div />;
+    const { report, list, order } = this.state;
+    return <div className='sentence question'>
+      <div className='header'>
+        <div className='content'>
+          <div className='title'>题目回顾</div>
+          <Button className='back' radius onClick={() => {
+            linkTo(`/paper/report/${report.id}`);
+          }}>返回练习报告</Button>
+        </div>
+      </div>
+      <div className='body'>
+        <div className='content'>
+          <div className='tip'><Assets name='notice' />点击题目查看详情</div>
+          <table>
+            <thead>
+              <tr>
+                <th>序号</th>
+                <th width='340'>题目</th>
+                <th className="point" onClick={() => {
+                  this.questionSort('correct');
+                }}>正误<GIcon name={order === 'correct' ? 'arrow-down' : 'arrow-up'} active={order === 'correct'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('diff');
+                }}>难度<GIcon name={order === 'diff' ? 'arrow-down' : 'arrow-up'} active={order === 'diff'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('userTime');
+                }}>用时<GIcon name={order === 'userTime' ? 'arrow-down' : 'arrow-up'} active={order === 'userTime'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('place');
+                }}>主要考点<GIcon name={order === 'place' ? 'arrow-down' : 'arrow-up'} active={order === 'place'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('collect');
+                }}>收藏<GIcon name={order === 'collect' ? 'arrow-down' : 'arrow-up'} active={order === 'collect'} /></th>
+                <th className="point" onClick={() => {
+                  this.questionSort('note');
+                }}>笔记<GIcon name={order === 'note' ? 'arrow-down' : 'arrow-up'} active={order === 'note'} /></th>
+              </tr>
+            </thead>
+            <tbody>
+              {(list || []).map(row => {
+                return <tr>
+                  <td>{row.no}</td>
+                  <td>
+                    <div className='n'><Link to={`/paper/question/${row.id}`}>{row.questionNo.title}</Link></div>
+                    <div className='desc'>{row.question.description}</div>
+                  </td>
+                  <td><GIcon name={row.isCorrect ? 'right' : 'error'} noHover /></td>
+                  <td>{row.question.difficult}</td>
+                  <td>{formatMinuteSecond(row.userTime)}</td>
+                  <td>{row.question.place}</td>
+                  <td><GIcon name='star' active={row.collect} noHover /></td>
+                  <td><GIcon name='note' active={row.note} noHover /></td>
+                </tr>;
+              })}
+            </tbody>
+          </table>
+        </div>
+      </div>
+    </div>;
   }
 
   renderExerciseDetail() {

+ 18 - 2
front/project/www/stores/main.js

@@ -124,6 +124,18 @@ export default class MainStore extends BaseStore {
     }, 3600);
   }
 
+  /**
+   * 获取服务信息
+   * @param {*} service
+   */
+  getService(service) {
+    return this.apiGet('/base/service', { service });
+  }
+
+  getContract(key) {
+    return this.apiGet('/base/contract', { key });
+  }
+
   listFaq(page, size, channel, position) {
     return this.apiGet('/base/faq/list', { page, size, channel, position });
   }
@@ -132,8 +144,12 @@ export default class MainStore extends BaseStore {
     return this.apiGet('/base/comment/list', { page, size, channel, position });
   }
 
-  listArticle(page, size, channel, position) {
-    return this.apiGet('/base/article/list', { page, size, channel, position });
+  readyInfo() {
+    return this.apiGet('/base/ready_info');
+  }
+
+  listRead(page, size, plate) {
+    return this.apiGet('/base/read/list', { page, size, plate });
   }
 }
 

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

@@ -26,10 +26,11 @@ public enum SettingKey {
     SERVICE_TEXTBOOK("service_textbook"), // 数学机经服务信息
     SERVICE_VIP("service_vip"), // vip服务信息
     COURSE_INDEX("course_index"), // 课程首页设置
-    PROMOTE("course_promote"), // 促销
+    PROMOTE("promote"), // 促销
     EXPERIENCE_INFO("experience_info"), // 心经信息
     SENTENCE_INFO("sentence_info"), // 长难句信息
     WECHAT_INFO("wechat_info"), // 微信公众号信息
+    READY_READ("ready_read"), // 推荐阅读设置
 
     TIPS("tips"); // 页面提示信息
 

+ 1 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/trade/RecordSource.java

@@ -9,6 +9,7 @@ public enum RecordSource {
     INVITE("invite"),
     PREPARE("prepare"),
     BACKEND("backend"),
+    // 赠送用gift开头,方便过滤
     GIFT_COURSE("gift_course"),
     GIFT_ACTIVITY("gift_activity"),
 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

+ 212 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/Contract.java

@@ -0,0 +1,212 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "contract")
+public class Contract implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 合同场景
+     */
+    @Column(name = "`key`")
+    private String key;
+
+    /**
+     * 协议名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    @Column(name = "`content`")
+    private String content;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取合同场景
+     *
+     * @return key - 合同场景
+     */
+    public String getKey() {
+        return key;
+    }
+
+    /**
+     * 设置合同场景
+     *
+     * @param key 合同场景
+     */
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    /**
+     * 获取协议名称
+     *
+     * @return title - 协议名称
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置协议名称
+     *
+     * @param title 协议名称
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * @return content
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * @param content
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    @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(", key=").append(key);
+        sb.append(", title=").append(title);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", content=").append(content);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static Contract.Builder builder() {
+        return new Contract.Builder();
+    }
+
+    public static class Builder {
+        private Contract obj;
+
+        public Builder() {
+            this.obj = new Contract();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置合同场景
+         *
+         * @param key 合同场景
+         */
+        public Builder key(String key) {
+            obj.setKey(key);
+            return this;
+        }
+
+        /**
+         * 设置协议名称
+         *
+         * @param title 协议名称
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * @param content
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
+        public Contract build() {
+            return this.obj;
+        }
+    }
+}

+ 291 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyArticle.java

@@ -0,0 +1,291 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "ready_article")
+public class ReadyArticle implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 标题
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 二级标题
+     */
+    @Column(name = "`category_id`")
+    private Integer categoryId;
+
+    /**
+     * 一级标题
+     */
+    @Column(name = "`parent_category_id`")
+    private Integer parentCategoryId;
+
+    /**
+     * 访问量
+     */
+    @Column(name = "`view_number`")
+    private Integer viewNumber;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 内容
+     */
+    @Column(name = "`content`")
+    private String content;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取标题
+     *
+     * @return title - 标题
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置标题
+     *
+     * @param title 标题
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取二级标题
+     *
+     * @return category_id - 二级标题
+     */
+    public Integer getCategoryId() {
+        return categoryId;
+    }
+
+    /**
+     * 设置二级标题
+     *
+     * @param categoryId 二级标题
+     */
+    public void setCategoryId(Integer categoryId) {
+        this.categoryId = categoryId;
+    }
+
+    /**
+     * 获取一级标题
+     *
+     * @return parent_category_id - 一级标题
+     */
+    public Integer getParentCategoryId() {
+        return parentCategoryId;
+    }
+
+    /**
+     * 设置一级标题
+     *
+     * @param parentCategoryId 一级标题
+     */
+    public void setParentCategoryId(Integer parentCategoryId) {
+        this.parentCategoryId = parentCategoryId;
+    }
+
+    /**
+     * 获取访问量
+     *
+     * @return view_number - 访问量
+     */
+    public Integer getViewNumber() {
+        return viewNumber;
+    }
+
+    /**
+     * 设置访问量
+     *
+     * @param viewNumber 访问量
+     */
+    public void setViewNumber(Integer viewNumber) {
+        this.viewNumber = viewNumber;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取内容
+     *
+     * @return content - 内容
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * 设置内容
+     *
+     * @param content 内容
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    @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(", title=").append(title);
+        sb.append(", categoryId=").append(categoryId);
+        sb.append(", parentCategoryId=").append(parentCategoryId);
+        sb.append(", viewNumber=").append(viewNumber);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", content=").append(content);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ReadyArticle.Builder builder() {
+        return new ReadyArticle.Builder();
+    }
+
+    public static class Builder {
+        private ReadyArticle obj;
+
+        public Builder() {
+            this.obj = new ReadyArticle();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置标题
+         *
+         * @param title 标题
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置二级标题
+         *
+         * @param categoryId 二级标题
+         */
+        public Builder categoryId(Integer categoryId) {
+            obj.setCategoryId(categoryId);
+            return this;
+        }
+
+        /**
+         * 设置一级标题
+         *
+         * @param parentCategoryId 一级标题
+         */
+        public Builder parentCategoryId(Integer parentCategoryId) {
+            obj.setParentCategoryId(parentCategoryId);
+            return this;
+        }
+
+        /**
+         * 设置访问量
+         *
+         * @param viewNumber 访问量
+         */
+        public Builder viewNumber(Integer viewNumber) {
+            obj.setViewNumber(viewNumber);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置内容
+         *
+         * @param content 内容
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
+        public ReadyArticle build() {
+            return this.obj;
+        }
+    }
+}

+ 186 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyArticleCategory.java

@@ -0,0 +1,186 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "ready_article_category")
+public class ReadyArticleCategory implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 标题
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 父级id
+     */
+    @Column(name = "`parent_id`")
+    private Integer parentId;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取标题
+     *
+     * @return title - 标题
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置标题
+     *
+     * @param title 标题
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取父级id
+     *
+     * @return parent_id - 父级id
+     */
+    public Integer getParentId() {
+        return parentId;
+    }
+
+    /**
+     * 设置父级id
+     *
+     * @param parentId 父级id
+     */
+    public void setParentId(Integer parentId) {
+        this.parentId = parentId;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    @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(", title=").append(title);
+        sb.append(", parentId=").append(parentId);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ReadyArticleCategory.Builder builder() {
+        return new ReadyArticleCategory.Builder();
+    }
+
+    public static class Builder {
+        private ReadyArticleCategory obj;
+
+        public Builder() {
+            this.obj = new ReadyArticleCategory();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置标题
+         *
+         * @param title 标题
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置父级id
+         *
+         * @param parentId 父级id
+         */
+        public Builder parentId(Integer parentId) {
+            obj.setParentId(parentId);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        public ReadyArticleCategory build() {
+            return this.obj;
+        }
+    }
+}

+ 23 - 58
server/data/src/main/java/com/qxgmat/data/dao/entity/Article.java

@@ -4,24 +4,18 @@ import java.io.Serializable;
 import java.util.Date;
 import javax.persistence.*;
 
-@Table(name = "article")
-public class Article implements Serializable {
+@Table(name = "ready_read")
+public class ReadyRead implements Serializable {
     @Id
     @Column(name = "`id`")
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
     /**
-     * 频道
+     * 板块
      */
-    @Column(name = "`channle`")
-    private String channle;
-
-    /**
-     * 具体位置
-     */
-    @Column(name = "`position`")
-    private Integer position;
+    @Column(name = "`plate`")
+    private String plate;
 
     /**
      * 标题
@@ -58,39 +52,21 @@ public class Article implements Serializable {
     }
 
     /**
-     * 获取频道
-     *
-     * @return channle - 频道
-     */
-    public String getChannle() {
-        return channle;
-    }
-
-    /**
-     * 设置频道
+     * 获取板块
      *
-     * @param channle 频道
+     * @return plate - 板块
      */
-    public void setChannle(String channle) {
-        this.channle = channle;
+    public String getPlate() {
+        return plate;
     }
 
     /**
-     * 获取具体位置
+     * 设置板块
      *
-     * @return position - 具体位置
+     * @param plate 板块
      */
-    public Integer getPosition() {
-        return position;
-    }
-
-    /**
-     * 设置具体位置
-     *
-     * @param position 具体位置
-     */
-    public void setPosition(Integer position) {
-        this.position = position;
+    public void setPlate(String plate) {
+        this.plate = plate;
     }
 
     /**
@@ -164,8 +140,7 @@ public class Article implements Serializable {
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
-        sb.append(", channle=").append(channle);
-        sb.append(", position=").append(position);
+        sb.append(", plate=").append(plate);
         sb.append(", title=").append(title);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
@@ -174,15 +149,15 @@ public class Article implements Serializable {
         return sb.toString();
     }
 
-    public static Article.Builder builder() {
-        return new Article.Builder();
+    public static ReadyRead.Builder builder() {
+        return new ReadyRead.Builder();
     }
 
     public static class Builder {
-        private Article obj;
+        private ReadyRead obj;
 
         public Builder() {
-            this.obj = new Article();
+            this.obj = new ReadyRead();
         }
 
         /**
@@ -194,22 +169,12 @@ public class Article implements Serializable {
         }
 
         /**
-         * 设置频道
-         *
-         * @param channle 频道
-         */
-        public Builder channle(String channle) {
-            obj.setChannle(channle);
-            return this;
-        }
-
-        /**
-         * 设置具体位置
+         * 设置板块
          *
-         * @param position 具体位置
+         * @param plate 板块
          */
-        public Builder position(Integer position) {
-            obj.setPosition(position);
+        public Builder plate(String plate) {
+            obj.setPlate(plate);
             return this;
         }
 
@@ -249,7 +214,7 @@ public class Article implements Serializable {
             return this;
         }
 
-        public Article build() {
+        public ReadyRead build() {
             return this.obj;
         }
     }

+ 326 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyRoom.java

@@ -0,0 +1,326 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "ready_room")
+public class ReadyRoom implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 区域
+     */
+    @Column(name = "`position`")
+    private String position;
+
+    /**
+     * 省份id
+     */
+    @Column(name = "`area_id`")
+    private Integer areaId;
+
+    /**
+     * 是否海外
+     */
+    @Column(name = "`is_overseas`")
+    private Integer isOverseas;
+
+    /**
+     * 考场名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 考场地址
+     */
+    @Column(name = "`address`")
+    private String address;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 考场说明
+     */
+    @Column(name = "`description`")
+    private String description;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取区域
+     *
+     * @return position - 区域
+     */
+    public String getPosition() {
+        return position;
+    }
+
+    /**
+     * 设置区域
+     *
+     * @param position 区域
+     */
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    /**
+     * 获取省份id
+     *
+     * @return area_id - 省份id
+     */
+    public Integer getAreaId() {
+        return areaId;
+    }
+
+    /**
+     * 设置省份id
+     *
+     * @param areaId 省份id
+     */
+    public void setAreaId(Integer areaId) {
+        this.areaId = areaId;
+    }
+
+    /**
+     * 获取是否海外
+     *
+     * @return is_overseas - 是否海外
+     */
+    public Integer getIsOverseas() {
+        return isOverseas;
+    }
+
+    /**
+     * 设置是否海外
+     *
+     * @param isOverseas 是否海外
+     */
+    public void setIsOverseas(Integer isOverseas) {
+        this.isOverseas = isOverseas;
+    }
+
+    /**
+     * 获取考场名称
+     *
+     * @return title - 考场名称
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置考场名称
+     *
+     * @param title 考场名称
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取考场地址
+     *
+     * @return address - 考场地址
+     */
+    public String getAddress() {
+        return address;
+    }
+
+    /**
+     * 设置考场地址
+     *
+     * @param address 考场地址
+     */
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取考场说明
+     *
+     * @return description - 考场说明
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 设置考场说明
+     *
+     * @param description 考场说明
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    @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(", position=").append(position);
+        sb.append(", areaId=").append(areaId);
+        sb.append(", isOverseas=").append(isOverseas);
+        sb.append(", title=").append(title);
+        sb.append(", address=").append(address);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", description=").append(description);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ReadyRoom.Builder builder() {
+        return new ReadyRoom.Builder();
+    }
+
+    public static class Builder {
+        private ReadyRoom obj;
+
+        public Builder() {
+            this.obj = new ReadyRoom();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置区域
+         *
+         * @param position 区域
+         */
+        public Builder position(String position) {
+            obj.setPosition(position);
+            return this;
+        }
+
+        /**
+         * 设置省份id
+         *
+         * @param areaId 省份id
+         */
+        public Builder areaId(Integer areaId) {
+            obj.setAreaId(areaId);
+            return this;
+        }
+
+        /**
+         * 设置是否海外
+         *
+         * @param isOverseas 是否海外
+         */
+        public Builder isOverseas(Integer isOverseas) {
+            obj.setIsOverseas(isOverseas);
+            return this;
+        }
+
+        /**
+         * 设置考场名称
+         *
+         * @param title 考场名称
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置考场地址
+         *
+         * @param address 考场地址
+         */
+        public Builder address(String address) {
+            obj.setAddress(address);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置考场说明
+         *
+         * @param description 考场说明
+         */
+        public Builder description(String description) {
+            obj.setDescription(description);
+            return this;
+        }
+
+        public ReadyRoom build() {
+            return this.obj;
+        }
+    }
+}

+ 167 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/ReadyRoomArea.java

@@ -0,0 +1,167 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import javax.persistence.*;
+
+@Table(name = "ready_room_area")
+public class ReadyRoomArea implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    @Column(name = "`position_name`")
+    private String positionName;
+
+    @Column(name = "`position`")
+    private String position;
+
+    @Column(name = "`title`")
+    private String title;
+
+    @Column(name = "`pinyin`")
+    private String pinyin;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * @return position_name
+     */
+    public String getPositionName() {
+        return positionName;
+    }
+
+    /**
+     * @param positionName
+     */
+    public void setPositionName(String positionName) {
+        this.positionName = positionName;
+    }
+
+    /**
+     * @return position
+     */
+    public String getPosition() {
+        return position;
+    }
+
+    /**
+     * @param position
+     */
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    /**
+     * @return title
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * @param title
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * @return pinyin
+     */
+    public String getPinyin() {
+        return pinyin;
+    }
+
+    /**
+     * @param pinyin
+     */
+    public void setPinyin(String pinyin) {
+        this.pinyin = pinyin;
+    }
+
+    @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(", positionName=").append(positionName);
+        sb.append(", position=").append(position);
+        sb.append(", title=").append(title);
+        sb.append(", pinyin=").append(pinyin);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static ReadyRoomArea.Builder builder() {
+        return new ReadyRoomArea.Builder();
+    }
+
+    public static class Builder {
+        private ReadyRoomArea obj;
+
+        public Builder() {
+            this.obj = new ReadyRoomArea();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * @param position
+         */
+        public Builder position(String position) {
+            obj.setPosition(position);
+            return this;
+        }
+
+        /**
+         * @param positionName
+         */
+        public Builder positionName(String positionName) {
+            obj.setPositionName(positionName);
+            return this;
+        }
+
+        /**
+         * @param title
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * @param pinyin
+         */
+        public Builder pinyin(String pinyin) {
+            obj.setPinyin(pinyin);
+            return this;
+        }
+
+        public ReadyRoomArea build() {
+            return this.obj;
+        }
+    }
+}

+ 5 - 6
server/data/src/main/java/com/qxgmat/data/dao/mapping/ArticleMapper.xml

@@ -1,18 +1,17 @@
 <?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.ArticleMapper">
-  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.Article">
+<mapper namespace="com.qxgmat.data.dao.ContractMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.Contract">
     <!--
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
-    <result column="channle" jdbcType="VARCHAR" property="channle" />
-    <result column="position" jdbcType="INTEGER" property="position" />
+    <result column="key" jdbcType="VARCHAR" property="key" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
-  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.Article">
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.Contract">
     <!--
       WARNING - @mbg.generated
     -->
@@ -22,7 +21,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `channle`, `position`, `title`, `create_time`, `update_time`
+    `id`, `key`, `title`, `create_time`, `update_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

+ 20 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyArticleCategoryMapper.xml

@@ -0,0 +1,20 @@
+<?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.ReadyArticleCategoryMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ReadyArticleCategory">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="parent_id" jdbcType="INTEGER" property="parentId" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `title`, `parent_id`, `create_time`, `update_time`
+  </sql>
+</mapper>

+ 35 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyArticleMapper.xml

@@ -0,0 +1,35 @@
+<?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.ReadyArticleMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ReadyArticle">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="category_id" jdbcType="INTEGER" property="categoryId" />
+    <result column="parent_category_id" jdbcType="INTEGER" property="parentCategoryId" />
+    <result column="view_number" jdbcType="INTEGER" property="viewNumber" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.ReadyArticle">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `title`, `category_id`, `parent_category_id`, `view_number`, `create_time`, 
+    `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `content`
+  </sql>
+</mapper>

+ 32 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyReadMapper.xml

@@ -0,0 +1,32 @@
+<?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.ReadyReadMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ReadyRead">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="plate" jdbcType="VARCHAR" property="plate" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.ReadyRead">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `plate`, `title`, `create_time`, `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `content`
+  </sql>
+</mapper>

+ 20 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyRoomAreaMapper.xml

@@ -0,0 +1,20 @@
+<?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.ReadyRoomAreaMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ReadyRoomArea">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="position_name" jdbcType="VARCHAR" property="positionName" />
+    <result column="position" jdbcType="VARCHAR" property="position" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="pinyin" jdbcType="VARCHAR" property="pinyin" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `position_name`, `position`, `title`, `pinyin`
+  </sql>
+</mapper>

+ 35 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/ReadyRoomMapper.xml

@@ -0,0 +1,35 @@
+<?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.ReadyRoomMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.ReadyRoom">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="position" jdbcType="VARCHAR" property="position" />
+    <result column="area_id" jdbcType="INTEGER" property="areaId" />
+    <result column="is_overseas" jdbcType="INTEGER" property="isOverseas" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="address" jdbcType="VARCHAR" property="address" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.ReadyRoom">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="description" jdbcType="LONGVARCHAR" property="description" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `position`, `area_id`, `is_overseas`, `title`, `address`, `create_time`, `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `description`
+  </sql>
+</mapper>

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

@@ -11,16 +11,17 @@ import java.util.List;
 public interface UserAskQuestionRelationMapper {
     List<UserAskQuestion> listExercise(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("answerStatus") Integer answerStatus,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
     List<UserAskQuestion> listExamination(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("libraryId") Integer libraryId,
@@ -28,8 +29,7 @@ public interface UserAskQuestionRelationMapper {
             @Param("answerStatus") Integer answerStatus,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserAskQuestion> listWithUser(

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

@@ -13,23 +13,23 @@ public interface UserCollectQuestionRelationMapper {
 
     List<UserCollectQuestion> listExercise(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserCollectQuestion> listExamination(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("libraryId") Integer libraryId,
             @Param("year") String year,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 }

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

@@ -11,23 +11,23 @@ import java.util.List;
 public interface UserNoteQuestionRelationMapper {
     List<UserNoteQuestion> listExercise(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserNoteQuestion> listExamination(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("libraryId") Integer libraryId,
             @Param("year") String year,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 }

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

@@ -25,32 +25,32 @@ public interface UserPaperRelationMapper {
 
     List<UserPaper> list(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("paperOrigin") String paperOrigin,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserPaper> listExercise(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("courseModules") String[] courseModules,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserPaper> listExamination(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("structIds") Integer[] structIds,
             @Param("libraryId") Integer libraryId,
             @Param("year") String year,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 }

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

@@ -14,24 +14,24 @@ public interface UserQuestionRelationMapper {
 
     List<UserQuestion> listExerciseError(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserQuestion> listExaminationError(
             @Param("userId") Number userId,
+            @Param("keyword") String keyword,
             @Param("questionTypes") String[] questionTypes,
             @Param("structIds") Integer[] structIds,
             @Param("libraryId") Integer libraryId,
             @Param("year") String year,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime,
-            String order,
-            String direction
+            String order
     );
 
     List<UserQuestion> listLast(

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

@@ -24,6 +24,9 @@
   </update>
 
   <select id="listExercise" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user_ask_question` uaq
@@ -47,6 +50,11 @@
       and (q.`question_module` = 'sentence')
     where
     q.`id` > 0 and uaq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or sq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -62,10 +70,15 @@
     <if test="endTime != null">
       and uaq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExamination" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user_ask_question` uaq
@@ -95,6 +108,11 @@
     </if>
     where
     q.`id` > 0 and uaq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or tq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -116,7 +134,9 @@
     <if test="endTime != null">
       and uaq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <!--用户提问列表-->

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

@@ -15,12 +15,16 @@
   </sql>
 
   <select id="listExercise" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select max(ucq.`id`) as `id`,
     max(uq.`create_time`) as `latest_time`,
     sum(uq.`user_correct`) / sum(uq.`user_number`) as `correct`,
     sum(uq.`user_time`) / sum(uq.`user_number`) as `time`,
-    uq.`question_type` as `question_type`,
-    if (qn.`title` = null, sq.`title`, qn.`title`) as `title`,
+    if(uq.`question_type`='sc', 1, if(uq.`question_type`='rc', 2, if(uq.`question_type`='cr', 3,if(uq.`question_type`='ds', 4, if(uq.`question_type`='ps', 5,if(uq.`question_type`='ir', 6, 7)))))) as `question_type`,
+    uq.`no` as `no`,
+    uq.`origin_id` as `pid`
     from `user_collect_question` ucq
     left join `user_question` uq on uq.`question_id` = ucq.`question_id` and uq.`user_id`=#{userId,jdbcType=VARCHAR}
     left join `question` q on q.`id` = uq.`question_id`
@@ -42,7 +46,12 @@
     left join `sentence_question` sq on sq.`question_id` = q.`id`
       and (q.`question_module` = 'sentence')
     where
-    q.`id` > 0
+    q.`id` > 0 and uq.`id` > 0
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or sq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -56,16 +65,22 @@
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
     group by ucq.`question_module`, ucq.`question_no_id`
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExamination" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select max(ucq.`id`) as `id`,
     max(uq.`create_time`) as `latest_time`,
     sum(uq.`user_correct`) / sum(uq.`user_number`) as `correct`,
     sum(uq.`user_time`) / sum(uq.`user_number`) as `time`,
-    uq.`question_type` as `question_type`,
-    if (qn.`title` = null, tq.`title`, qn.`title`) as `title`,
+    if(uq.`question_type`='sc', 1, if(uq.`question_type`='rc', 2, if(uq.`question_type`='cr', 3,if(uq.`question_type`='ds', 4, if(uq.`question_type`='ps', 5,if(uq.`question_type`='ir', 6, 7)))))) as `question_type`,
+    uq.`no` as `no`,
+    uq.`origin_id` as `pid`
     from `user_collect_question` ucq
     left join `user_question` uq on uq.`question_id` = ucq.`question_id` and uq.`user_id`=#{userId,jdbcType=VARCHAR}
     left join `question` q on q.`id` = uq.`question_id`
@@ -93,7 +108,12 @@
         and tq.`year` = #{year,jdbcType=VARCHAR}
       </if>
     where
-    q.`id` > 0 and uq.`user_id` = #{userId,jdbcType=VARCHAR}
+    q.`id` > 0 and uq.`id` > 0
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or tq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -113,7 +133,9 @@
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
     group by ucq.`question_module`, ucq.`question_no_id`
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
 </mapper>

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

@@ -15,6 +15,9 @@
   </sql>
 
   <select id="listExercise" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user_note_question` unq
@@ -38,6 +41,11 @@
     and (q.`question_module` = 'sentence')
     where
     q.`id` > 0 and unq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or sq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -50,10 +58,15 @@
     <if test="endTime != null">
       and unq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExamination" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user_note_question` unq
@@ -83,6 +96,11 @@
     </if>
     where
     q.`id` > 0 and unq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or tq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -101,7 +119,9 @@
     <if test="endTime != null">
       and unq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
 </mapper>

+ 28 - 3
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml

@@ -29,6 +29,9 @@
   </update>
 
   <select id="list" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     up.`id`, ur.`user_correct` / up.`question_number` as `correct`, up.`user_time` / up.`question_number` as `time`
     from `user_paper` up
@@ -43,10 +46,15 @@
     <if test="endTime != null">
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExercise" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     up.`id`, ur.`user_correct` / up.`question_number` as `correct`, up.`user_time` / up.`question_number` as `time`
     from `user_paper` up
@@ -89,7 +97,13 @@
         pa.`question_type` = #{item}
       </foreach>
     </if>
+    left join `preview_paper` pp on pa.`paper_id` = pp.`id`
     where up.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (ep.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or pa.`title like #{keywordLike,jdbcType=VARCHAR}`
+      or pp.`title like #{keywordLike,jdbcType=VARCHAR}`)
+    </if>
     <if test="structIds != null">
       and ep.`id` > 0
     </if>
@@ -105,10 +119,15 @@
     <if test="endTime != null">
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExamination" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     up.`id`, ur.`user_correct` / up.`question_number` as `correct`, up.`user_time` / up.`question_number` as `time`
     from `user_paper` up
@@ -133,6 +152,10 @@
       and tp.`year` = #{year,jdbcType=VARCHAR}
     </if>
     where up.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (ep.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or tp.`title like #{keywordLike,jdbcType=VARCHAR}`)
+    </if>
     <if test="structIds != null">
       and ep.`id` > 0
     </if>
@@ -151,6 +174,8 @@
     <if test="endTime != null">
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 </mapper>

+ 28 - 6
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml

@@ -21,12 +21,16 @@
   </sql>
 
   <select id="listExerciseError" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select max(uq.`id`) as `id`,
     max(uq.`create_time`) as `latest_time`,
     sum(uq.`user_correct`) / sum(uq.`user_number`) as `correct`,
     sum(uq.`user_time`) / sum(uq.`user_number`) as `time`,
-    uq.`question_type` as `question_type`,
-    if (qn.`title` = null, sq.`title`, qn.`title`) as `title`,
+    if(uq.`question_type`='sc', 1, if(uq.`question_type`='rc', 2, if(uq.`question_type`='cr', 3,if(uq.`question_type`='ds', 4, if(uq.`question_type`='ps', 5,if(uq.`question_type`='ir', 6, 7)))))) as `question_type`,
+    uq.`no` as `no`,
+    uq.`origin_id` as `pid`
     from `user_question` uq
     left join `question` q on q.`id` = uq.`question_id`
       and (q.`question_module` = 'base' or q.`question_module` = 'sentence')
@@ -53,6 +57,11 @@
       and upq.`question_origin` = 'remove_error'
     where
     q.`id` > 0 and upq.`id` = null and uq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or sq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -66,16 +75,22 @@
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
     group by uq.`question_module`, uq.`question_no_id`
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <select id="listExaminationError" resultMap="IdMap">
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select max(uq.`id`) as `id`,
     max(uq.`create_time`) as `latest_time`,
     sum(uq.`user_correct`) / sum(uq.`user_number`) as `correct`,
     sum(uq.`user_time`) / sum(uq.`user_number`) as `time`,
-    uq.`question_type` as `question_type`,
-    if (qn.`title` = null, tq.`title`, qn.`title`) as `title`,
+    if(uq.`question_type`='sc', 1, if(uq.`question_type`='rc', 2, if(uq.`question_type`='cr', 3,if(uq.`question_type`='ds', 4, if(uq.`question_type`='ps', 5,if(uq.`question_type`='ir', 6, 7)))))) as `question_type`,
+    uq.`no` as `no`,
+    uq.`origin_id` as `pid`
     from `user_question` uq
     left join `question` q on q.`id` = uq.`question_id`
     and (q.`question_module` = 'base' or q.`question_module` = 'textbook')
@@ -108,6 +123,11 @@
       and upq.`question_origin` = 'remove_error'
     where
     q.`id` > 0 and upq.`id` = null and uq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="keyword != null">
+      and (q.`stem` like #{keywordLike,jdbcType=VARCHAR}
+      or qn.`title` like #{keywordLike,jdbcType=VARCHAR}
+      or tq.`title` like #{keywordLike,jdbcType=VARCHAR})
+    </if>
     <if test="structIds != null">
       and qn.`id` > 0
     </if>
@@ -127,7 +147,9 @@
       and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
     group by uq.`question_module`, uq.`question_no_id`
-    order by ${order} ${direction}
+    <if test="order != null">
+      order by ${order}
+    </if>
   </select>
 
   <!--

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

@@ -1,5 +1,6 @@
 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;
@@ -538,8 +539,8 @@ public class CourseController {
         entity.setEndTime(courseTime.getEndTime());
 
         // 默认回答时间
-        Integer ask = toolsService.getAskTime(BigDecimal.valueOf(0));
-        entity.setAskTime(ask);
+        JSONObject askInfo = toolsService.getAskTime(BigDecimal.valueOf(0));
+        if (askInfo != null )entity.setAskTime(askInfo.getIntValue("hour") * 3600);
 
         entity = userOrderRecordService.addStudent(entity);
         managerLogService.log(request);

+ 204 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/ReadyController.java

@@ -0,0 +1,204 @@
+package com.qxgmat.controller.admin;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.PageMessage;
+import com.nuliji.tools.Response;
+import com.nuliji.tools.ResponseHelp;
+import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.dto.admin.request.ReadyArticleDto;
+import com.qxgmat.dto.admin.request.ReadyReadDto;
+import com.qxgmat.dto.admin.request.ReadyRoomDto;
+import com.qxgmat.help.ShiroHelp;
+import com.qxgmat.service.inline.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpSession;
+import java.util.List;
+
+@RestController("AdminReadyController")
+@RequestMapping("/admin/ready")
+@Api(tags = "GetReady接口", description = "ready相关", produces = MediaType.APPLICATION_JSON_VALUE)
+public class ReadyController {
+    private static final Logger logger = LoggerFactory.getLogger(QuestionController.class);
+    @Autowired
+    private ShiroHelp shiroHelp;
+
+    @Autowired
+    private ReadyArticleService readyArticleService;
+
+    @Autowired
+    private ReadyArticleCategoryService readyArticleCategoryService;
+
+    @Autowired
+    private ReadyRoomService readyRoomService;
+
+    @Autowired
+    private ReadyRoomAreaService readyRoomAreaService;
+
+    @Autowired
+    private ReadyReadService readyReadService;
+
+    @RequestMapping(value = "/category/all", method = RequestMethod.GET)
+    @ApiOperation(value = "所有分类层级", httpMethod = "GET")
+    public Response<List<ReadyArticleCategory>> allCategory(HttpSession session) {
+        List<ReadyArticleCategory> p = readyArticleCategoryService.all();
+        return ResponseHelp.success(p);
+    }
+
+    @RequestMapping(value = "/article/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加文章", httpMethod = "POST")
+    private Response<Boolean> addArticle(@RequestBody @Validated ReadyArticleDto dto){
+        ReadyArticle entity = Transform.dtoToEntity(dto);
+        if(entity.getCategoryId() == null || entity.getCategoryId() == 0){
+            if (entity.getParentCategoryId() == null || entity.getParentCategoryId() == 0){
+                // 添加一级标题
+                ReadyArticleCategory category = readyArticleCategoryService.addCategory(dto.getParentCategory(), 0);
+                entity.setParentCategoryId(category.getId());
+            }
+            // 添加二级标题
+            ReadyArticleCategory category = readyArticleCategoryService.addCategory(dto.getCategory(), entity.getParentCategoryId());
+            entity.setCategoryId(category.getId());
+        }
+        readyArticleService.add(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/article/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改文章", httpMethod = "PUT")
+    private Response<Boolean> editArticle(@RequestBody @Validated ReadyArticleDto dto){
+        ReadyArticle entity = Transform.dtoToEntity(dto);
+        readyArticleService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/article/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "删除文章", httpMethod = "DELETE")
+    private Response<Boolean> deleteArticle(@RequestParam int id){
+        readyArticleService.delete(id);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/article/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "文章详情", httpMethod = "GET")
+    private Response<ReadyArticle> detailArticle(@RequestParam int id){
+        ReadyArticle article = readyArticleService.get(id);
+        return ResponseHelp.success(article);
+    }
+
+    @RequestMapping(value = "/article/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取文章列表", httpMethod = "GET")
+    private Response<PageMessage<ReadyArticle>> listArticle(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer parentCategoryId,
+            @RequestParam(required = false) Integer categoryId,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction
+    ){
+        Page<ReadyArticle> p = readyArticleService.list(page, size, parentCategoryId, categoryId, order, DirectionStatus.ValueOf(direction));
+        return ResponseHelp.success(p, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/area/all", method = RequestMethod.GET)
+    @ApiOperation(value = "所有区域层级", httpMethod = "GET")
+    public Response<List<ReadyRoomArea>> allArea(HttpSession session) {
+        List<ReadyRoomArea> p = readyRoomAreaService.all();
+        return ResponseHelp.success(p);
+    }
+
+    @RequestMapping(value = "/room/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加考场", httpMethod = "POST")
+    private Response<Boolean> addRoom(@RequestBody @Validated ReadyRoomDto dto){
+        ReadyRoom entity = Transform.dtoToEntity(dto);
+        readyRoomService.add(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/room/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改考场", httpMethod = "PUT")
+    private Response<Boolean> editRoom(@RequestBody @Validated ReadyRoomDto dto){
+        ReadyRoom entity = Transform.dtoToEntity(dto);
+        readyRoomService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/room/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "删除考场", httpMethod = "DELETE")
+    private Response<Boolean> deleteRoom(@RequestParam int id){
+        readyRoomService.delete(id);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/room/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "考场详情", httpMethod = "GET")
+    private Response<ReadyRoom> detailRoom(@RequestParam int id){
+        ReadyRoom article = readyRoomService.get(id);
+        return ResponseHelp.success(article);
+    }
+
+    @RequestMapping(value = "/room/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取考场列表", httpMethod = "GET")
+    private Response<PageMessage<ReadyRoom>> listRoom(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String position,
+            @RequestParam(required = false) Integer areaId,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction
+    ){
+        Page<ReadyRoom> p = readyRoomService.list(page, size, position, areaId, order, DirectionStatus.ValueOf(direction));
+        return ResponseHelp.success(p, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/read/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加文章", httpMethod = "POST")
+    private Response<Boolean> addRead(@RequestBody @Validated ReadyReadDto dto){
+        ReadyRead entity = Transform.dtoToEntity(dto);
+        readyReadService.add(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/read/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改文章", httpMethod = "PUT")
+    private Response<Boolean> editRead(@RequestBody @Validated ReadyReadDto dto){
+        ReadyRead entity = Transform.dtoToEntity(dto);
+        readyReadService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/read/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "删除文章", httpMethod = "DELETE")
+    private Response<Boolean> deleteRead(@RequestParam int id){
+        readyReadService.delete(id);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/read/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "文章详情", httpMethod = "GET")
+    private Response<ReadyRead> detailRead(@RequestParam int id){
+        ReadyRead article = readyReadService.get(id);
+        return ResponseHelp.success(article);
+    }
+
+    @RequestMapping(value = "/read/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取文章列表", httpMethod = "GET")
+    private Response<PageMessage<ReadyRead>> listRead(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String plate,
+            @RequestParam(required = false, defaultValue = "id") String order,
+            @RequestParam(required = false, defaultValue = "desc") String direction
+    ){
+        Page<ReadyRead> p = readyReadService.list(page, size, plate, order, DirectionStatus.ValueOf(direction));
+        return ResponseHelp.success(p, page, size, p.getTotal());
+    }
+}

+ 42 - 47
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java

@@ -65,6 +65,9 @@ public class SettingController {
     private RankService rankService;
 
     @Autowired
+    private ContractService contractService;
+
+    @Autowired
     private CommentService commentService;
 
     @Autowired
@@ -74,9 +77,6 @@ public class SettingController {
     private MessageService messageService;
 
     @Autowired
-    private ArticleService articleService;
-
-    @Autowired
     private UsersService usersService;
 
     @Autowired
@@ -408,6 +408,23 @@ public class SettingController {
         return ResponseHelp.success(entity.getValue());
     }
 
+    @RequestMapping(value = "/ready_read", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改推荐阅读设置", httpMethod = "PUT")
+    private Response<Boolean> editReadyRead(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.READY_READ);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/ready_read", method = RequestMethod.GET)
+    @ApiOperation(value = "获取推荐阅读配置", httpMethod = "GET")
+    private Response<JSONObject> getReadyRead(){
+        Setting entity = settingService.getByKey(SettingKey.READY_READ);
+
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/comment/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加评价", httpMethod = "POST")
     private Response<Boolean> addComment(@RequestBody @Validated CommentDto dto){
@@ -593,50 +610,6 @@ public class SettingController {
         return ResponseHelp.success(p, page, size, p.getTotal());
     }
 
-    @RequestMapping(value = "/article/add", method = RequestMethod.POST)
-    @ApiOperation(value = "添加文章", httpMethod = "POST")
-    private Response<Boolean> addArticle(@RequestBody @Validated ArticleDto dto){
-        Article entity = Transform.dtoToEntity(dto);
-        articleService.add(entity);
-        return ResponseHelp.success(true);
-    }
-
-    @RequestMapping(value = "/article/edit", method = RequestMethod.PUT)
-    @ApiOperation(value = "修改文章", httpMethod = "PUT")
-    private Response<Boolean> editArticle(@RequestBody @Validated Article dto){
-        Article entity = Transform.dtoToEntity(dto);
-        articleService.edit(entity);
-        return ResponseHelp.success(true);
-    }
-
-    @RequestMapping(value = "/article/delete", method = RequestMethod.DELETE)
-    @ApiOperation(value = "删除文章", httpMethod = "DELETE")
-    private Response<Boolean> deleteArticle(@RequestParam int id){
-        articleService.delete(id);
-        return ResponseHelp.success(true);
-    }
-
-    @RequestMapping(value = "/article/detail", method = RequestMethod.GET)
-    @ApiOperation(value = "文章详情", httpMethod = "GET")
-    private Response<Article> detailArticle(@RequestParam int id){
-        Article article = articleService.get(id);
-        return ResponseHelp.success(article);
-    }
-
-    @RequestMapping(value = "/article/list", method = RequestMethod.GET)
-    @ApiOperation(value = "获取文章列表", httpMethod = "GET")
-    private Response<PageMessage<Article>> listArticle(
-            @RequestParam(required = false, defaultValue = "1") int page,
-            @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = false) String channel,
-            @RequestParam(required = false) String position,
-            @RequestParam(required = false, defaultValue = "id") String order,
-            @RequestParam(required = false, defaultValue = "desc") String direction
-    ){
-        Page<Article> p = articleService.list(page, size, channel, position, order, DirectionStatus.ValueOf(direction));
-        return ResponseHelp.success(p, page, size, p.getTotal());
-    }
-
     @RequestMapping(value = "/ad/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加广告", httpMethod = "POST")
     public Response<Ad> add(@RequestBody @Validated AdDto dto, HttpServletRequest request) {
@@ -684,6 +657,28 @@ public class SettingController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/contract/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改合同", httpMethod = "PUT")
+    private Response<Boolean> editContract(@RequestBody @Validated ContractDto dto){
+        Contract entity = Transform.dtoToEntity(dto);
+        contractService.editContract(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/contract/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "修改排行", httpMethod = "GET")
+    private Response<Contract> getContract(String key){
+        Contract in = contractService.getContract(key);
+        return ResponseHelp.success(in);
+    }
+
+    @RequestMapping(value = "/contract/all", method = RequestMethod.GET)
+    @ApiOperation(value = "获取排行设置", httpMethod = "GET")
+    private Response<List<Contract>> allContract(){
+        List<Contract> contractList = contractService.all();
+        return ResponseHelp.success(contractList);
+    }
+
     @RequestMapping(value = "/rank/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加排行", httpMethod = "POST")
     private Response<Boolean> addRank(@RequestBody @Validated RankDto dto){

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

@@ -1,5 +1,6 @@
 package com.qxgmat.controller.api;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.PageMessage;
@@ -9,7 +10,6 @@ import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.SettingKey;
-import com.qxgmat.data.constants.enums.module.ChannelModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.dto.extend.UserExtendDto;
@@ -47,6 +47,9 @@ public class BaseController {
     private RankService rankService;
 
     @Autowired
+    private ContractService contractService;
+
+    @Autowired
     private ExerciseStructService exerciseStructService;
 
     @Autowired
@@ -59,7 +62,7 @@ public class BaseController {
     private CommentService commentService;
 
     @Autowired
-    private ArticleService articleService;
+    private ReadyReadService readyReadService;
 
     @Autowired
     private UsersService usersService;
@@ -213,6 +216,13 @@ public class BaseController {
         return ResponseHelp.success(setting.getValue());
     }
 
+    @RequestMapping(value = "/contract", method = RequestMethod.GET)
+    @ApiOperation(value = "获取合同信息", notes = "获取合同信息", httpMethod = "GET")
+    public Response<Contract> contract(@RequestParam(required = true) String key)  {
+        Contract contract = contractService.getContract(key);
+        return ResponseHelp.success(contract);
+    }
+
     @RequestMapping(value = "/faq/list", method = RequestMethod.GET)
     @ApiOperation(value = "faq列表", httpMethod = "GET")
     public Response<PageMessage<FaqDto>> listFaq(
@@ -253,17 +263,30 @@ public class BaseController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
-    @RequestMapping(value = "/article/list", method = RequestMethod.GET)
+    @RequestMapping(value = "/ready_info", method = RequestMethod.GET)
+    @ApiOperation(value = "获取GetReady信息", notes = "获取GetReady信息", httpMethod = "GET")
+    public Response<JSONObject> readyRead()  {
+        Setting entity = settingService.getByKey(SettingKey.READY_READ);
+        JSONObject info = entity.getValue();
+
+        // todo
+        JSONObject dto = new JSONObject();
+        dto.put("read", info);
+        dto.put("category", new JSONArray());
+        dto.put("area", new JSONArray());
+        return ResponseHelp.success(dto);
+    }
+
+    @RequestMapping(value = "/read/list", method = RequestMethod.GET)
     @ApiOperation(value = "推荐阅读", httpMethod = "GET")
-    public Response<PageMessage<Article>> listArticle(
+    public Response<PageMessage<ReadyRead>> listRead(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = true) String channel,
-            @RequestParam(required = true) String position,
+            @RequestParam(required = true) String plate,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<Article> p = articleService.list(page, size, channel, position, order, DirectionStatus.ValueOf(direction));
+        Page<ReadyRead> p = readyReadService.list(page, size, plate, order, DirectionStatus.ValueOf(direction));
         return ResponseHelp.success(p, page, size, p.getTotal());
     }
 }

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

@@ -744,7 +744,7 @@ public class MyController {
     }
 
     @RequestMapping(value = "/collect/experience/list", method = RequestMethod.GET)
-    @ApiOperation(value = "获取收藏题目列表", notes = "获取收藏题目列表", httpMethod = "GET")
+    @ApiOperation(value = "获取收藏心经列表", notes = "获取收藏心经列表", httpMethod = "GET")
     public Response<PageMessage<CourseExperience>> listExperienceCollect(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
@@ -820,6 +820,7 @@ public class MyController {
     public Response<PageMessage<UserCollectQuestionInfoDto>> listQuestionCollect(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String module,
             @RequestParam(required = false) String[] questionTypes,
             @RequestParam(required = false) Integer[] structIds,
@@ -827,14 +828,13 @@ public class MyController {
             @RequestParam(required = false) String endTime,
             @RequestParam(required = false) Boolean latest,
             @RequestParam(required = false) String year,
-            @RequestParam(required = false, defaultValue = "id") String order, // title, time, correct, question_type, latest_time
-            @RequestParam(required = false, defaultValue = "desc") String direction,
+            @RequestParam(required = false) String order, // (pid asc, no asc), time, correct, question_type, latest_time
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
         QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
         Page<UserCollectQuestion> p = null;
         if(questionNoModule == QuestionNoModule.EXERCISE){
-            p = userCollectQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userCollectQuestionService.listExercise(page, size, user.getId(), keyword, questionTypes, structIds, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if (questionNoModule == QuestionNoModule.EXAMINATION){
             Integer libraryId = null;
             if (latest != null){
@@ -844,7 +844,7 @@ public class MyController {
                     year = null;
                 }
             }
-            p = userCollectQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+            p = userCollectQuestionService.listExamination(page, size, user.getId(), keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else{
             throw new ParameterException("参数逻辑错误");
         }
@@ -888,6 +888,7 @@ public class MyController {
     public Response<PageMessage<UserQuestionErrorInfoDto>> listError(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String module,
             @RequestParam(required = false) String[] questionTypes,
             @RequestParam(required = false) Integer[] structIds,
@@ -895,14 +896,13 @@ public class MyController {
             @RequestParam(required = false) String endTime,
             @RequestParam(required = false) Boolean latest,
             @RequestParam(required = false) String year,
-            @RequestParam(required = false, defaultValue = "id") String order, // title, time, correct, question_type, latest_time
-            @RequestParam(required = false, defaultValue = "desc") String direction
+            @RequestParam(required = false) String order // (pid asc, no asc), time, correct, question_type, latest_time
     )  {
         User user = (User) shiroHelp.getLoginUser();
         QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
         Page<UserQuestion> p = null;
         if(questionNoModule == QuestionNoModule.EXERCISE){
-            p = userQuestionService.listExerciseError(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userQuestionService.listExerciseError(page, size, user.getId(), keyword, questionTypes, structIds, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if (questionNoModule == QuestionNoModule.EXAMINATION){
             Integer libraryId = null;
             if (latest != null){
@@ -912,7 +912,7 @@ public class MyController {
                     year = null;
                 }
             }
-            p = userQuestionService.listExaminationError(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+            p = userQuestionService.listExaminationError(page, size, user.getId(), keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else{
             throw new ParameterException("参数逻辑错误");
         }
@@ -1030,6 +1030,7 @@ public class MyController {
     public Response<PageMessage<UserNoteQuestionInfoDto>> listNoteQuestion(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String module,
             @RequestParam(required = false) String[] questionTypes,
             @RequestParam(required = false) Integer[] structIds,
@@ -1037,14 +1038,13 @@ public class MyController {
             @RequestParam(required = false) String endTime,
             @RequestParam(required = false) Boolean latest,
             @RequestParam(required = false) String year,
-            @RequestParam(required = false, defaultValue = "id") String order, // update_time
-            @RequestParam(required = false, defaultValue = "desc") String direction,
+            @RequestParam(required = false) String order, // update_time
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
         QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
         Page<UserNoteQuestion> p = null;
         if(questionNoModule == QuestionNoModule.EXERCISE){
-            p = userNoteQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userNoteQuestionService.listExercise(page, size, user.getId(), keyword, questionTypes, structIds, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if (questionNoModule == QuestionNoModule.EXAMINATION){
             Integer libraryId = null;
             if (latest != null){
@@ -1054,7 +1054,7 @@ public class MyController {
                     year = null;
                 }
             }
-            p = userNoteQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+            p = userNoteQuestionService.listExamination(page, size, user.getId(), keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else{
             throw new ParameterException("参数逻辑错误");
         }
@@ -1099,6 +1099,7 @@ public class MyController {
     public Response<PageMessage<UserPaperDto>> listReport(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String module,
             @RequestParam(required = false) String origin,
             @RequestParam(required = false) String[] questionTypes,
@@ -1108,17 +1109,16 @@ public class MyController {
             @RequestParam(required = false) Boolean latest,
             @RequestParam(required = false) String year,
             @RequestParam(required = false) String[] courseModules,
-            @RequestParam(required = false, defaultValue = "id") String order, // title, latest_time,correct,time
-            @RequestParam(required = false, defaultValue = "desc") String direction,
+            @RequestParam(required = false) String order, // title, latest_time,correct,time
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
         PaperOrigin paperOrigin = PaperOrigin.ValueOf(origin);
         QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
         Page<UserPaper> p = null;
         if (questionNoModule != null && (paperOrigin == PaperOrigin.COLLECT || paperOrigin == PaperOrigin.ERROR)){
-            p = userPaperService.list(page, size, user.getId(), paperOrigin, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userPaperService.list(page, size, user.getId(), keyword, paperOrigin, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if(questionNoModule == QuestionNoModule.EXERCISE){
-            p = userPaperService.listExercise(page, size, user.getId(), questionTypes, structIds, courseModules, startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userPaperService.listExercise(page, size, user.getId(), keyword, questionTypes, structIds, courseModules, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if (questionNoModule == QuestionNoModule.EXAMINATION){
             Integer libraryId = null;
             if (latest != null){
@@ -1129,7 +1129,7 @@ public class MyController {
                     year = null;
                 }
             }
-            p = userPaperService.listExamination(page, size, user.getId(), structIds, libraryId, year, order, startTime, endTime, DirectionStatus.ValueOf(direction));
+            p = userPaperService.listExamination(page, size, user.getId(), keyword, structIds, libraryId, year, startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else{
             throw new ParameterException("参数逻辑错误");
         }
@@ -1253,6 +1253,7 @@ public class MyController {
     public Response<PageMessage<UserAskQuestionInfoDto>> listAskQuestion(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String module,
             @RequestParam(required = false) String[] questionTypes,
             @RequestParam(required = false) Integer[] structIds,
@@ -1261,14 +1262,13 @@ public class MyController {
             @RequestParam(required = false) Integer askStatus,
             @RequestParam(required = false) Boolean latest,
             @RequestParam(required = false) String year,
-            @RequestParam(required = false, defaultValue = "id") String order, // create_time, answer_time
-            @RequestParam(required = false, defaultValue = "desc") String direction,
+            @RequestParam(required = false) String order, // create_time, answer_time
             HttpSession session)  {
         User user = (User) shiroHelp.getLoginUser();
         QuestionNoModule questionNoModule = QuestionNoModule.ValueOf(module);
         Page<UserAskQuestion> p = null;
         if(questionNoModule == QuestionNoModule.EXERCISE){
-            p = userAskQuestionService.listExercise(page, size, user.getId(), questionTypes, structIds, AskStatus.ValueOf(askStatus),startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userAskQuestionService.listExercise(page, size, user.getId(), keyword, questionTypes, structIds, AskStatus.ValueOf(askStatus),startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else if (questionNoModule == QuestionNoModule.EXAMINATION){
             Integer libraryId = null;
             if (latest != null){
@@ -1278,7 +1278,7 @@ public class MyController {
                     year = null;
                 }
             }
-            p = userAskQuestionService.listExamination(page, size, user.getId(), questionTypes, structIds, libraryId, year, AskStatus.ValueOf(askStatus), startTime, endTime, order, DirectionStatus.ValueOf(direction));
+            p = userAskQuestionService.listExamination(page, size, user.getId(), keyword, questionTypes, structIds, libraryId, year, AskStatus.ValueOf(askStatus), startTime, endTime, order != null ? order.replace("|", " ") : null);
         }else{
             throw new ParameterException("参数逻辑错误");
         }

+ 3 - 2
server/gateway-api/src/main/java/com/qxgmat/controller/api/OrderController.java

@@ -15,6 +15,7 @@ import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.dto.extend.CourseDataExtendDto;
 import com.qxgmat.dto.extend.CourseExtendDto;
 import com.qxgmat.dto.extend.CoursePackageExtendDto;
+import com.qxgmat.dto.request.OrderConfirmDto;
 import com.qxgmat.dto.request.PayOrderDto;
 import com.qxgmat.dto.request.RecordAddDto;
 import com.qxgmat.dto.request.RecordUseDto;
@@ -105,9 +106,9 @@ public class OrderController {
 
     @RequestMapping(value = "/pay/confirm", method = RequestMethod.POST)
     @ApiOperation(value = "确认支付:创建订单", notes = "创建订单", httpMethod = "POST")
-    public Response<UserOrderPreDto> confirmPay(HttpServletRequest request) throws Exception {
+    public Response<UserOrderPreDto> confirmPay(@RequestBody @Validated OrderConfirmDto dto, HttpServletRequest request) throws Exception {
         User user = (User) shiroHelp.getLoginUser();
-        UserOrder order = orderFlowService.makeOrder(user.getId());
+        UserOrder order = orderFlowService.makeOrder(user.getId(), dto.getCourseId());
 
         return ResponseHelp.success(detail(user.getId(), order, null));
     }

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

@@ -13,6 +13,7 @@ import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.entity.QuestionNoRelation;
 import com.qxgmat.data.relation.entity.UserReportRelation;
+import com.qxgmat.dto.admin.request.QuestionNoDto;
 import com.qxgmat.dto.extend.*;
 import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.*;
@@ -116,6 +117,33 @@ public class QuestionController {
     @Autowired
     private CourseExtendService courseExtendService;
 
+
+    @RequestMapping(value = "/search/stem", method = RequestMethod.GET)
+    @ApiOperation(value = "搜索题目编号列表:题干搜索", httpMethod = "GET")
+    public Response<PageMessage<QuestionBaseExtendDto>> searchStem(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = true) String keyword,
+            HttpSession session) {
+        PageResult<QuestionNoRelation> p = questionNoService.searchStem(page, size, keyword);
+        List<QuestionBaseExtendDto> pr = Transform.convert(p, QuestionBaseExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/search/no", method = RequestMethod.GET)
+    @ApiOperation(value = "搜索题目编号列表:题目编号搜索", httpMethod = "GET")
+    public Response<PageMessage<QuestionNoDto>> searchNo(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = true) String keyword,
+            HttpSession session) {
+        PageResult<QuestionNoRelation> p = questionNoService.searchNo(page, size, keyword, null);
+        List<QuestionNoDto> pr = Transform.convert(p, QuestionNoDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/info", method = RequestMethod.GET)
     @ApiOperation(value = "获取题目信息", notes = "获取题目信息", httpMethod = "GET")
     public Response<UserQuestionDetailDto> info(
@@ -672,29 +700,48 @@ public class QuestionController {
 
     @RequestMapping(value = "/report/question", method = RequestMethod.GET)
     @ApiOperation(value = "获取做题记录", notes = "获取做题记录", httpMethod = "GET")
-    public Response<List<UserQuestionExtendDto>> detailReportQuestion(
+    public Response<List<UserQuestionBaseDto>> detailReportQuestion(
             @RequestParam(required = true) Integer userReportId
     )  {
         User user = (User) shiroHelp.getLoginUser();
         if (user == null) {
             throw new AuthException("请先登录");
         }
-        List<UserQuestion> userQuestionList = questionFlowService.listByReport(user.getId(), userReportId);
-        List<UserQuestionExtendDto> userQuestionDtos = Transform.convert(userQuestionList, UserQuestionExtendDto.class);
+        List<UserQuestion> p = questionFlowService.listByReport(user.getId(), userReportId);
+        List<UserQuestionBaseDto> pr = Transform.convert(p, UserQuestionBaseDto.class);
 
-        Collection ids = Transform.getIds(userQuestionList, UserQuestion.class, "questionId");
-        List<UserCollectQuestion> userCollectQuestionList = userCollectQuestionService.listByUserAndQuestions(user.getId(), ids);
+        Collection questionIds = Transform.getIds(p, UserQuestion.class, "questionId");
+        List<UserCollectQuestion> userCollectQuestionList = userCollectQuestionService.listByUserAndQuestions(user.getId(), questionIds);
         Map collectMap = Transform.getMap(userCollectQuestionList, UserCollectQuestion.class, "questionId", "id");
 
-        List<UserNoteQuestion> userNoteQuestionList = userNoteQuestionService.listByUserAndQuestions(user.getId(), ids);
+        List<UserNoteQuestion> userNoteQuestionList = userNoteQuestionService.listByUserAndQuestions(user.getId(), questionIds);
         Map noteMap = Transform.getMap(userNoteQuestionList, UserNoteQuestion.class, "questionId", "id");
 
-        for(UserQuestionExtendDto dto : userQuestionDtos){
+        for(UserQuestionBaseDto dto : pr){
             dto.setCollect(collectMap.containsKey(dto.getQuestionId()));
             dto.setNote(noteMap.containsKey(dto.getQuestionId()));
         }
 
-        return ResponseHelp.success(userQuestionDtos);
+        // 绑定题目信息
+        List<Question> questionList = questionService.select(questionIds);
+        Transform.combine(pr, questionList, UserQuestionBaseDto.class, "questionId", "question", Question.class, "id", QuestionExtendDto.class);
+
+        List<UserQuestionBaseDto> basePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.BASE.key)).collect(Collectors.toList());
+        Collection baseQuestionNoIds = Transform.getIds(basePr, UserQuestionBaseDto.class, "questionNoId");
+        List<QuestionNo> baseQuestionNoList = questionNoService.select(baseQuestionNoIds);
+        Transform.combine(basePr, baseQuestionNoList, UserQuestionBaseDto.class, "questionNoId", "questionNo", QuestionNo.class, "id", QuestionNoExtendDto.class);
+
+        List<UserQuestionBaseDto> sentencePr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.SENTENCE.key)).collect(Collectors.toList());
+        Collection sentenceQuestionNoIds = Transform.getIds(sentencePr, UserQuestionBaseDto.class, "questionNoId");
+        List<SentenceQuestion> sentenceQuestionList = sentenceQuestionService.select(sentenceQuestionNoIds);
+        Transform.combine(sentencePr, sentenceQuestionList, UserQuestionBaseDto.class, "questionNoId", "questionNo", SentenceQuestion.class, "id", QuestionNoExtendDto.class);
+
+        List<UserQuestionBaseDto> textbookPr = pr.stream().filter((row)->row.getQuestionModule().equals(QuestionModule.TEXTBOOK.key)).collect(Collectors.toList());
+        Collection textbookQuestionNoIds = Transform.getIds(textbookPr, UserQuestionBaseDto.class, "questionNoId");
+        List<TextbookQuestion> textbookQuestionList = textbookQuestionService.select(textbookQuestionNoIds);
+        Transform.combine(textbookPr, textbookQuestionList, UserQuestionBaseDto.class, "questionNoId", "questionNo", TextbookQuestion.class, "id", QuestionNoExtendDto.class);
+
+        return ResponseHelp.success(pr);
     }
 
     @RequestMapping(value = "/examination/start", method = RequestMethod.POST)
@@ -914,9 +961,6 @@ public class QuestionController {
         }
         UserQuestionBaseDto baseDto = Transform.convert(userQuestion, UserQuestionBaseDto.class);
 
-        // 绑定questionNos
-        baseDto.setQuestionNos(Transform.convert(questionNoService.listByQuestion(userQuestion.getQuestionId()), QuestionNoExtendDto.class));
-
         // 绑定question
         baseDto.setQuestion(Transform.convert(questionService.get(userQuestion.getQuestionId()), QuestionBaseExtendDto.class));
 

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

@@ -0,0 +1,37 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.Contract;
+
+@Dto(entity = Contract.class)
+public class ContractDto {
+    private String title;
+
+    private String key;
+
+    private String content;
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getKey() {
+        return key;
+    }
+
+    public void setKey(String key) {
+        this.key = key;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+}

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

@@ -1,12 +1,5 @@
 package com.qxgmat.dto.admin.request;
 
-import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.Question;
-import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
-import org.json.JSONObject;
-
-import javax.validation.constraints.NotEmpty;
-
 public class QuestionNoSearchDto {
     private int page = 1;
 

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

@@ -0,0 +1,78 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.ReadyArticle;
+
+
+@Dto(entity = ReadyArticle.class)
+public class ReadyArticleDto {
+    private Integer id;
+
+    private Integer parentCategoryId;
+
+    private String parentCategory;
+
+    private Integer categoryId;
+
+    private String category;
+
+    private String title;
+
+    private String content;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public Integer getParentCategoryId() {
+        return parentCategoryId;
+    }
+
+    public void setParentCategoryId(Integer parentCategoryId) {
+        this.parentCategoryId = parentCategoryId;
+    }
+
+    public String getParentCategory() {
+        return parentCategory;
+    }
+
+    public void setParentCategory(String parentCategory) {
+        this.parentCategory = parentCategory;
+    }
+
+    public Integer getCategoryId() {
+        return categoryId;
+    }
+
+    public void setCategoryId(Integer categoryId) {
+        this.categoryId = categoryId;
+    }
+
+    public String getCategory() {
+        return category;
+    }
+
+    public void setCategory(String category) {
+        this.category = category;
+    }
+}

+ 8 - 18
server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/ArticleDto.java

@@ -1,16 +1,14 @@
 package com.qxgmat.dto.admin.request;
 
 import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.Article;
+import com.qxgmat.data.dao.entity.ReadyRead;
 
 
-@Dto(entity = Article.class)
-public class ArticleDto {
+@Dto(entity = ReadyRead.class)
+public class ReadyReadDto {
     private Integer id;
 
-    private String channel;
-
-    private String position;
+    private String plate;
 
     private String title;
 
@@ -40,19 +38,11 @@ public class ArticleDto {
         this.content = content;
     }
 
-    public String getChannel() {
-        return channel;
-    }
-
-    public void setChannel(String channel) {
-        this.channel = channel;
-    }
-
-    public String getPosition() {
-        return position;
+    public String getPlate() {
+        return plate;
     }
 
-    public void setPosition(String position) {
-        this.position = position;
+    public void setPlate(String plate) {
+        this.plate = plate;
     }
 }

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

@@ -0,0 +1,78 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.ReadyRoom;
+
+
+@Dto(entity = ReadyRoom.class)
+public class ReadyRoomDto {
+    private Integer id;
+
+    private String position;
+
+    private Integer areaId;
+
+    private Integer isOverseas;
+
+    private String title;
+
+    private String address;
+
+    private String description;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getPosition() {
+        return position;
+    }
+
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    public Integer getAreaId() {
+        return areaId;
+    }
+
+    public void setAreaId(Integer areaId) {
+        this.areaId = areaId;
+    }
+
+    public Integer getIsOverseas() {
+        return isOverseas;
+    }
+
+    public void setIsOverseas(Integer isOverseas) {
+        this.isOverseas = isOverseas;
+    }
+
+    public String getAddress() {
+        return address;
+    }
+
+    public void setAddress(String address) {
+        this.address = address;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+}

+ 17 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/OrderConfirmDto.java

@@ -0,0 +1,17 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderCheckout;
+
+@Dto(entity = UserOrderCheckout.class)
+public class OrderConfirmDto {
+    private Integer courseId;
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+}

+ 55 - 14
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserQuestionBaseDto.java

@@ -1,11 +1,12 @@
 package com.qxgmat.dto.response;
 
+import com.alibaba.fastjson.JSONObject;
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserQuestion;
-import com.qxgmat.dto.extend.QuestionBaseExtendDto;
+import com.qxgmat.dto.extend.QuestionExtendDto;
 import com.qxgmat.dto.extend.QuestionNoExtendDto;
 
-import java.util.List;
+import java.util.Date;
 
 @Dto(entity = UserQuestion.class)
 public class UserQuestionBaseDto {
@@ -21,14 +22,22 @@ public class UserQuestionBaseDto {
 
     private Integer questionNoId;
 
-    private QuestionBaseExtendDto question;
+    private QuestionExtendDto question;
 
     private QuestionNoExtendDto questionNo;
 
-    private List<QuestionNoExtendDto> questionNos;
+    private Integer isCorrect;
+
+    private JSONObject setting;
+
+    private JSONObject detail;
+
+    private Date updateTime;
 
     private Boolean collect;
 
+    private Boolean note;
+
     public Integer getId() {
         return id;
     }
@@ -53,22 +62,14 @@ public class UserQuestionBaseDto {
         this.questionNoId = questionNoId;
     }
 
-    public QuestionBaseExtendDto getQuestion() {
+    public QuestionExtendDto getQuestion() {
         return question;
     }
 
-    public void setQuestion(QuestionBaseExtendDto question) {
+    public void setQuestion(QuestionExtendDto question) {
         this.question = question;
     }
 
-    public List<QuestionNoExtendDto> getQuestionNos() {
-        return questionNos;
-    }
-
-    public void setQuestionNos(List<QuestionNoExtendDto> questionNos) {
-        this.questionNos = questionNos;
-    }
-
     public Boolean getCollect() {
         return collect;
     }
@@ -108,4 +109,44 @@ public class UserQuestionBaseDto {
     public void setQuestionType(String questionType) {
         this.questionType = questionType;
     }
+
+    public Integer getIsCorrect() {
+        return isCorrect;
+    }
+
+    public void setIsCorrect(Integer isCorrect) {
+        this.isCorrect = isCorrect;
+    }
+
+    public JSONObject getSetting() {
+        return setting;
+    }
+
+    public void setSetting(JSONObject setting) {
+        this.setting = setting;
+    }
+
+    public JSONObject getDetail() {
+        return detail;
+    }
+
+    public void setDetail(JSONObject detail) {
+        this.detail = detail;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    public Boolean getNote() {
+        return note;
+    }
+
+    public void setNote(Boolean note) {
+        this.note = note;
+    }
 }

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

@@ -47,15 +47,9 @@ public class UserCollectQuestionService extends AbstractService {
      * @param userId
      * @return
      */
-    public Page<UserCollectQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserCollectQuestion> listExercise(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order){
         Page<UserCollectQuestion> p = page(()->{
-            userCollectQuestionRelationMapper.listExercise(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
+            userCollectQuestionRelationMapper.listExercise(userId, keyword, questionTypes, structIds, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserCollectQuestion.class, "id");
@@ -73,15 +67,9 @@ public class UserCollectQuestionService extends AbstractService {
      * @param userId
      * @return
      */
-    public Page<UserCollectQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserCollectQuestion> listExamination(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order){
         Page<UserCollectQuestion> p = page(()->{
-            userCollectQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+            userCollectQuestionRelationMapper.listExamination(userId, keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserCollectQuestion.class, "id");

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

@@ -52,15 +52,9 @@ public class UserNoteQuestionService extends AbstractService {
      * @param direction
      * @return
      */
-    public Page<UserNoteQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserNoteQuestion> listExercise(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order){
         Page<UserNoteQuestion> p = page(()->{
-            userNoteQuestionRelationMapper.listExercise(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
+            userNoteQuestionRelationMapper.listExercise(userId, keyword, questionTypes, structIds, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserNoteQuestion.class, "id");
@@ -83,15 +77,9 @@ public class UserNoteQuestionService extends AbstractService {
      * @param direction
      * @return
      */
-    public Page<UserNoteQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserNoteQuestion> listExamination(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order){
         Page<UserNoteQuestion> p = page(()->{
-            userNoteQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+            userNoteQuestionRelationMapper.listExamination(userId, keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserNoteQuestion.class, "id");

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

@@ -59,18 +59,11 @@ public class UserPaperService extends AbstractService {
      * @param startTime
      * @param endTime
      * @param order
-     * @param direction
      * @return
      */
-    public Page<UserPaper> list(int page, int size, Integer userId, PaperOrigin origin, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserPaper> list(int page, int size, Integer userId, String keyword, PaperOrigin origin, String startTime, String endTime, String order){
         Page<UserPaper> p = page(()->{
-            userPaperRelationMapper.list(userId, origin != null ? origin.key : null, startTime, endTime, finalOrder, finalDirection.key);
+            userPaperRelationMapper.list(userId, keyword, origin != null ? origin.key : null, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserPaper.class, "id");
@@ -89,18 +82,11 @@ public class UserPaperService extends AbstractService {
      * @param startTime
      * @param endTime
      * @param order
-     * @param direction
      * @return
      */
-    public Page<UserPaper> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String[] courseModules, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserPaper> listExercise(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, String[] courseModules, String startTime, String endTime, String order){
         Page<UserPaper> p = page(()->{
-            userPaperRelationMapper.listExercise(userId, questionTypes, structIds, courseModules, startTime, endTime, finalOrder, finalDirection.key);
+            userPaperRelationMapper.listExercise(userId, keyword, questionTypes, structIds, courseModules, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserPaper.class, "id");
@@ -119,18 +105,11 @@ public class UserPaperService extends AbstractService {
      * @param startTime
      * @param endTime
      * @param order
-     * @param direction
      * @return
      */
-    public Page<UserPaper> listExamination(int page, int size, Integer userId, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserPaper> listExamination(int page, int size, Integer userId, String keyword, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order){
         Page<UserPaper> p = page(()->{
-            userPaperRelationMapper.listExamination(userId, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+            userPaperRelationMapper.listExamination(userId, keyword, structIds, libraryId, year, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserPaper.class, "id");

+ 4 - 18
server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java

@@ -48,18 +48,11 @@ public class UserQuestionService extends AbstractService {
      * @param startTime
      * @param endTime
      * @param order
-     * @param direction
      * @return
      */
-    public Page<UserQuestion> listExerciseError(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserQuestion> listExerciseError(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, String startTime, String endTime, String order){
         Page<UserQuestion> p = page(()->{
-            userQuestionRelationMapper.listExerciseError(userId, questionTypes, structIds, startTime, endTime, finalOrder, finalDirection.key);
+            userQuestionRelationMapper.listExerciseError(userId, keyword, questionTypes, structIds, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserQuestion.class, "id");
@@ -78,18 +71,11 @@ public class UserQuestionService extends AbstractService {
      * @param startTime
      * @param endTime
      * @param order
-     * @param direction
      * @return
      */
-    public Page<UserQuestion> listExaminationError(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserQuestion> listExaminationError(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, String startTime, String endTime, String order){
         Page<UserQuestion> p = page(()->{
-            userQuestionRelationMapper.listExaminationError(userId, questionTypes, structIds, libraryId, year, startTime, endTime, finalOrder, finalDirection.key);
+            userQuestionRelationMapper.listExaminationError(userId, keyword, questionTypes, structIds, libraryId, year, startTime, endTime, order);
         }, page, size);
 
         Collection ids = Transform.getIds(p, UserQuestion.class, "id");

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

@@ -292,6 +292,7 @@ public class OrderFlowService {
         initOrderCallback.put(ProductType.COURSE, ((order, userOrderCheckoutList) -> {
             BigDecimal money = order.getMoney();
             BigDecimal originMoney = order.getOriginMoney();
+            Integer vsNumber = 0;
 
             // 独立课程信息: 排除套餐内的
             List<UserOrderCheckout> courseCheckout = userOrderCheckoutList.stream().filter((checkout)-> checkout.getProductType().equals(ProductType.COURSE.key) && checkout.getParentId() == 0).collect(Collectors.toList());
@@ -334,6 +335,7 @@ public class OrderFlowService {
                 courseMoney = courseMoney.add(checkout.getMoney());
                 money = money.add(checkout.getMoney());
                 originMoney = originMoney.add(checkout.getMoney());
+                vsNumber += checkout.getNumber();
             }
 
             // 套餐费用: 添加时计算
@@ -346,14 +348,38 @@ public class OrderFlowService {
             }
 
             // 满金额处理
-            Integer ask = toolsService.getAskTime(courseMoney);
-            order.setAskTime(ask * 3600);
+            // 回复时长
+            JSONObject askInfo = toolsService.getAskTime(courseMoney);
+            if(askInfo != null) order.setAskTime(askInfo.getIntValue("hour") * 3600);
+
+            // 1v1辅导
+            JSONObject vsInfo = toolsService.getVsNumber(courseMoney);
+
+            // 满课时处理
+            Boolean coach = toolsService.getCoach(vsNumber);
 
             JSONArray gift = order.getGift();
-            if (ask> 0){
+            if (askInfo!=null && askInfo.getIntValue("money") > 0){
+                // 因为存在默认最低值,金额超过限额,才写入赠送
                 JSONObject info = new JSONObject();
                 info.put("key", "ask");
-                info.put("message", toolsService.askTimeMessage().replace("{}", ask.toString()));
+                info.put("money", askInfo.getIntValue("money"));
+                info.put("hour", askInfo.getIntValue("hour"));
+                info.put("message", toolsService.askTimeMessage().replace("{}", askInfo.getInteger("hour").toString()));
+                gift.add(info);
+            }
+            if (vsInfo != null){
+                JSONObject info = new JSONObject();
+                info.put("key", "vs");
+                info.put("money", vsInfo.getIntValue("money"));
+                info.put("number", vsInfo.getIntValue("number"));
+                info.put("message", toolsService.vsRecordMessage().replace("{}", vsInfo.getInteger("number").toString()));
+                gift.add(info);
+            }
+            if(coach){
+                JSONObject info = new JSONObject();
+                info.put("key", "coach");
+                info.put("message", toolsService.coachMessage());
                 gift.add(info);
             }
 
@@ -670,6 +696,30 @@ public class OrderFlowService {
             callback.callback(userOrder, record);
             userOrderRecordService.add(record);
         }
+
+        JSONArray gift = userOrder.getGift();
+        for(Object infoO : gift){
+            JSONObject info = (JSONObject)infoO;
+            if(info.get("key").equals("vs")){
+                // 添加赠送课时
+                Integer courseId = info.getInteger("courseId");
+                if(courseId != null){
+                    UserOrderRecord record = UserOrderRecord.builder()
+                            .orderId(userOrder.getId())
+                            .userId(userOrder.getUserId())
+                            .productType(ProductType.COURSE.key)
+                            .productId(courseId)
+                            .number(info.getIntValue("number"))
+                            .source(RecordSource.GIFT_COURSE.key)
+                            .build();
+
+                    InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
+                    callback.callback(userOrder, record);
+                    userOrderRecordService.add(record);
+                }
+            }
+        }
+
         userOrderCheckoutService.deleteByUser(userId, orderId);
 
         // 累加用户支付信息
@@ -790,9 +840,17 @@ public class OrderFlowService {
      * @return
      */
     @Transactional
-    public UserOrder makeOrder(Integer userId){
+    public UserOrder makeOrder(Integer userId, Integer courseId){
         List<UserOrderCheckout> list = userOrderCheckoutService.allByUser(userId, 0);
         UserOrder order = preOrderWithCheckout(userId, list);
+        // 保存课程赠送选择: 付款后添加
+        JSONArray gift = order.getGift();
+        for(Object infoO:gift){
+            JSONObject info = (JSONObject)infoO;
+            if(info.getString("key").equals("vs")){
+                info.put("courseId", courseId);
+            }
+        }
         order = userOrderService.add(order);
 
         // 转移购物车信息

+ 63 - 5
server/gateway-api/src/main/java/com/qxgmat/service/extend/ToolsService.java

@@ -458,7 +458,6 @@ public class ToolsService {
     }
 
     /**
-     * 获取计算回复时长:{video: {text:}}
      * @return
      */
     public String askTimeMessage(){
@@ -466,12 +465,25 @@ public class ToolsService {
     }
 
     /**
+     * @return
+     */
+    public String vsRecordMessage(){
+        return "指定1v1辅导{}课时";
+    }
+
+    /**
+     * @return
+     */
+    public String coachMessage(){
+        return "课前1v1语音复习规划辅导";
+    }
+    /**
      * 计算回复时长:{ask_time: [{"money":32,"hour":2}]}
-     * 单位:秒
+     * 单位:小时
      * @param totalMoney 课程总金额
      * @return
      */
-    public Integer getAskTime(BigDecimal totalMoney){
+    public JSONObject getAskTime(BigDecimal totalMoney){
         Setting setting = settingService.getByKey(SettingKey.PROMOTE);
         JSONObject value = setting.getValue();
 
@@ -490,9 +502,55 @@ public class ToolsService {
         }
         if (maxIndex >= 0){
             JSONObject o = settings.getJSONObject(maxIndex);
-            return o.getIntValue("hour");
+            return o;
+        }
+        return null;
+    }
+
+    /**
+     * 计算赠送1v1课时:{vs_record: [{"money":32,"number":2}]}
+     * @param totalMoney 课程总金额
+     * @return
+     */
+    public JSONObject getVsNumber(BigDecimal totalMoney){
+        Setting setting = settingService.getByKey(SettingKey.PROMOTE);
+        JSONObject value = setting.getValue();
+
+        JSONArray settings = value.getJSONArray("vs_record");
+        int max = 0;
+        int maxIndex = -1;
+        for(int i = 0; i < settings.size(); i++){
+            JSONObject o = settings.getJSONObject(i);
+            int money = o.getIntValue("money");
+            if(money < totalMoney.intValue()){
+                if (money > max){
+                    max = money;
+                    maxIndex = i;
+                }
+            }
+        }
+        if (maxIndex >= 0){
+            JSONObject o = settings.getJSONObject(maxIndex);
+            return o;
+        }
+        return null;
+    }
+
+    /**
+     * 计算赠送满课时辅导:{toach: {number: 2}}
+     * @param vsNumber 总课时数
+     * @return
+     */
+    public Boolean getCoach(Integer vsNumber){
+        Setting setting = settingService.getByKey(SettingKey.PROMOTE);
+        JSONObject value = setting.getValue();
+
+        JSONObject settings = value.getJSONObject("toach");
+        if (vsNumber >= settings.getIntValue("number")){
+            return true;
+        }else{
+            return false;
         }
-        return 0;
     }
 
     /**

+ 0 - 4
server/gateway-api/src/main/java/com/qxgmat/service/inline/AdService.java

@@ -8,12 +8,8 @@ import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.AdMapper;
 import com.qxgmat.data.dao.entity.Ad;
-import com.qxgmat.data.dao.entity.Article;
-import com.qxgmat.data.dao.entity.ExaminationStruct;
-import com.qxgmat.data.dao.entity.Message;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
-import org.springframework.cache.annotation.Cacheable;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;

+ 0 - 102
server/gateway-api/src/main/java/com/qxgmat/service/inline/ArticleService.java

@@ -1,102 +0,0 @@
-package com.qxgmat.service.inline;
-
-import com.github.pagehelper.Page;
-import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.exception.ParameterException;
-import com.nuliji.tools.exception.SystemException;
-import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.constants.enums.status.DirectionStatus;
-import com.qxgmat.data.dao.ArticleMapper;
-import com.qxgmat.data.dao.MessageMapper;
-import com.qxgmat.data.dao.entity.Article;
-import com.qxgmat.data.dao.entity.Message;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
-@Service
-public class ArticleService extends AbstractService {
-    private static final Logger logger = LoggerFactory.getLogger(ArticleService.class);
-
-    @Resource
-    private ArticleMapper articleMapper;
-
-    public Page<Article> list(int page, int size, String channel, String position, String order, DirectionStatus direction){
-        Example example = new Example(Article.class);
-        if (channel != null)
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("channel", channel)
-            );
-        if (position != null)
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("position", position)
-            );
-
-        if(order == null || order.isEmpty()) order = "id";
-        switch(direction){
-            case ASC:
-                example.orderBy(order).asc();
-                break;
-            case DESC:
-            default:
-                example.orderBy(order).desc();
-        }
-        return select(articleMapper, example, page, size);
-    }
-
-    public Article add(Article message){
-        int result = insert(articleMapper, message);
-        message = one(articleMapper, message.getId());
-        if(message == null){
-            throw new SystemException("消息添加失败");
-        }
-        return message;
-    }
-
-    public Article edit(Article message){
-        Article in = one(articleMapper, message.getId());
-        if(in == null){
-            throw new ParameterException("消息不存在");
-        }
-        int result = update(articleMapper, message);
-        return message;
-    }
-
-    public boolean delete(Number id){
-        Article in = one(articleMapper, id);
-        if(in == null){
-            throw new ParameterException("消息不存在");
-        }
-        int result = delete(articleMapper, id);
-        return result > 0;
-    }
-
-    public Article get(Number id){
-        Article in = one(articleMapper, id);
-
-        if(in == null){
-            throw new ParameterException("消息不存在");
-        }
-        return in;
-    }
-
-    public Page<Article> select(int page, int pageSize){
-        return select(articleMapper, page, pageSize);
-    }
-
-    public Page<Article> select(Integer[] ids){
-        return page(()->select(articleMapper, ids), 1, ids.length);
-    }
-
-    public List<Article> select(Collection ids){
-        return select(articleMapper, ids);
-    }
-
-}

+ 103 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ContractService.java

@@ -0,0 +1,103 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.dao.ContractMapper;
+import com.qxgmat.data.dao.RankMapper;
+import com.qxgmat.data.dao.entity.Contract;
+import com.qxgmat.data.dao.entity.Rank;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ContractService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ContractService.class);
+
+    @Resource
+    private ContractMapper contractMapper;
+
+    /**
+     * 获取所有contract数据
+     * @return
+     */
+    public List<Contract> all(){
+        return select(contractMapper);
+    }
+
+    public Contract getContract(String key){
+        Example example = new Example(Contract.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("key", key)
+        );
+        return one(contractMapper, example);
+    }
+
+    public Contract editContract(Contract contract){
+        Contract in = getContract(contract.getKey());
+        if (in == null){
+            return add(contract);
+        }else{
+            contract.setId(in.getId());
+            return edit(contract);
+        }
+    }
+
+    public Contract add(Contract rank){
+        int result = insert(contractMapper, rank);
+        rank = one(contractMapper, rank.getId());
+        if(rank == null){
+            throw new SystemException("添加失败");
+        }
+        return rank;
+    }
+
+    public Contract edit(Contract rank){
+        Contract in = one(contractMapper, rank.getId());
+        if(in == null){
+            throw new ParameterException("合同不存在");
+        }
+        int result = update(contractMapper, rank);
+        return rank;
+    }
+
+    public boolean delete(Number id){
+        Contract in = one(contractMapper, id);
+        if(in == null){
+            throw new ParameterException("合同不存在");
+        }
+        int result = delete(contractMapper, id);
+        return result > 0;
+    }
+
+    public Contract get(Number id){
+        Contract in = one(contractMapper, id);
+
+        if(in == null){
+            throw new ParameterException("合同不存在");
+        }
+        return in;
+    }
+
+    public Page<Contract> select(int page, int pageSize){
+        return select(contractMapper, page, pageSize);
+    }
+
+    public Page<Contract> select(Integer[] ids){
+        return page(()->select(contractMapper, ids), 1, ids.length);
+    }
+
+    public List<Contract> select(Collection ids){
+        return select(contractMapper, ids);
+    }
+
+}

+ 103 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyArticleCategoryService.java

@@ -0,0 +1,103 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.ReadyArticleCategoryMapper;
+import com.qxgmat.data.dao.ReadyArticleMapper;
+import com.qxgmat.data.dao.entity.ReadyArticle;
+import com.qxgmat.data.dao.entity.ReadyArticleCategory;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ReadyArticleCategoryService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ReadyArticleCategoryService.class);
+
+    @Resource
+    private ReadyArticleCategoryMapper readyArticleCategoryMapper;
+
+    public List<ReadyArticleCategory> all(){
+        Example example = new Example(ReadyArticleCategory.class);
+        example.setOrderByClause("id asc");
+        return select(readyArticleCategoryMapper);
+    }
+
+    public ReadyArticleCategory getCategory(String title, Integer parentId){
+        Example example = new Example(ReadyArticleCategory.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("title", title)
+                        .andEqualTo("parentId", parentId)
+        );
+        return one(readyArticleCategoryMapper, example);
+    }
+
+    public ReadyArticleCategory addCategory(String title, Integer parentId){
+        ReadyArticleCategory in = getCategory(title, parentId);
+        if (in == null){
+            return add(ReadyArticleCategory.builder()
+                    .parentId(parentId)
+                    .title(title)
+                    .build());
+        }
+        return in;
+    }
+
+    public ReadyArticleCategory add(ReadyArticleCategory entity){
+        int result = insert(readyArticleCategoryMapper, entity);
+        entity = one(readyArticleCategoryMapper, entity.getId());
+        if(entity == null){
+            throw new SystemException("文章分类添加失败");
+        }
+        return entity;
+    }
+
+    public ReadyArticleCategory edit(ReadyArticleCategory entity){
+        ReadyArticleCategory in = one(readyArticleCategoryMapper, entity.getId());
+        if(in == null){
+            throw new ParameterException("文章分类不存在");
+        }
+        int result = update(readyArticleCategoryMapper, entity);
+        return entity;
+    }
+
+    public boolean delete(Number id){
+        ReadyArticleCategory in = one(readyArticleCategoryMapper, id);
+        if(in == null){
+            throw new ParameterException("文章分类不存在");
+        }
+        int result = delete(readyArticleCategoryMapper, id);
+        return result > 0;
+    }
+
+    public ReadyArticleCategory get(Number id){
+        ReadyArticleCategory in = one(readyArticleCategoryMapper, id);
+
+        if(in == null){
+            throw new ParameterException("文章分类不存在");
+        }
+        return in;
+    }
+
+    public Page<ReadyArticleCategory> select(int page, int pageSize){
+        return select(readyArticleCategoryMapper, page, pageSize);
+    }
+
+    public Page<ReadyArticleCategory> select(Integer[] ids){
+        return page(()->select(readyArticleCategoryMapper, ids), 1, ids.length);
+    }
+
+    public List<ReadyArticleCategory> select(Collection ids){
+        return select(readyArticleCategoryMapper, ids);
+    }
+
+}

+ 100 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyArticleService.java

@@ -0,0 +1,100 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.ReadyArticleMapper;
+import com.qxgmat.data.dao.ReadyReadMapper;
+import com.qxgmat.data.dao.entity.ReadyArticle;
+import com.qxgmat.data.dao.entity.ReadyRead;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ReadyArticleService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ReadyArticleService.class);
+
+    @Resource
+    private ReadyArticleMapper readyArticleMapper;
+
+    public Page<ReadyArticle> list(int page, int size, Integer parentCategoryId, Integer categoryId, String order, DirectionStatus direction){
+        Example example = new Example(ReadyArticle.class);
+        if (parentCategoryId != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("parentCategoryId", parentCategoryId)
+            );
+        if (categoryId != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("categoryId", categoryId)
+            );
+        if(order == null || order.isEmpty()) order = "id";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(readyArticleMapper, example, page, size);
+    }
+
+    public ReadyArticle add(ReadyArticle entity){
+        int result = insert(readyArticleMapper, entity);
+        entity = one(readyArticleMapper, entity.getId());
+        if(entity == null){
+            throw new SystemException("文章添加失败");
+        }
+        return entity;
+    }
+
+    public ReadyArticle edit(ReadyArticle entity){
+        ReadyArticle in = one(readyArticleMapper, entity.getId());
+        if(in == null){
+            throw new ParameterException("文章不存在");
+        }
+        int result = update(readyArticleMapper, entity);
+        return entity;
+    }
+
+    public boolean delete(Number id){
+        ReadyArticle in = one(readyArticleMapper, id);
+        if(in == null){
+            throw new ParameterException("文章不存在");
+        }
+        int result = delete(readyArticleMapper, id);
+        return result > 0;
+    }
+
+    public ReadyArticle get(Number id){
+        ReadyArticle in = one(readyArticleMapper, id);
+
+        if(in == null){
+            throw new ParameterException("文章不存在");
+        }
+        return in;
+    }
+
+    public Page<ReadyArticle> select(int page, int pageSize){
+        return select(readyArticleMapper, page, pageSize);
+    }
+
+    public Page<ReadyArticle> select(Integer[] ids){
+        return page(()->select(readyArticleMapper, ids), 1, ids.length);
+    }
+
+    public List<ReadyArticle> select(Collection ids){
+        return select(readyArticleMapper, ids);
+    }
+
+}

+ 93 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyReadService.java

@@ -0,0 +1,93 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.ReadyReadMapper;
+import com.qxgmat.data.dao.entity.ReadyRead;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ReadyReadService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ReadyReadService.class);
+
+    @Resource
+    private ReadyReadMapper readyReadMapper;
+
+    public Page<ReadyRead> list(int page, int size, String plate, String order, DirectionStatus direction){
+        Example example = new Example(ReadyRead.class);
+        if (plate != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("plate", plate)
+            );
+        if(order == null || order.isEmpty()) order = "id";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(readyReadMapper, example, page, size);
+    }
+
+    public ReadyRead add(ReadyRead entity){
+        int result = insert(readyReadMapper, entity);
+        entity = one(readyReadMapper, entity.getId());
+        if(entity == null){
+            throw new SystemException("阅读添加失败");
+        }
+        return entity;
+    }
+
+    public ReadyRead edit(ReadyRead entity){
+        ReadyRead in = one(readyReadMapper, entity.getId());
+        if(in == null){
+            throw new ParameterException("阅读不存在");
+        }
+        int result = update(readyReadMapper, entity);
+        return entity;
+    }
+
+    public boolean delete(Number id){
+        ReadyRead in = one(readyReadMapper, id);
+        if(in == null){
+            throw new ParameterException("阅读不存在");
+        }
+        int result = delete(readyReadMapper, id);
+        return result > 0;
+    }
+
+    public ReadyRead get(Number id){
+        ReadyRead in = one(readyReadMapper, id);
+
+        if(in == null){
+            throw new ParameterException("阅读不存在");
+        }
+        return in;
+    }
+
+    public Page<ReadyRead> select(int page, int pageSize){
+        return select(readyReadMapper, page, pageSize);
+    }
+
+    public Page<ReadyRead> select(Integer[] ids){
+        return page(()->select(readyReadMapper, ids), 1, ids.length);
+    }
+
+    public List<ReadyRead> select(Collection ids){
+        return select(readyReadMapper, ids);
+    }
+
+}

+ 82 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyRoomAreaService.java

@@ -0,0 +1,82 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.ReadyRoomAreaMapper;
+import com.qxgmat.data.dao.ReadyRoomMapper;
+import com.qxgmat.data.dao.entity.ReadyRoom;
+import com.qxgmat.data.dao.entity.ReadyRoomArea;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ReadyRoomAreaService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ReadyRoomAreaService.class);
+
+    @Resource
+    private ReadyRoomAreaMapper readyRoomAreaMapper;
+
+    public List<ReadyRoomArea> all(){
+        Example example = new Example(ReadyRoomArea.class);
+        example.setOrderByClause("id asc");
+        return select(readyRoomAreaMapper);
+    }
+
+    public ReadyRoomArea add(ReadyRoomArea entity){
+        int result = insert(readyRoomAreaMapper, entity);
+        entity = one(readyRoomAreaMapper, entity.getId());
+        if(entity == null){
+            throw new SystemException("区域添加失败");
+        }
+        return entity;
+    }
+
+    public ReadyRoomArea edit(ReadyRoomArea entity){
+        ReadyRoomArea in = one(readyRoomAreaMapper, entity.getId());
+        if(in == null){
+            throw new ParameterException("区域不存在");
+        }
+        int result = update(readyRoomAreaMapper, entity);
+        return entity;
+    }
+
+    public boolean delete(Number id){
+        ReadyRoomArea in = one(readyRoomAreaMapper, id);
+        if(in == null){
+            throw new ParameterException("区域不存在");
+        }
+        int result = delete(readyRoomAreaMapper, id);
+        return result > 0;
+    }
+
+    public ReadyRoomArea get(Number id){
+        ReadyRoomArea in = one(readyRoomAreaMapper, id);
+
+        if(in == null){
+            throw new ParameterException("区域不存在");
+        }
+        return in;
+    }
+
+    public Page<ReadyRoomArea> select(int page, int pageSize){
+        return select(readyRoomAreaMapper, page, pageSize);
+    }
+
+    public Page<ReadyRoomArea> select(Integer[] ids){
+        return page(()->select(readyRoomAreaMapper, ids), 1, ids.length);
+    }
+
+    public List<ReadyRoomArea> select(Collection ids){
+        return select(readyRoomAreaMapper, ids);
+    }
+
+}

+ 100 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/ReadyRoomService.java

@@ -0,0 +1,100 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.dao.ReadyArticleMapper;
+import com.qxgmat.data.dao.ReadyRoomMapper;
+import com.qxgmat.data.dao.entity.ReadyArticle;
+import com.qxgmat.data.dao.entity.ReadyRoom;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class ReadyRoomService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(ReadyRoomService.class);
+
+    @Resource
+    private ReadyRoomMapper readyRoomMapper;
+
+    public Page<ReadyRoom> list(int page, int size, String position, Integer areaId, String order, DirectionStatus direction){
+        Example example = new Example(ReadyRoom.class);
+        if (position != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("position", position)
+            );
+        if (areaId != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("areaId", areaId)
+            );
+        if(order == null || order.isEmpty()) order = "id";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(readyRoomMapper, example, page, size);
+    }
+
+    public ReadyRoom add(ReadyRoom entity){
+        int result = insert(readyRoomMapper, entity);
+        entity = one(readyRoomMapper, entity.getId());
+        if(entity == null){
+            throw new SystemException("考场添加失败");
+        }
+        return entity;
+    }
+
+    public ReadyRoom edit(ReadyRoom entity){
+        ReadyRoom in = one(readyRoomMapper, entity.getId());
+        if(in == null){
+            throw new ParameterException("考场不存在");
+        }
+        int result = update(readyRoomMapper, entity);
+        return entity;
+    }
+
+    public boolean delete(Number id){
+        ReadyRoom in = one(readyRoomMapper, id);
+        if(in == null){
+            throw new ParameterException("考场不存在");
+        }
+        int result = delete(readyRoomMapper, id);
+        return result > 0;
+    }
+
+    public ReadyRoom get(Number id){
+        ReadyRoom in = one(readyRoomMapper, id);
+
+        if(in == null){
+            throw new ParameterException("考场不存在");
+        }
+        return in;
+    }
+
+    public Page<ReadyRoom> select(int page, int pageSize){
+        return select(readyRoomMapper, page, pageSize);
+    }
+
+    public Page<ReadyRoom> select(Integer[] ids){
+        return page(()->select(readyRoomMapper, ids), 1, ids.length);
+    }
+
+    public List<ReadyRoom> select(Collection ids){
+        return select(readyRoomMapper, ids);
+    }
+
+}

+ 4 - 16
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java

@@ -34,15 +34,9 @@ public class UserAskQuestionService extends AbstractService {
     @Resource
     private UserAskQuestionRelationMapper userAskQuestionRelationMapper;
 
-    public Page<UserAskQuestion> listExercise(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, AskStatus status, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserAskQuestion> listExercise(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, AskStatus status, String startTime, String endTime, String order){
         Page<UserAskQuestion> p = page(
-            ()-> userAskQuestionRelationMapper.listExercise(userId, questionTypes, structIds, status != null ? status.index:null, startTime, endTime, finalOrder, finalDirection.key)
+            ()-> userAskQuestionRelationMapper.listExercise(userId, keyword, questionTypes, structIds, status != null ? status.index:null, startTime, endTime, order)
         , page, size);
 
         Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");
@@ -50,15 +44,9 @@ public class UserAskQuestionService extends AbstractService {
         return p;
     }
 
-    public Page<UserAskQuestion> listExamination(int page, int size, Integer userId, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, AskStatus status, String startTime, String endTime, String order, DirectionStatus direction){
-        if(order == null || order.isEmpty()) order = "id";
-        if (direction == null){
-            direction = DirectionStatus.DESC;
-        }
-        String finalOrder = order;
-        DirectionStatus finalDirection = direction;
+    public Page<UserAskQuestion> listExamination(int page, int size, Integer userId, String keyword, String[] questionTypes, Integer[] structIds, Integer libraryId, String year, AskStatus status, String startTime, String endTime, String order){
         Page<UserAskQuestion> p = page(
-                ()-> userAskQuestionRelationMapper.listExamination(userId, questionTypes, structIds, libraryId, year, status != null ? status.index:null, startTime, endTime, finalOrder, finalDirection.key)
+                ()-> userAskQuestionRelationMapper.listExamination(userId, keyword, questionTypes, structIds, libraryId, year, status != null ? status.index:null, startTime, endTime, order)
                 , page, size);
 
         Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");