Browse Source

Merge branch 'master' of www.gitinn.com:zaixianjiaoyu/sourcecode

# Conflicts:
#	front/project/www/components/Login/index.js
#	front/project/www/routes/paper/process/sentence/index.js
#	front/project/www/stores/user.js
KaysonCui 5 years ago
parent
commit
39722f6b6c
100 changed files with 3548 additions and 1052 deletions
  1. 7 1
      front/project/Constant.js
  2. 9 0
      front/project/admin/routes/course/detail/page.js
  3. 1 1
      front/project/admin/routes/course/vsDetail/page.js
  4. 15 0
      front/project/admin/routes/show/deploy/index.js
  5. 3 0
      front/project/admin/routes/show/deploy/index.less
  6. 418 0
      front/project/admin/routes/show/deploy/page.js
  7. 2 1
      front/project/admin/routes/show/index.js
  8. 16 0
      front/project/admin/stores/system.js
  9. 3 2
      front/project/h5/routes/page/identity/page.js
  10. 16 11
      front/project/h5/routes/page/study/page.js
  11. 2 2
      front/project/h5/routes/textbook/main/page.js
  12. 1 1
      front/project/h5/stores/course.js
  13. 7 0
      front/project/h5/stores/main.js
  14. 4 3
      front/project/h5/stores/my.js
  15. 20 6
      front/project/h5/stores/user.js
  16. 282 46
      front/project/www/components/Login/index.js
  17. 7 3
      front/project/www/local.json
  18. 13 0
      front/project/www/routes/examination/main/page.js
  19. 52 42
      front/project/www/routes/exercise/main/page.js
  20. 99 141
      front/project/www/routes/paper/process/base/index.js
  21. 2 2
      front/project/www/routes/paper/process/page.js
  22. 109 34
      front/project/www/routes/paper/process/sentence/index.js
  23. 12 0
      front/project/www/routes/paper/process/sentence/index.less
  24. 56 38
      front/project/www/routes/paper/question/page.js
  25. 1 0
      front/project/www/routes/paper/report/index.js
  26. 46 16
      front/project/www/routes/paper/report/page.js
  27. 10 0
      front/project/www/routes/preview/list/index.js
  28. 59 0
      front/project/www/routes/preview/list/index.less
  29. 286 0
      front/project/www/routes/preview/list/page.js
  30. 0 10
      front/project/www/routes/sentence/process/index.js
  31. 0 0
      front/project/www/routes/sentence/process/page.js
  32. 29 26
      front/project/www/routes/sentence/read/page.js
  33. 10 2
      front/project/www/stores/course.js
  34. 14 0
      front/project/www/stores/main.js
  35. 15 3
      front/project/www/stores/question.js
  36. 25 23
      front/project/www/stores/user.js
  37. 1 1
      server/data/src/main/java/com/qxgmat/data/constants/enums/ServiceKey.java
  38. 2 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  39. 17 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/logic/TextbookLogic.java
  40. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/CourseStudentOnlineMapper.java
  41. 23 23
      server/data/src/main/java/com/qxgmat/data/dao/entity/Course.java
  42. 0 195
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentOnline.java
  43. 7 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExaminationPaper.java
  44. 92 22
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibraryHistory.java
  45. 35 35
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookPaper.java
  46. 16 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookQuestion.java
  47. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrderRecord.java
  48. 70 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java
  49. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserReport.java
  50. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserService.java
  51. 3 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseMapper.xml
  52. 0 20
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseStudentOnlineMapper.xml
  53. 4 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookLibraryHistoryMapper.xml
  54. 3 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookPaperMapper.xml
  55. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/TextbookQuestionMapper.xml
  56. 5 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml
  57. 5 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPaperMapper.xml
  58. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserReportMapper.xml
  59. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceMapper.xml
  60. 36 0
      server/data/src/main/java/com/qxgmat/data/relation/PreviewAssignRelationMapper.java
  61. 19 0
      server/data/src/main/java/com/qxgmat/data/relation/TextbookPaperRelationMapper.java
  62. 14 6
      server/data/src/main/java/com/qxgmat/data/relation/UserCourseRecordRelationMapper.java
  63. 36 0
      server/data/src/main/java/com/qxgmat/data/relation/UserOrderRecordRelationMapper.java
  64. 0 5
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java
  65. 22 0
      server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java
  66. 7 2
      server/data/src/main/java/com/qxgmat/data/relation/UserSentenceRecordRelationMapper.java
  67. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/entity/UserCourseStatRelation.java
  68. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/entity/UserSentenceStatRelation.java
  69. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExaminationPaperRelationMapper.xml
  70. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExercisePaperRelationMapper.xml
  71. 97 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewAssignRelationMapper.xml
  72. 40 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookPaperRelationMapper.xml
  73. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookQuestionRelationMapper.xml
  74. 41 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCourseRecordRelationMapper.xml
  75. 88 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml
  76. 0 21
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml
  77. 56 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml
  78. 21 4
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserSentenceRecordRelationMapper.xml
  79. 45 18
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  80. 8 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java
  81. 34 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  82. 11 4
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  83. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/AuthController.java
  84. 21 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java
  85. 101 58
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  86. 28 81
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  87. 72 19
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  88. 2 6
      server/gateway-api/src/main/java/com/qxgmat/controller/api/SentenceController.java
  89. 163 11
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  90. 0 5
      server/gateway-api/src/main/java/com/qxgmat/controller/api/WechatController.java
  91. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/CourseStudentOnlineDto.java
  92. 30 10
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/TextbookLibraryHistoryDto.java
  93. 15 15
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CourseStudentOnlineListDto.java
  94. 140 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserCourseAppointmentExtendDto.java
  95. 109 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserServiceRecordExtendDto.java
  96. 73 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserTextbookGroupExtendDto.java
  97. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/MyDto.java
  98. 18 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/PaperBaseDto.java
  99. 102 21
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseDetailDto.java
  100. 0 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseProgressDto.java

+ 7 - 1
front/project/Constant.js

@@ -56,7 +56,11 @@ export const SentenceOption = [{ label: '平行', value: 'parallel' }, { label:
 
 
 export const ExaminationSubject = [{ short: 'V', value: 'verbal', label: '语文', english: 'Verbal' }, { short: 'Q', value: 'quant', label: '数学', english: 'Quant' }, { short: 'IR', value: 'ir', label: '综合推理', english: 'LR' }, { short: 'AWA', value: 'awa', label: '作文', english: 'AWA' }];
 export const ExaminationSubject = [{ short: 'V', value: 'verbal', label: '语文', english: 'Verbal' }, { short: 'Q', value: 'quant', label: '数学', english: 'Quant' }, { short: 'IR', value: 'ir', label: '综合推理', english: 'LR' }, { short: 'AWA', value: 'awa', label: '作文', english: 'AWA' }];
 
 
-export const ExaminationOrder = [{ list: ['awa', 'ir', 'quant', 'verbal'] }, { list: ['quant', 'verbal', 'ir', 'awa'] }, { list: ['verbal', 'quant', 'ir', 'awa'] }];
+export const ExaminationOrder = [
+  { label: 'ARQV', value: ['awa', 'ir', 'quant', 'verbal'], list: [{ label: 'Analytical Writing Analysis', value: 'awa' }, { label: 'Integrated Reasoning', value: 'ir' }, { label: 'Quantitative', value: 'quant' }, { label: 'Verbal', value: 'verbal' }] },
+  { label: 'VQRA', value: ['verbal', 'quant', 'ir', 'awa'], list: [{ label: 'Verbal', value: 'verbal' }, { label: 'Quantitative', value: 'quant' }, { label: 'Integrated Reasoning', value: 'ir' }, { label: 'Analytical Writing Analysis', value: 'awa' }] },
+  { label: 'QVRA', value: ['quant', 'verbal', 'ir', 'awa'], list: [{ label: 'Quantitative', value: 'quant' }, { label: 'Verbal', value: 'verbal' }, { label: 'Integrated Reasoning', value: 'ir' }, { label: 'Analytical Writing Analysis', value: 'awa' }] },
+];
 
 
 export const DataType = [{ label: '电子', value: 'electron' }, { label: '纸质', value: 'paper' }];
 export const DataType = [{ label: '电子', value: 'electron' }, { label: '纸质', value: 'paper' }];
 
 
@@ -70,6 +74,8 @@ export const ExperiencePercent = [{ label: '50+', value: '_50' }, { label: '100+
 
 
 export const CourseModule = [{ label: '视频课程', value: 'video' }, { label: '小班课程', value: 'online' }, { label: '1v1课程', value: 'vs' }];
 export const CourseModule = [{ label: '视频课程', value: 'video' }, { label: '小班课程', value: 'online' }, { label: '1v1课程', value: 'vs' }];
 
 
+export const CourseModuleShow = [{ label: '在线课程', value: 'online', courseModules: ['video', 'online'] }, { label: '1V1私教', value: 'vs', courseModules: ['vs'] }];
+
 export const CourseVsType = [{ label: '新手辅导', value: 'novice' }, { label: '诊断辅导', value: 'coach' }, { label: '系统授课', value: 'system' }, { label: '答疑课', value: 'answer' }];
 export const CourseVsType = [{ label: '新手辅导', value: 'novice' }, { label: '诊断辅导', value: 'coach' }, { label: '系统授课', value: 'system' }, { label: '答疑课', value: 'answer' }];
 
 
 export const CourseVideoType = [{ label: '基础刷题', value: 'base' }, { label: '系统授课', value: 'system' }, { label: '思维提升', value: 'thinking' }];
 export const CourseVideoType = [{ label: '基础刷题', value: 'base' }, { label: '系统授课', value: 'system' }, { label: '思维提升', value: 'thinking' }];

+ 9 - 0
front/project/admin/routes/course/detail/page.js

@@ -311,6 +311,15 @@ export default class extends Page {
             <Input placeholder='请输入课程名称' />,
             <Input placeholder='请输入课程名称' />,
           )}
           )}
         </Form.Item>
         </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='有效期'>
+          {getFieldDecorator('expireDays', {
+            rules: [
+              { required: true, message: '请输入有效期' },
+            ],
+          })(
+            <InputNumber placeholder='天' />,
+          )}
+        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='教师'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='教师'>
           {getFieldDecorator('teacher', {
           {getFieldDecorator('teacher', {
             rules: [
             rules: [

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

@@ -138,7 +138,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='有效期'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='有效期'>
-          {getFieldDecorator('expireDays', {
+          {getFieldDecorator('expirePreDays', {
             rules: [
             rules: [
               { required: true, message: '请输入有效期' },
               { required: true, message: '请输入有效期' },
             ],
             ],

+ 15 - 0
front/project/admin/routes/show/deploy/index.js

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

+ 3 - 0
front/project/admin/routes/show/deploy/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#show-deploy {}

+ 418 - 0
front/project/admin/routes/show/deploy/page.js

@@ -0,0 +1,418 @@
+import React from 'react';
+import { Tabs, Form, Row, Col, Input, InputNumber, Button, Upload, Icon } from 'antd';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import { flattenObject } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { ServiceParamMap } from '../../../../Constant';
+import { System } from '../../../stores/system';
+
+export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.state.tab = 'qx_cat';
+    this.vipList = ServiceParamMap.vip;
+  }
+
+  initData() {
+    this.refresh(this.state.tab);
+  }
+
+  refresh(tab) {
+    if (tab === 'qx_cat') {
+      return this.refreshQxCat();
+    }
+    if (tab === 'textbook') {
+      return this.refreshTextbook();
+    }
+    if (tab === 'vip') {
+      return this.refreshVip();
+    }
+    return Promise.reject();
+  }
+
+  refreshQxCat() {
+    return System.getServiceQxCat().then(result => {
+      this.setState({ qx_cat: result || {} });
+      const { form } = this.props;
+      form.setFieldsValue(flattenObject(result, 'qx_cat'));
+    });
+  }
+
+  refreshTextbook() {
+    return System.getServiceTextbook().then(result => {
+      this.setState({ textbook: result || {} });
+      const { form } = this.props;
+      form.setFieldsValue(flattenObject(result, 'textbook'));
+    });
+  }
+
+  refreshVip() {
+    return System.getServiceVip().then(result => {
+      this.setState({ vip: result || {} });
+      const { form } = this.props;
+      form.setFieldsValue(flattenObject(result, 'vip'));
+    });
+  }
+
+  changeMapValue(field, second, index, key, value) {
+    const data = this.state[field] || {};
+    data[second] = data[second] || [];
+    data[second][index] = data[second][index] || {};
+    data[second][index][key] = value;
+    this.setState({ [field]: data });
+  }
+
+  submit(tab) {
+    let handler;
+    if (tab === 'qx_cat') {
+      handler = this.submitQxCat();
+    }
+    if (tab === 'textbook') {
+      handler = this.submitTextbook();
+    }
+    if (tab === 'vip') {
+      handler = this.submitVip();
+    }
+    handler.then(() => {
+      asyncSMessage('保存成功');
+    });
+  }
+
+  submitQxCat() {
+    const { qx_cat } = this.state;
+    return System.setServiceQxCat(qx_cat);
+  }
+
+  submitTextbook() {
+    const { textbook } = this.state;
+    return System.setServiceTextbook(textbook);
+  }
+
+  submitVip() {
+    const { vip } = this.state;
+    return System.setServiceVip(vip);
+  }
+
+  renderQxCat() {
+    const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
+    const image = getFieldValue('qx_cat.image') || null;
+    return <Form>
+      <Row>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品价格'>
+          {getFieldDecorator('qx_cat.package[0].price', {
+            rules: [
+              { required: true, message: '输入千行Cat价格' },
+            ],
+          })(
+            <InputNumber placeholder='请输入千行Cat价格' onChange={(value) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'price', value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='服务名称'>
+          {getFieldDecorator('qx_cat.package[0].title', {
+            rules: [
+              { required: true, message: '输入千行Cat名称' },
+            ],
+          })(
+            <Input placeholder='请输入千行Cat名称' onChange={(e) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'title', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='服务简介'>
+          {getFieldDecorator('qx_cat.package[0].description', {
+            rules: [
+              { required: true, message: '输入千行Cat服务简介' },
+            ],
+          })(
+            <Input placeholder='请输入千行Cat服务简介' onChange={(e) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'description', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='有效期说明'>
+          {getFieldDecorator('qx_cat.package[0].expire_info', {
+            rules: [
+              { required: true, message: '输入千行Cat有效期说明' },
+            ],
+          })(
+            <Input placeholder='请输入千行Cat有效期说明' onChange={(e) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'expire_info', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='退款政策'>
+          {getFieldDecorator('qx_cat.package[0].refund_policy', {
+            rules: [
+              { required: true, message: '输入千行Cat退款政策' },
+            ],
+          })(
+            <Input placeholder='请输入千行Cat退款政策' onChange={(e) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'refund_policy', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='版权说明'>
+          {getFieldDecorator('qx_cat.package[0].copyright_notes', {
+            rules: [
+              { required: true, message: '输入千行Cat版权说明' },
+            ],
+          })(
+            <Input placeholder='请输入千行Cat版权说明' onChange={(e) => {
+              this.changeMapValue('qx_cat', 'package', 0, 'copyright_notes', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品图片'>
+          {getFieldDecorator('qx_cat.image', {
+            rules: [
+              { required: true, message: '上传图片' },
+            ],
+          })(
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                setFieldsValue({ 'qx_cat.image': result.url });
+                return Promise.reject();
+              })}
+            >
+              {image ? <img src={image} alt="avatar" /> : <div>
+                <Icon type={this.state.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">Upload</div>
+              </div>}
+            </Upload>,
+          )}
+        </Form.Item>
+      </Row>
+    </Form>;
+  }
+
+  renderTextbook() {
+    const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
+    const image = getFieldValue('textbook.image') || null;
+    return <Form>
+      <Row>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品图片'>
+          {getFieldDecorator('textbook.image', {
+            rules: [
+              { required: true, message: '上传图片' },
+            ],
+          })(
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                setFieldsValue({ 'textbook.image': result.url });
+                return Promise.reject();
+              })}
+            >
+              {image ? <img src={image} alt="avatar" /> : <div>
+                <Icon type={this.state.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">Upload</div>
+              </div>}
+            </Upload>,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品价格'>
+          {getFieldDecorator('textbook.package[0].price', {
+            rules: [
+              { required: true, message: '输入数学机经价格' },
+            ],
+          })(
+            <InputNumber placeholder='请输入数学机经价格' onChange={(value) => {
+              this.changeMapValue('textbook', 'package', 0, 'price', value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='服务名称'>
+          {getFieldDecorator('textbook.package[0].title', {
+            rules: [
+              { required: true, message: '输入数学机经名称' },
+            ],
+          })(
+            <Input placeholder='请输入数学机经名称' onChange={(e) => {
+              this.changeMapValue('textbook', 'package', 0, 'title', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='服务简介'>
+          {getFieldDecorator('textbook.package[0].description', {
+            rules: [
+              { required: true, message: '输入数学机经服务简介' },
+            ],
+          })(
+            <Input placeholder='请输入数学机经服务简介' onChange={(e) => {
+              this.changeMapValue('textbook', 'package', 0, 'description', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='有效期说明'>
+          {getFieldDecorator('textbook.package[0].expire_info', {
+            rules: [
+              { required: true, message: '输入数学机经有效期说明' },
+            ],
+          })(
+            <Input placeholder='请输入数学机经有效期说明' onChange={(e) => {
+              this.changeMapValue('textbook', 'package', 0, 'expire_info', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='退款政策'>
+          {getFieldDecorator('textbook.package[0].refund_policy', {
+            rules: [
+              { required: true, message: '输入数学机经退款政策' },
+            ],
+          })(
+            <Input placeholder='请输入数学机经退款政策' onChange={(e) => {
+              this.changeMapValue('textbook', 'package', 0, 'refund_policy', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='版权说明'>
+          {getFieldDecorator('textbook.package[0].copyright_notes', {
+            rules: [
+              { required: true, message: '输入数学机经版权说明' },
+            ],
+          })(
+            <Input placeholder='请输入数学机经版权说明' onChange={(e) => {
+              this.changeMapValue('textbook', 'package', 0, 'copyright_notes', e.target.value);
+            }} style={{ width: '200px' }} />,
+          )}
+        </Form.Item>
+      </Row>
+    </Form>;
+  }
+
+  renderVip() {
+    const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
+    const image = getFieldValue('vip.image') || null;
+    return <Form>
+      <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='商品图片'>
+        {getFieldDecorator('vip.image', {
+          rules: [
+            { required: true, message: '上传图片' },
+          ],
+        })(
+          <Upload
+            listType="picture-card"
+            showUploadList={false}
+            beforeUpload={(file) => System.uploadImage(file).then((result) => {
+              setFieldsValue({ 'vip.image': result.url });
+              return Promise.reject();
+            })}
+          >
+            {image ? <img src={image} alt="avatar" /> : <div>
+              <Icon type={this.state.loading ? 'loading' : 'plus'} />
+              <div className="ant-upload-text">Upload</div>
+            </div>}
+          </Upload>,
+        )}
+      </Form.Item>
+      <Row>
+        {this.vipList.map((row, index) => {
+          return <Col span={12}>
+            <h1>{row.label}</h1>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='商品价格'>
+              {getFieldDecorator(`vip.package[${index}].price`, {
+                rules: [
+                  { required: true, message: '输入价格' },
+                ],
+              })(
+                <InputNumber placeholder={'输入价格'} onChange={(value) => {
+                  this.changeMapValue('vip', 'package', index, 'price', value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='服务名称'>
+              {getFieldDecorator(`vip.package[${index}].title`, {
+                rules: [
+                  { required: true, message: '输入名称' },
+                ],
+              })(
+                <Input placeholder={'输入名称'} onChange={(e) => {
+                  this.changeMapValue('vip', 'package', index, 'title', e.target.value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='服务简介'>
+              {getFieldDecorator(`vip.package[${index}].description`, {
+                rules: [
+                  { required: true, message: '输入服务简介' },
+                ],
+              })(
+                <Input placeholder='请输入服务简介' onChange={(e) => {
+                  this.changeMapValue('vip', 'package', index, 'description', e.target.value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='有效期说明'>
+              {getFieldDecorator(`vip.package[${index}].expire_info`, {
+                rules: [
+                  { required: true, message: '输入有效期说明' },
+                ],
+              })(
+                <Input placeholder='请输入有效期说明' onChange={(e) => {
+                  this.changeMapValue('vip', 'package', index, 'expire_info', e.target.value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='退款政策'>
+              {getFieldDecorator(`vip.package[${index}].refund_policy`, {
+                rules: [
+                  { required: true, message: '输入退款政策' },
+                ],
+              })(
+                <Input placeholder='请输入退款政策' onChange={(e) => {
+                  this.changeMapValue('vip', 'package', index, 'refund_policy', e.target.value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+            <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='版权说明'>
+              {getFieldDecorator(`vip.package[${index}].copyright_notes`, {
+                rules: [
+                  { required: true, message: '输入版权说明' },
+                ],
+              })(
+                <Input placeholder='请输入版权说明' onChange={(e) => {
+                  this.changeMapValue('vip', 'package', index, 'copyright_notes', e.target.value);
+                }} style={{ width: '200px' }} />,
+              )}
+            </Form.Item>
+          </Col>;
+        })}
+
+      </Row>
+    </Form>;
+  }
+
+  renderView() {
+    const { tab } = this.state;
+    return <Block><Tabs activeKey={tab} onChange={(value) => {
+      this.setState({ tab: value, selectedKeys: [], checkedKeys: [] });
+      this.refresh(value);
+    }}>
+      <Tabs.TabPane tab="千行Cat" key="qx_cat">
+        {this.renderQxCat()}
+      </Tabs.TabPane>
+      <Tabs.TabPane tab="数学机经" key="textbook">
+        {this.renderTextbook()}
+      </Tabs.TabPane>
+      <Tabs.TabPane tab="Vip" key="vip">
+        {this.renderVip()}
+      </Tabs.TabPane>
+    </Tabs>
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit(tab);
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </Block>;
+  }
+}

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

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

+ 16 - 0
front/project/admin/stores/system.js

@@ -149,6 +149,14 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/experience_info', params);
     return this.apiPut('/setting/experience_info', params);
   }
   }
 
 
+  getWechatInfo() {
+    return this.apiGet('/setting/wechat_info');
+  }
+
+  setWechatInfo(params) {
+    return this.apiPut('/setting/wechat_info', params);
+  }
+
   getTips() {
   getTips() {
     return this.apiGet('/setting/tips');
     return this.apiGet('/setting/tips');
   }
   }
@@ -157,6 +165,14 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/tips', params);
     return this.apiPut('/setting/tips', params);
   }
   }
 
 
+  getSentenceInfo() {
+    return this.apiGet('/setting/sentence_info');
+  }
+
+  setTSentenceInfo(params) {
+    return this.apiPut('/setting/sentence_info', params);
+  }
+
   listRank(params) {
   listRank(params) {
     return this.apiGet('/setting/rank/list', params);
     return this.apiGet('/setting/rank/list', params);
   }
   }

+ 3 - 2
front/project/h5/routes/page/identity/page.js

@@ -6,6 +6,7 @@ import { asyncSMessage } from '@src/services/AsyncTools';
 import { dataURLtoBlob, formatDate } from '@src/services/Tools';
 import { dataURLtoBlob, formatDate } from '@src/services/Tools';
 import Icon from '../../../components/Icon';
 import Icon from '../../../components/Icon';
 import { Common } from '../../../stores/common';
 import { Common } from '../../../stores/common';
+// import { Main } from '../../../stores/main';
 import { My } from '../../../stores/my';
 import { My } from '../../../stores/my';
 
 
 export default class extends Page {
 export default class extends Page {
@@ -107,7 +108,7 @@ export default class extends Page {
     return (
     return (
       <div>
       <div>
         <div className="text">
         <div className="text">
-          请扫描您的居民身份证原件,领取6个月VIP权限。
+          请扫描您的居民身份证原件,领取90天VIP权限。
           <br />
           <br />
           千行将重视和保护您的隐私。
           千行将重视和保护您的隐私。
         </div>
         </div>
@@ -145,7 +146,7 @@ export default class extends Page {
           <Icon type="check-circle" />
           <Icon type="check-circle" />
         </div>
         </div>
         <div className="title">认证完成!</div>
         <div className="title">认证完成!</div>
-        <div className="desc">180天VIP权限已赠送至您的账户</div>
+        <div className="desc">90天VIP权限已赠送至您的账户</div>
         <div className="desc">生效时间:{formatDate(data.useStartTime, 'YYYY-MM-DD')}</div>
         <div className="desc">生效时间:{formatDate(data.useStartTime, 'YYYY-MM-DD')}</div>
       </div>
       </div>
     );
     );

+ 16 - 11
front/project/h5/routes/page/study/page.js

@@ -1,7 +1,7 @@
 import React from 'react';
 import React from 'react';
 import './index.less';
 import './index.less';
 import Page from '@src/containers/Page';
 import Page from '@src/containers/Page';
-import { formatDate, formatSeconds } from '@src/services/Tools';
+import { formatDate, formatSeconds, formatPercent } from '@src/services/Tools';
 import Icon from '../../../components/Icon';
 import Icon from '../../../components/Icon';
 import { My } from '../../../stores/my';
 import { My } from '../../../stores/my';
 
 
@@ -12,13 +12,20 @@ export default class extends Page {
     My.getStudyTotal().then(total => {
     My.getStudyTotal().then(total => {
       this.setState({ total });
       this.setState({ total });
     });
     });
-    My.getStudyWeek().then(week => {
-      this.setState({ week });
+    My.getStudyWeek(0).then(latest => {
+      const diff = latest.time - latest.avgTime;
+      const diffPercent = diff > 0 ? formatPercent(latest.time - latest.avgTime, latest.avgTime, true) : formatPercent(latest.avgTime - latest.time, latest.avgTime, true);
+      this.setState({ latest, diff, diffPercent });
+      My.getStudyWeek(1).then(last => {
+        const diffLast = latest.time - last.time;
+        const diffLastPercent = diffLast > 0 ? formatPercent(latest.time - last.time, last.time, true) : formatPercent(last.time - latest.time, last.time, true);
+        this.setState({ last, diffLast, diffLastPercent });
+      });
     });
     });
   }
   }
 
 
   renderView() {
   renderView() {
-    const { total } = this.state;
+    const { total, latest = {}, diff = 0, diffPercent = 0, diffLast = 0, diffLastPercent = 0 } = this.state;
     return (
     return (
       <div>
       <div>
         <div className="block">
         <div className="block">
@@ -33,22 +40,20 @@ export default class extends Page {
         <div className="t-c">
         <div className="t-c">
           <div className="item">
           <div className="item">
             <div className="text">学习时间</div>
             <div className="text">学习时间</div>
-            <div className="value">
-              <span>23</span>Hour
-            </div>
+            <div className="value" dangerouslySetInnerHTML={{ __html: formatSeconds(latest.time).replace(/([0-9]+)([msh])/g, '<span>$1</span>$2') }} />
           </div>
           </div>
           <div className="item">
           <div className="item">
             <div className="text">同比上周</div>
             <div className="text">同比上周</div>
             <div className="value">
             <div className="value">
-              <Icon type="caret-up" theme="filled" color="#6EC64B" />
-              <span>15</span>%
+              {diffLast > 0 ? <Icon type="caret-up" theme="filled" color="#6EC64B" /> : <Icon type="caret-down" theme="filled" color="#F36565" />}
+              <span>{diffLastPercent}</span>%
             </div>
             </div>
           </div>
           </div>
           <div className="item">
           <div className="item">
             <div className="text">同比全站</div>
             <div className="text">同比全站</div>
             <div className="value">
             <div className="value">
-              <Icon type="caret-down" theme="filled" color="#F36565" />
-              <span>15</span>%
+              {diff > 0 ? <Icon type="caret-up" theme="filled" color="#6EC64B" /> : <Icon type="caret-down" theme="filled" color="#F36565" />}
+              <span>{diffPercent}</span>%
             </div>
             </div>
           </div>
           </div>
         </div>
         </div>

+ 2 - 2
front/project/h5/routes/textbook/main/page.js

@@ -79,14 +79,14 @@ export default class extends Page {
 
 
   renderEmpty() {
   renderEmpty() {
     const { unUseRecord } = this.state;
     const { unUseRecord } = this.state;
-    if (unUseRecord > 0) {
+    if (unUseRecord) {
       return <div className="empty">
       return <div className="empty">
         <div className="text">
         <div className="text">
           还未开通本月机经。 <br />
           还未开通本月机经。 <br />
           您可至千行网站「我的-工具」查看往期机经。
           您可至千行网站「我的-工具」查看往期机经。
       </div>
       </div>
         <Button block width={120} radius onClick={() => {
         <Button block width={120} radius onClick={() => {
-          linkTo(`/open/${unUseRecord}`);
+          linkTo(`/open/${unUseRecord.id}`);
         }}>
         }}>
           去开通
           去开通
       </Button>
       </Button>

+ 1 - 1
front/project/h5/stores/course.js

@@ -13,7 +13,7 @@ export default class CourseStore extends BaseStore {
   }
   }
 
 
   get(courseId) {
   get(courseId) {
-    return this.apiGet('/course/detail', { courseId });
+    return this.apiGet('/course/simple', { courseId });
   }
   }
 
 
   listPackage(params) {
   listPackage(params) {

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

@@ -28,6 +28,13 @@ export default class MainStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取微信信息
+   */
+  getWechat() {
+    return this.apiGet('/base/wechat');
+  }
+
+  /**
    * 获取对应位置的提示tips
    * 获取对应位置的提示tips
    * @param {*} position
    * @param {*} position
    */
    */

+ 4 - 3
front/project/h5/stores/my.js

@@ -108,10 +108,11 @@ export default class MyStore extends BaseStore {
   }
   }
 
 
   /**
   /**
-   * 获取本周学习记录
+   * 获取每周学习记录
+   * @param {*} week 0本周,1上周
    */
    */
-  getStudyWeek() {
-    return this.apiGet('/my/study/week', {});
+  getStudyWeek(week) {
+    return this.apiGet('/my/study/week', { week });
   }
   }
 
 
   /**
   /**

+ 20 - 6
front/project/h5/stores/user.js

@@ -10,6 +10,11 @@ export default class UserStore extends BaseStore {
     return { login: false };
     return { login: false };
   }
   }
 
 
+  infoHandle(result) {
+    this.setToken(result.token);
+    this.setState({ login: true, needLogin: false, info: result, username: result.username });
+  }
+
   originInviteCode(inviteCode) {
   originInviteCode(inviteCode) {
     this.setState({
     this.setState({
       inviteCode,
       inviteCode,
@@ -19,8 +24,14 @@ export default class UserStore extends BaseStore {
   /**
   /**
    * 验证token
    * 验证token
    */
    */
-  token() {
-    return this.apiPost('/auth/token');
+  refreshToken() {
+    return this.apiPost('/auth/token')
+      .then(result => {
+        this.infoHandle(result);
+      })
+      .catch(() => {
+        this.logout(false);
+      });
   }
   }
 
 
   /**
   /**
@@ -34,13 +45,16 @@ export default class UserStore extends BaseStore {
     if (!inviteCode) {
     if (!inviteCode) {
       ({ inviteCode } = this.state);
       ({ inviteCode } = this.state);
     }
     }
-    return this.apiPost('/auth/login', { area, mobile, mobileVerifyCode, inviteCode });
+    return this.apiPost('/auth/login', { area, mobile, mobileVerifyCode, inviteCode }).then(result => {
+      this.infoHandle(result);
+      return result;
+    });
   }
   }
 
 
   loginWechat(code) {
   loginWechat(code) {
-    return this.apiGet('/auth/wechat', { code }).then((info) => {
-      this.setState({ login: true, info });
-      return info;
+    return this.apiGet('/auth/wechat', { code }).then((result) => {
+      this.infoHandle(result);
+      return result;
     });
     });
   }
   }
 
 

+ 282 - 46
front/project/www/components/Login/index.js

@@ -2,12 +2,15 @@ import React, { Component } from 'react';
 import './index.less';
 import './index.less';
 import { Modal, Icon, Button, Tooltip } from 'antd';
 import { Modal, Icon, Button, Tooltip } from 'antd';
 import Assets from '@src/components/Assets';
 import Assets from '@src/components/Assets';
+import { asyncSMessage } from '@src/services/AsyncTools';
 import { Icon as GIcon } from '../Icon';
 import { Icon as GIcon } from '../Icon';
 import { Button as GButton } from '../Button';
 import { Button as GButton } from '../Button';
 import { User } from '../../stores/user';
 import { User } from '../../stores/user';
+import { My } from '../../stores/my';
+import { Common } from '../../stores/common';
+import { MobileArea } from '../../../Constant';
 
 
 const LOGIN_PHONE = 'LOGIN_PHONE';
 const LOGIN_PHONE = 'LOGIN_PHONE';
-const REGISTER_PHONE = 'REGISTER_PHONE';
 const LOGIN_WX = 'LOGIN_WX';
 const LOGIN_WX = 'LOGIN_WX';
 const BIND_PHONE = 'BIND_PHONE';
 const BIND_PHONE = 'BIND_PHONE';
 const BIND_WX = 'BIND_WX';
 const BIND_WX = 'BIND_WX';
@@ -33,23 +36,148 @@ export default class Login extends Component {
     User.closeLogin();
     User.closeLogin();
   }
   }
 
 
+  login() {
+    const { data, needEmail, mobileError, validError } = this.state;
+    const { area, mobile, mobileVerifyCode, email } = data;
+    if (mobileError !== '' || validError !== '') return;
+    if (area === '' || mobile === '' || mobileVerifyCode === '') return;
+    if (needEmail && email === '') return;
+    User.login(area, mobile, mobileVerifyCode)
+      .then(() => {
+        let handler = null;
+        if (needEmail) {
+          handler = My.bindEmail(email);
+        } else {
+          handler = Promise.resolve();
+        }
+        handler.then(result => {
+          if (result.bindWechat) {
+            this.close();
+          } else {
+            this.setState({ type: BIND_WX });
+          }
+        });
+      })
+      .catch(err => {
+        if (err.message.indexOf('验证码') >= 0) {
+          this.setState({ validError: err.message });
+        } else {
+          this.setState({ mobileError: err.message });
+        }
+      });
+  }
+
+  bind() {
+    const { data, needEmail, mobileError, validError } = this.state;
+    const { area, mobile, mobileVerifyCode, email } = data;
+    if (mobileError !== '' || validError !== '') return;
+    if (area === '' || mobile === '' || mobileVerifyCode === '') return;
+    if (needEmail && email === '') return;
+    User.bind(area, mobile, mobileVerifyCode)
+      .then(() => {
+        let handler = null;
+        if (needEmail) {
+          handler = My.bindEmail(email);
+        } else {
+          handler = Promise.resolve();
+        }
+        handler.then(() => {
+          this.close();
+        });
+      })
+      .catch(err => {
+        if (err.message.indexOf('验证码') >= 0) {
+          this.setState({ validError: err.message });
+        } else {
+          this.setState({ mobileError: err.message });
+        }
+      });
+  }
+
+  scanLogin() {
+    User.loginWechat('').then(result => {
+      if (result.bindMobile) {
+        this.close();
+      } else {
+        this.setState({ type: BIND_PHONE });
+      }
+    });
+  }
+
+  scanBind() {
+    User.loginWechat('')
+      .then(() => {
+        this.close();
+      })
+      .catch(err => {
+        this.setState({ type: BIND_WX_ERROR, wechatError: err.message });
+      });
+  }
+
+  changeData(field, value) {
+    let { data } = this.state;
+    data = data || {};
+    data[field] = value;
+    this.setState({ data });
+  }
+
+  validMobile() {
+    const { data } = this.state;
+    const { area, mobile } = data;
+    if (area === '' || mobile === '') return;
+    User.validWechat(area, mobile)
+      .then(result => {
+        if (result) {
+          this.setState({ mobileError: '' });
+          return User.validMobile(area, mobile).then(r => {
+            this.setState({ needEmail: r });
+          });
+        }
+        this.setState({ needEmail: false });
+        return Promise.reject(new Error('该手机已绑定其他账号,请更换手机号码'));
+      })
+      .catch(err => {
+        this.setState({ mobileError: err.message });
+      });
+  }
+
+  sendValid() {
+    const { data, mobileError } = this.state;
+    const { area, mobile } = data;
+    if (area === '' || mobile === '' || mobileError !== '') return Promise.reject();
+    return Common.sendSms(area, mobile)
+      .then(result => {
+        if (result) {
+          asyncSMessage('发送成功');
+          this.setState({ mobileError: '', validError: '' });
+        } else {
+          throw new Error('发送失败');
+        }
+      })
+      .catch(err => {
+        this.setState({ mobileError: err.message });
+        throw err;
+      });
+  }
+
   render() {
   render() {
     const { type } = this.state;
     const { type } = this.state;
     const { user } = this.props;
     const { user } = this.props;
     return (
     return (
       <Modal wrapClassName={`login-modal ${type}`} visible={user.needLogin} footer={null} closable={false} width={470}>
       <Modal wrapClassName={`login-modal ${type}`} visible={user.needLogin} footer={null} closable={false} width={470}>
         {this.renderBody(type)}
         {this.renderBody(type)}
-        <GIcon name="close" onClick={() => this.close()} />
+        <GIcon
+          name="close"
+          onClick={() => {
+            this.close();
+          }}
+        />
       </Modal>
       </Modal>
     );
     );
   }
   }
 
 
   renderBody(type) {
   renderBody(type) {
     switch (type) {
     switch (type) {
-      case LOGIN_PHONE:
-        return this.renderLoginPhone();
-      case REGISTER_PHONE:
-        return this.renderRegisterPhone();
       case LOGIN_WX:
       case LOGIN_WX:
         return this.renderLoginWx();
         return this.renderLoginWx();
       case BIND_PHONE:
       case BIND_PHONE:
@@ -58,45 +186,69 @@ export default class Login extends Component {
         return this.renderBindWx();
         return this.renderBindWx();
       case BIND_WX_ERROR:
       case BIND_WX_ERROR:
         return this.renderBindWxError();
         return this.renderBindWxError();
+      case LOGIN_PHONE:
       default:
       default:
-        return this.LOGIN_PHONE();
+        return this.renderLoginPhone();
     }
     }
   }
   }
 
 
   renderLoginPhone() {
   renderLoginPhone() {
+    const { needEmail } = this.state;
     return (
     return (
       <div className="body">
       <div className="body">
         <div className="title">手机号登录</div>
         <div className="title">手机号登录</div>
-        <SelectInput placeholder="请输入手机号" />
-        <VerificationInput placeholder="请输入验证码" />
-        <Button type="primary" size="large" block>
-          登录
-        </Button>
-        <Tooltip overlayClassName="gray" placement="left" title="微信扫码登录">
-          <a className="other">
-            <Assets name="code" />
-          </a>
-        </Tooltip>
-      </div>
-    );
-  }
-
-  renderRegisterPhone() {
-    return (
-      <div className="body">
-        <div className="title">手机号登录</div>
-        <div className="tip">
+        <div className="tip" hidden={!needEmail}>
           <Assets name="notice" />
           <Assets name="notice" />
           该手机号尚未注册,将自动为您注册账户
           该手机号尚未注册,将自动为您注册账户
         </div>
         </div>
-        <SelectInput placeholder="请输入手机号" />
-        <VerificationInput placeholder="请输入验证码" />
-        <Input placeholder="请输入邮箱" />
-        <Button type="primary" size="large" block>
+        <SelectInput
+          placeholder="请输入手机号"
+          selectValue={this.state.data.area}
+          select={MobileArea}
+          value={this.state.data.mobile}
+          error={this.state.mobileError}
+          onSelect={value => {
+            this.changeData('area', value);
+          }}
+          onChange={e => {
+            this.changeData('mobile', e.target.value);
+            this.validMobile(e.target.value);
+          }}
+        />
+        <VerificationInput
+          placeholder="请输入验证码"
+          value={this.state.data.mobileVerifyCode}
+          error={this.state.validError}
+          onSend={() => {
+            return this.sendValid();
+          }}
+        />
+        {needEmail && (
+          <Input
+            placeholder="请输入邮箱"
+            value={this.state.data.email}
+            onChange={e => {
+              this.changeData('email', e.target.value);
+            }}
+          />
+        )}
+        <Button
+          type="primary"
+          size="large"
+          block
+          onClick={() => {
+            this.login();
+          }}
+        >
           登录
           登录
         </Button>
         </Button>
         <Tooltip overlayClassName="gray" placement="left" title="微信扫码登录">
         <Tooltip overlayClassName="gray" placement="left" title="微信扫码登录">
-          <a className="other">
+          <a
+            className="other"
+            onClick={() => {
+              this.setState({ type: LOGIN_WX });
+            }}
+          >
             <Assets name="code" />
             <Assets name="code" />
           </a>
           </a>
         </Tooltip>
         </Tooltip>
@@ -113,7 +265,12 @@ export default class Login extends Component {
           <div className="text">请使用微信扫描二维码登录</div>
           <div className="text">请使用微信扫描二维码登录</div>
         </div>
         </div>
         <Tooltip overlayClassName="gray" placement="left" title="手机号登录">
         <Tooltip overlayClassName="gray" placement="left" title="手机号登录">
-          <a className="other">
+          <a
+            className="other"
+            onClick={() => {
+              this.setState({ type: LOGIN_PHONE });
+            }}
+          >
             <Assets name="phone" />
             <Assets name="phone" />
           </a>
           </a>
         </Tooltip>
         </Tooltip>
@@ -122,6 +279,7 @@ export default class Login extends Component {
   }
   }
 
 
   renderBindPhone() {
   renderBindPhone() {
+    const { needEmail } = this.state;
     return (
     return (
       <div className="body">
       <div className="body">
         <div className="title">绑定手机号</div>
         <div className="title">绑定手机号</div>
@@ -129,10 +287,45 @@ export default class Login extends Component {
           <Assets name="notice" />
           <Assets name="notice" />
           微信登录成功!为更好的使用服务,请您绑定手机号和邮箱。
           微信登录成功!为更好的使用服务,请您绑定手机号和邮箱。
         </div>
         </div>
-        <SelectInput placeholder="请输入手机号" />
-        <VerificationInput placeholder="请输入验证码" />
-        <Input placeholder="请输入邮箱" />
-        <Button type="primary" size="large" block>
+        <SelectInput
+          placeholder="请输入手机号"
+          selectValue={this.state.data.area}
+          select={MobileArea}
+          value={this.state.data.mobile}
+          error={this.state.mobileError}
+          onSelect={value => {
+            this.changeData('area', value);
+          }}
+          onChange={e => {
+            this.changeData('mobile', e.target.value);
+            this.validMobile(e.target.value);
+          }}
+        />
+        <VerificationInput
+          placeholder="请输入验证码"
+          value={this.state.data.mobileVerifyCode}
+          error={this.state.validError}
+          onSend={() => {
+            return this.sendValid();
+          }}
+        />
+        {needEmail && (
+          <Input
+            placeholder="请输入邮箱"
+            value={this.state.data.email}
+            onChange={e => {
+              this.changeData('email', e.target.value);
+            }}
+          />
+        )}
+        <Button
+          type="primary"
+          size="large"
+          block
+          onClick={() => {
+            this.bind();
+          }}
+        >
           绑定
           绑定
         </Button>
         </Button>
       </div>
       </div>
@@ -150,7 +343,14 @@ export default class Login extends Component {
         <div className="qr-code">
         <div className="qr-code">
           <Assets name="qrcode" />
           <Assets name="qrcode" />
           <div className="text">请使用微信扫描二维码登录</div>
           <div className="text">请使用微信扫描二维码登录</div>
-          <div className="jump">跳过</div>
+          <div
+            className="jump"
+            onClick={() => {
+              this.close();
+            }}
+          >
+            跳过
+          </div>
         </div>
         </div>
       </div>
       </div>
     );
     );
@@ -162,7 +362,14 @@ export default class Login extends Component {
         <div className="title">绑定失败</div>
         <div className="title">绑定失败</div>
         <div className="text">该微信账户已绑定其他手机号,您可直接使用微信登入。</div>
         <div className="text">该微信账户已绑定其他手机号,您可直接使用微信登入。</div>
         <div className="btn">
         <div className="btn">
-          <GButton radius>Ok</GButton>
+          <GButton
+            radius
+            onClick={() => {
+              this.close();
+            }}
+          >
+            Ok
+          </GButton>
         </div>
         </div>
       </div>
       </div>
     );
     );
@@ -171,12 +378,17 @@ export default class Login extends Component {
 
 
 class Input extends Component {
 class Input extends Component {
   render() {
   render() {
-    const { className = '', onChange, placeholder, error, left, right } = this.props;
+    const { className = '', onChange, placeholder, value, error, left, right } = this.props;
     return (
     return (
       <div className={`g-input-container ${className}`}>
       <div className={`g-input-container ${className}`}>
         <div className={`g-input-wrapper ${error ? 'error' : ''}`}>
         <div className={`g-input-wrapper ${error ? 'error' : ''}`}>
           {left && <div className="g-input-left">{left}</div>}
           {left && <div className="g-input-left">{left}</div>}
-          <input className="g-input" placeholder={placeholder} onChange={data => onChange && onChange(data)} />
+          <input
+            className="g-input"
+            placeholder={placeholder}
+            value={value}
+            onChange={data => onChange && onChange(data)}
+          />
           {right && <div className="g-input-right">{right}</div>}
           {right && <div className="g-input-right">{right}</div>}
         </div>
         </div>
         <div hidden={!error} className="g-input-error">
         <div hidden={!error} className="g-input-error">
@@ -188,26 +400,49 @@ class Input extends Component {
 }
 }
 
 
 class SelectInput extends Component {
 class SelectInput extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { showSelect: false };
+  }
+
   render() {
   render() {
-    const { className = '', onChange, placeholder, value, selectValue, onSelect } = this.props;
+    const { showSelect } = this.state;
+    const { className = '', onChange, placeholder, value, error, selectValue, select, onSelect } = this.props;
     return (
     return (
       <Input
       <Input
         className={className}
         className={className}
         left={
         left={
-          <span className="g-input-left-select" onClick={() => onSelect && onSelect()}>
+          <span className="g-input-left-select" onClick={() => this.setState({ showSelect: !showSelect })}>
             {selectValue}
             {selectValue}
-            <Icon type="down" />
+            <Icon type={showSelect ? 'up' : 'down'} />
+            {showSelect && (
+              <ul className="select-list">
+                {select.map(row => {
+                  return (
+                    <li
+                      onClick={() => {
+                        this.setState({ showSelect: false });
+                        if (onSelect) onSelect(row.value);
+                      }}
+                    >
+                      {row.label}
+                    </li>
+                  );
+                })}
+              </ul>
+            )}
           </span>
           </span>
         }
         }
         value={value}
         value={value}
         placeholder={placeholder}
         placeholder={placeholder}
         onChange={data => onChange && onChange(data)}
         onChange={data => onChange && onChange(data)}
+        error={error}
       />
       />
     );
     );
   }
   }
 }
 }
 
 
-class VerificationInput extends Component {
+export class VerificationInput extends Component {
   constructor(props) {
   constructor(props) {
     super(props);
     super(props);
     this.timeKey = null;
     this.timeKey = null;
@@ -221,9 +456,10 @@ class VerificationInput extends Component {
   onSend() {
   onSend() {
     const { onSend, time = 60 } = this.props;
     const { onSend, time = 60 } = this.props;
     if (onSend) {
     if (onSend) {
-      onSend();
+      onSend().then(() => {
+        this.setTime(time);
+      });
     }
     }
-    this.setTime(time);
   }
   }
 
 
   setTime(time) {
   setTime(time) {

+ 7 - 3
front/project/www/local.json

@@ -14,9 +14,13 @@
     ]
     ]
   },
   },
   "test": {
   "test": {
-    "scripts": ["http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"]
+    "scripts": [
+      "http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"
+    ]
   },
   },
   "production": {
   "production": {
-    "scripts": ["http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"]
+    "scripts": [
+      "http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"
+    ]
   }
   }
-}
+}

+ 13 - 0
front/project/www/routes/examination/main/page.js

@@ -1,6 +1,7 @@
 import React from 'react';
 import React from 'react';
 import './index.less';
 import './index.less';
 import { Link } from 'react-router-dom';
 import { Link } from 'react-router-dom';
+import { Tooltip } from 'antd';
 import Page from '@src/containers/Page';
 import Page from '@src/containers/Page';
 import { asyncConfirm } from '@src/services/AsyncTools';
 import { asyncConfirm } from '@src/services/AsyncTools';
 import { formatTreeData, getMap } from '@src/services/Tools';
 import { formatTreeData, getMap } from '@src/services/Tools';
@@ -532,6 +533,18 @@ export default class extends Page {
             },
             },
             { type: 'select', checked: 'all', list: [{ key: 'all', title: '全部' }] },
             { type: 'select', checked: 'all', list: [{ key: 'all', title: '全部' }] },
           ]}
           ]}
+          rightAction={
+            <div>
+              有效期至:2019-11-13{' '}
+              <Tooltip overlayClassName="gray" placement="top" title="全部模考做完才可重置">
+                <a>
+                  <Button size="small" disabled radius>
+                    Reset
+                  </Button>
+                </a>
+              </Tooltip>
+            </div>
+          }
           data={previews}
           data={previews}
           columns={this.columns}
           columns={this.columns}
         />
         />

+ 52 - 42
front/project/www/routes/exercise/main/page.js

@@ -1,6 +1,6 @@
 import React from 'react';
 import React from 'react';
 import './index.less';
 import './index.less';
-import { Modal, Tooltip } from 'antd';
+import { Modal } from 'antd';
 import { Link } from 'react-router-dom';
 import { Link } from 'react-router-dom';
 import Page from '@src/containers/Page';
 import Page from '@src/containers/Page';
 import { asyncConfirm } from '@src/services/AsyncTools';
 import { asyncConfirm } from '@src/services/AsyncTools';
@@ -25,10 +25,11 @@ import { Sentence } from '../../../stores/sentence';
 import { Question } from '../../../stores/question';
 import { Question } from '../../../stores/question';
 import { Course } from '../../../stores/course';
 import { Course } from '../../../stores/course';
 import { User } from '../../../stores/user';
 import { User } from '../../../stores/user';
+import { CourseModuleShow } from '../../../../Constant';
 
 
 const SENTENCE = 'sentence';
 const SENTENCE = 'sentence';
 const PREVIEW = 'preview';
 const PREVIEW = 'preview';
-const PREVIEW_CLASS = 'PREVIEW_CLASS';
+const PREVIEW_COURSE = 'PREVIEW_COURSE';
 const PREVIEW_LIST = 'PREVIEW_LIST';
 const PREVIEW_LIST = 'PREVIEW_LIST';
 
 
 const exerciseColumns = [
 const exerciseColumns = [
@@ -263,14 +264,15 @@ export default class extends Page {
     this.code = null;
     this.code = null;
     this.columns = exerciseColumns;
     this.columns = exerciseColumns;
     this.exerciseProgress = {};
     this.exerciseProgress = {};
+    this.courseProgress = {};
     this.inited = false;
     this.inited = false;
     return {
     return {
       tab1: SENTENCE,
       tab1: SENTENCE,
       tab2: '',
       tab2: '',
-      pt: PREVIEW_CLASS,
+      previewType: PREVIEW_COURSE,
       tabs: [],
       tabs: [],
-      allClass: [],
-      classProcess: {},
+      allCourse: [],
+      courseProgress: {},
     };
     };
   }
   }
 
 
@@ -282,11 +284,20 @@ export default class extends Page {
         return row;
         return row;
       });
       });
       const tabs = formatTreeData(list, 'id', 'title', 'parentId');
       const tabs = formatTreeData(list, 'id', 'title', 'parentId');
+      // 课程顶级分类
+      const courseStructs = result.filter(row => row.isCourse && row.level === 1);
       tabs.push({ key: PREVIEW, name: '预习作业' });
       tabs.push({ key: PREVIEW, name: '预习作业' });
-      this.setState({ tabs });
+      this.setState({ tabs, courseStructs });
       this.inited = true;
       this.inited = true;
       this.refreshData();
       this.refreshData();
     });
     });
+    this.setState({
+      courseTabs: CourseModuleShow.map(row => {
+        row.title = row.label;
+        row.key = row.value;
+        return row;
+      }),
+    });
   }
   }
 
 
   initData() {
   initData() {
@@ -396,26 +407,36 @@ export default class extends Page {
   }
   }
 
 
   refreshPreview() {
   refreshPreview() {
-    const { pt } = this.state;
-    switch (pt) {
+    const { previewType } = this.state;
+    switch (previewType) {
       case PREVIEW_LIST:
       case PREVIEW_LIST:
         this.refreshListPreview();
         this.refreshListPreview();
         break;
         break;
-      case PREVIEW_CLASS:
+      case PREVIEW_COURSE:
       default:
       default:
-        this.refreshClassProcess();
+        this.refreshCourseProcess();
         break;
         break;
     }
     }
   }
   }
 
 
-  refreshClassProcess() {
-    Course.classProcess().then(result => {
-      const classProcess = {};
+  refreshCourseProcess() {
+    const { courseTabs, structId } = this.state;
+    let { tab2 } = this.state;
+    let tab;
+    if (tab2 === '') {
+      tab2 = courseTabs[0].key;
+      this.setState({ tab2 });
+      ([tab] = courseTabs);
+    } else {
+      ([tab] = courseTabs.filter(row => row.key === tab2));
+    }
+    Course.progress(tab.courseModules, structId).then(result => {
+      const courseProgress = {};
       for (let i = 0; i < result.length; i += 1) {
       for (let i = 0; i < result.length; i += 1) {
         const item = result[i];
         const item = result[i];
-        classProcess[item.category].push(item);
+        courseProgress[item.category].push(item);
       }
       }
-      this.setState({ classProcess });
+      this.setState({ courseProgress });
     });
     });
   }
   }
 
 
@@ -479,7 +500,7 @@ export default class extends Page {
   }
   }
 
 
   onChangePreviewType(type) {
   onChangePreviewType(type) {
-    this.setState({ pt: type });
+    this.setState({ previewType: type });
     this.refreshPreview();
     this.refreshPreview();
   }
   }
 
 
@@ -568,9 +589,9 @@ export default class extends Page {
   }
   }
 
 
   renderView() {
   renderView() {
-    const { tab1, tab2, tabs, latest, sentenceModel } = this.state;
+    const { tab1, tab2, tabs, latest, sentenceModel, previewType, courseTabs = [] } = this.state;
     const [subject] = tabs.filter(row => row.key === tab1);
     const [subject] = tabs.filter(row => row.key === tab1);
-    const children = subject ? subject.children : [];
+    const children = subject ? subject.children : (tab1 === 'preview' && previewType === 'PREVIEW_COURSE' ? courseTabs : []);
     return (
     return (
       <div>
       <div>
         {latest && (
         {latest && (
@@ -603,6 +624,7 @@ export default class extends Page {
             {children && children.length > 1 && (
             {children && children.length > 1 && (
               <Tabs active={tab2} tabs={children} onChange={key => this.onChangeTab(2, key)} />
               <Tabs active={tab2} tabs={children} onChange={key => this.onChangeTab(2, key)} />
             )}
             )}
+            {}
           </Module>
           </Module>
           {tab1 !== SENTENCE && tab1 !== PREVIEW && this.renderExercise()}
           {tab1 !== SENTENCE && tab1 !== PREVIEW && this.renderExercise()}
           {tab1 === SENTENCE && this.renderSentence()}
           {tab1 === SENTENCE && this.renderSentence()}
@@ -616,8 +638,8 @@ export default class extends Page {
   renderPreview() {
   renderPreview() {
     const { previewType } = this.state;
     const { previewType } = this.state;
     switch (previewType) {
     switch (previewType) {
-      case PREVIEW_CLASS:
-        return this.renderPreviewClass();
+      case PREVIEW_COURSE:
+        return this.renderPreviewCourse();
       case PREVIEW_LIST:
       case PREVIEW_LIST:
         return this.renderPreviewList();
         return this.renderPreviewList();
       default:
       default:
@@ -625,8 +647,8 @@ export default class extends Page {
     }
     }
   }
   }
 
 
-  renderPreviewClass() {
-    const { allClass, classProcess } = this.state;
+  renderPreviewCourse() {
+    const { allCourse, courseProgress } = this.state;
     return (
     return (
       <div className="work-body">
       <div className="work-body">
         <div className="work-nav">
         <div className="work-nav">
@@ -636,8 +658,8 @@ export default class extends Page {
           </div>
           </div>
         </div>
         </div>
         <Division col="3">
         <Division col="3">
-          {allClass.map(item => {
-            return <Card data={item} process={classProcess[item.id]} previewAction={this.previewAction} />;
+          {allCourse.map(item => {
+            return <Card data={item} process={courseProgress[item.id]} previewAction={this.previewAction} />;
           })}
           })}
         </Division>
         </Division>
       </div>
       </div>
@@ -650,7 +672,7 @@ export default class extends Page {
       <div className="work-body">
       <div className="work-body">
         <div className="work-nav">
         <div className="work-nav">
           <div className="left">全部作业</div>
           <div className="left">全部作业</div>
-          <div className="right theme c-p" onClick={() => this.onChangePreviewType(PREVIEW_CLASS)}>
+          <div className="right theme c-p" onClick={() => this.onChangePreviewType(PREVIEW_COURSE)}>
             我的课程 >
             我的课程 >
           </div>
           </div>
         </div>
         </div>
@@ -666,20 +688,7 @@ export default class extends Page {
               checked: 'unfinish',
               checked: 'unfinish',
               list: [{ key: 'unfinish', title: '未完成' }, { key: 'finish', title: '已完成' }],
               list: [{ key: 'unfinish', title: '未完成' }, { key: 'finish', title: '已完成' }],
             },
             },
-            { type: 'select', checked: 'all', list: [{ key: 'all', title: '全部' }] },
           ]}
           ]}
-          rightAction={
-            <div>
-              有效期至:2019-11-13{' '}
-              <Tooltip overlayClassName="gray" placement="top" title="全部模考做完才可重置">
-                <a>
-                  <Button size="small" disabled radius>
-                    Reset
-                  </Button>
-                </a>
-              </Tooltip>
-            </div>
-          }
           data={previews}
           data={previews}
           columns={this.columns}
           columns={this.columns}
         />
         />
@@ -709,6 +718,7 @@ export default class extends Page {
       paperFilterList = [],
       paperFilterList = [],
       paperList = [],
       paperList = [],
       paperChecked,
       paperChecked,
+      sentenceInfo = {},
     } = this.state;
     } = this.state;
     const { sentenceTrail } = this.props.user;
     const { sentenceTrail } = this.props.user;
     let maxStep = 0;
     let maxStep = 0;
@@ -729,7 +739,7 @@ export default class extends Page {
         {sentence.code && <div className="sentence-code">CODE: {sentence.code}</div>}
         {sentence.code && <div className="sentence-code">CODE: {sentence.code}</div>}
         {sentenceTrail && (
         {sentenceTrail && (
           <div className="sentence-code">
           <div className="sentence-code">
-            CODE: <Link to="">去获取</Link>
+            CODE: <a href={sentenceInfo.link} target="_blank">去获取</a>
             <a
             <a
               onClick={() => {
               onClick={() => {
                 this.setState({ sentenceModel: true });
                 this.setState({ sentenceModel: true });
@@ -818,7 +828,7 @@ export default class extends Page {
   }
   }
 
 
   renderInputCode() {
   renderInputCode() {
-    const { sentenceError } = this.state;
+    const { sentenceError, sentenceInfo = {} } = this.state;
     return (
     return (
       <Module className="code-module">
       <Module className="code-module">
         <div className="title">输入《千行GMAT长难句》专属 Code,解锁在线练习功能。</div>
         <div className="title">输入《千行GMAT长难句》专属 Code,解锁在线练习功能。</div>
@@ -845,9 +855,9 @@ export default class extends Page {
             什么是CODE?
             什么是CODE?
           </Link>
           </Link>
           <span>没有 CODE?</span>
           <span>没有 CODE?</span>
-          <Link to="/" className="link">
+          <a href={sentenceInfo.link} target="_blank" className="link">
             去获取 >>
             去获取 >>
-          </Link>
+          </a>
           <a
           <a
             onClick={() => {
             onClick={() => {
               this.trailSentence();
               this.trailSentence();

+ 99 - 141
front/project/www/routes/paper/process/base/index.js

@@ -12,7 +12,7 @@ import Calculator from '../../../../components/Calculator';
 import AnswerSelect from '../../../../components/AnswerSelect';
 import AnswerSelect from '../../../../components/AnswerSelect';
 import AnswerTable from '../../../../components/AnswerTable';
 import AnswerTable from '../../../../components/AnswerTable';
 import Editor from '../../../../components/Editor';
 import Editor from '../../../../components/Editor';
-import { QuestionType } from '../../../../../Constant';
+import { QuestionType, ExaminationOrder } from '../../../../../Constant';
 
 
 const QuestionTypeMap = getMap(QuestionType, 'value');
 const QuestionTypeMap = getMap(QuestionType, 'value');
 
 
@@ -262,51 +262,15 @@ export default class extends Component {
   }
   }
 
 
   renderExaminationStart() {
   renderExaminationStart() {
-    const { disorder } = this.state;
+    // const { paper, userQuestion, singleTime, stageTime, flow } = this.props;
+    // const { showTime, showNo } = this.state;
     const { paper, flow } = this.props;
     const { paper, flow } = this.props;
     return (
     return (
-      <div className="start">
-        <div className="bg" />
-        <div className="fixed-content">
-          <div className="title">{paper.title}</div>
-          <div className="desc">
-            <div className="block">
-              <div className="desc-title">
-                <Assets name="subject_icon" />
-                题目总数
-              </div>
-              <div className="desc-info">{paper.questionNumer}</div>
-            </div>
-            <div className="block">
-              <div className="desc-title">
-                <Assets name="time_icon" />
-                建议用时
-              </div>
-              <div className="desc-info">{formatSeconds(paper.time)}</div>
-            </div>
-          </div>
-          <div className="tip">
-            <Checkbox className="m-r-1" checked={disorder} onChange={() => this.setState({ disorder: !disorder })} />
-            题目选项乱序显示
-          </div>
-          <div className="submit">
-            <Button size="lager" radius onClick={() => flow.start({ disorder })}>
-              开始练习
-            </Button>
-          </div>
-        </div>
-      </div>
-    );
-  }
-
-  renderExerciseStart() {
-    const { paper, userQuestion, singleTime, stageTime, flow } = this.props;
-    const { showTime, showNo } = this.state;
-    return (
       <div className="layout">
       <div className="layout">
+        <div className="fixed" />
         <div className="layout-header">
         <div className="layout-header">
           <div className="title">{paper.title}</div>
           <div className="title">{paper.title}</div>
-          <div className="right">
+          {/* <div className="right">
             <div
             <div
               className="block"
               className="block"
               onClick={() => {
               onClick={() => {
@@ -326,9 +290,9 @@ export default class extends Component {
               <Assets name="subjectnumber_icon" />
               <Assets name="subjectnumber_icon" />
               {showNo && `${userQuestion.no} of ${paper.questionNumber}`}
               {showNo && `${userQuestion.no} of ${paper.questionNumber}`}
             </div>
             </div>
-          </div>
+          </div> */}
         </div>
         </div>
-        <div className={'layout-body'}>{this.renderExerciseStartCAT()}</div>
+        <div className={'layout-body'}>{paper.isAdapt > 1 ? this.renderExaminationStartCAT() : this.renderExaminationStartDefault()}</div>
         <div className="layout-footer">
         <div className="layout-footer">
           <div className="help">
           <div className="help">
             <Assets name="help_icon" />
             <Assets name="help_icon" />
@@ -346,7 +310,47 @@ export default class extends Component {
     );
     );
   }
   }
 
 
-  renderExerciseStartDefault() {
+  renderExerciseStart() {
+    const { disorder } = this.state;
+    const { paper, flow } = this.props;
+    return (
+      <div className="start">
+        <div className="bg" />
+        <div className="fixed-content">
+          <div className="title">{paper.title}</div>
+          <div className="desc">
+            <div className="block">
+              <div className="desc-title">
+                <Assets name="subject_icon" />
+                题目总数
+              </div>
+              <div className="desc-info">{paper.questionNumer}</div>
+            </div>
+            <div className="block">
+              <div className="desc-title">
+                <Assets name="time_icon" />
+                建议用时
+              </div>
+              <div className="desc-info">{formatSeconds(paper.time)}</div>
+            </div>
+          </div>
+          {paper.times > 0 && <div className="tip">
+            <Checkbox className="m-r-1" checked={!disorder} onChange={() => this.setState({ disorder: !!disorder })} />
+            题目选项乱序显示
+          </div>}
+          <div className="submit">
+            <Button size="lager" radius onClick={() => flow.start({ disorder: paper.times > 0 ? !disorder : false })}>
+              开始练习
+            </Button>
+          </div>
+        </div>
+      </div>
+    );
+  }
+
+  renderExaminationStartCAT() {
+    const { disorder, order, orderIndex } = this.state;
+    const { paper, flow } = this.props;
     return (
     return (
       <div className="exercise-start default">
       <div className="exercise-start default">
         <div className="title">Section Ordering</div>
         <div className="title">Section Ordering</div>
@@ -361,50 +365,29 @@ export default class extends Component {
           selected, before moving on to the next section. You will NOT be able to return to this screen.
           selected, before moving on to the next section. You will NOT be able to return to this screen.
         </div>
         </div>
         <div className="block-list">
         <div className="block-list">
-          <div className="block-item">
-            <div className="block-title">
-              <div className="block-title-border">
-                <AntDIcon type="check" />
-                <span>ARQV</span>
+          {ExaminationOrder.map((row, index) => {
+            return <div className="block-item">
+              <div className="block-title" onClick={() => {
+                this.setState({ order: row.value, orderIndex: index });
+              }}>
+                <div className="block-title-border">
+                  {orderIndex === index && <AntDIcon type="check" />}
+                  <span>{row.label}</span>
+                </div>
               </div>
               </div>
-            </div>
-            <div className="block-text">1.Analytical Writing Analysis </div>
-            <div className="block-text">2.Integrated Reasoning </div>
-            <div className="block-text">3.Quantitative </div>
-            <div className="block-text">4.Verbal </div>
-          </div>
-          <div className="block-item">
-            <div className="block-title">
-              <div className="block-title-border">
-                <AntDIcon type="check" />
-                <span>VQRA </span>
-              </div>
-            </div>
-            <div className="block-text">1.Verbal </div>
-            <div className="block-text">2.Quantitative </div>
-            <div className="block-text">3.Integrated Reasoning </div>
-            <div className="block-text">4.Analytical Writing Analysis </div>
-          </div>
-          <div className="block-item">
-            <div className="block-title">
-              <div className="block-title-border">
-                <AntDIcon type="check" />
-                <span>QVRA</span>
-              </div>
-            </div>
-            <div className="block-text">1.Quantitative</div>
-            <div className="block-text">2.Verbal </div>
-            <div className="block-text">3.Integrated Reasoning </div>
-            <div className="block-text">4.Analytical Writing Analysis </div>
-          </div>
+              {row.list.map((r, i) => {
+                return <div className="block-text">{i + 1}.{r.label} </div>;
+              })}
+            </div>;
+          })}
         </div>
         </div>
         <div className="bottom">
         <div className="bottom">
-          <div className="text">
-            <Checkbox checked /> 题目选项乱序显示
-          </div>
+          {paper.times > 0 && <div className="text">
+            <Checkbox checked={!disorder} onChange={() => this.setState({ disorder: !!disorder })} /> 题目选项乱序显示
+          </div>}
           <div className="text">
           <div className="text">
             Click{' '}
             Click{' '}
-            <div className="next" onClick={() => this.next()}>
+            <div className="next" onClick={() => flow.start({ disorder: paper.times > 0 ? !disorder : false, order })}>
               Next
               Next
               <Assets name="next_icon" />
               <Assets name="next_icon" />
             </div>{' '}
             </div>{' '}
@@ -415,68 +398,44 @@ export default class extends Component {
     );
     );
   }
   }
 
 
-  renderExerciseStartCAT() {
+  renderExaminationStartDefault() {
+    const { disorder, order, orderIndex } = this.state;
+    const { paper, flow } = this.props;
     return (
     return (
       <div className="exercise-start cat">
       <div className="exercise-start cat">
         <div className="title">Section Ordering</div>
         <div className="title">Section Ordering</div>
         <div className="block-list">
         <div className="block-list">
-          <div className="block-item">
-            <div className="block-item-body active">
-              <AntDIcon type="check" style={{ color: '#fff' }} />
-              <div className="block-text">
-                <Checkbox checked /> Analytical Writing Analysis{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox checked /> Integrated Reasoning{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox checked /> Quantitative{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox checked /> Verbal{' '}
-              </div>
-            </div>
-          </div>
-          <div className="block-item">
-            <div className="block-item-body">
-              <div className="block-text">
-                <Checkbox /> Quantitative
-              </div>
-              <div className="block-text">
-                <Checkbox /> Verbal{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox /> Integrated Reasoning{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox /> Analytical Writing Analysis{' '}
-              </div>
-            </div>
-          </div>
-          <div className="block-item">
-            <div className="block-item-body">
-              <div className="block-text">
-                <Checkbox /> Verbal{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox /> Quantitative{' '}
-              </div>
-              <div className="block-text">
-                <Checkbox /> Integrated Reasoning{' '}
+          {ExaminationOrder.map((row, index) => {
+            return <div className="block-item" onClick={() => {
+              this.setState({ order: row.value, orderIndex: index });
+            }}>
+              <div className={orderIndex === index ? 'block-item-body active' : 'block-item-body'}>
+                {orderIndex === index && <AntDIcon type="check" style={{ color: '#fff' }} />}
+                {row.list.map((r, i) => {
+                  return <div className="block-text" onClick={() => {
+                    if (order.indexOf(r.value) > 0) {
+                      // 取消
+                      order[i] = '';
+                    } else {
+                      // 选中
+                      order[i] = r.value;
+                    }
+                    this.setState({ order });
+                  }}>
+                    <Checkbox checked={orderIndex === index ? order.indexOf(r.value) >= 0 : false} /> {r.label}{' '}
+                  </div>;
+                })}
               </div>
               </div>
-              <div className="block-text">
-                <Checkbox /> Analytical Writing Analysis{' '}
-              </div>
-            </div>
-          </div>
+            </div>;
+          })}
         </div>
         </div>
         <div className="bottom">
         <div className="bottom">
-          <div className="text">
-            <Checkbox checked /> 题目选项乱序显示
-          </div>
+          {paper.times > 0 && <div className="text">
+            <Checkbox checked={!disorder} onChange={() => this.setState({ disorder: !!disorder })} /> 题目选项乱序显示
+          </div>}
           <div className="text">
           <div className="text">
             Click{' '}
             Click{' '}
-            <div className="next" onClick={() => this.next()}>
+            <div className="next" onClick={() => flow.start({ disorder: paper.times > 0 ? !disorder : false, order: order.filter(row => row) })}>
               Next
               Next
               <Assets name="next_icon" />
               <Assets name="next_icon" />
             </div>{' '}
             </div>{' '}
@@ -565,12 +524,11 @@ export default class extends Component {
                 <span className="t-d-l">N</span>o
                 <span className="t-d-l">N</span>o
               </div>
               </div>
             </div>
             </div>
-          ) : (
-            <div className="btn-list">
-              <div className="btn" onClick={() => this.hideModal(true)}>
-                <span className="t-d-l">O</span>k
+          ) : (<div className="btn-list">
+            <div className="btn" onClick={() => this.hideModal(true)}>
+              <span className="t-d-l">O</span>k
               </div>
               </div>
-            </div>
+          </div>
           )}
           )}
         </div>
         </div>
       </div>
       </div>

+ 2 - 2
front/project/www/routes/paper/process/page.js

@@ -291,9 +291,9 @@ export default class extends Page {
     if (!paper.id || !scene) return null;
     if (!paper.id || !scene) return null;
     switch (paper.paperModule) {
     switch (paper.paperModule) {
       case 'sentence':
       case 'sentence':
-        return <Sentence key={userQuestion.id} {...this.state} flow={this} />;
+        return <Sentence key={userQuestion.id} {...this.state} flow={this} mode='process' />;
       default:
       default:
-        return <Base key={userQuestion.id} {...this.state} flow={this} />;
+        return <Base key={userQuestion.id} {...this.state} flow={this} mode='process' />;
     }
     }
   }
   }
 }
 }

+ 109 - 34
front/project/www/routes/paper/process/sentence/index.js

@@ -1,9 +1,10 @@
 import React, { Component } from 'react';
 import React, { Component } from 'react';
 import './index.less';
 import './index.less';
 import Assets from '@src/components/Assets';
 import Assets from '@src/components/Assets';
-import { formatSecond, formatPercent } from '@src/services/Tools';
+import { formatSecond, formatPercent, formatSeconds } from '@src/services/Tools';
 import Icon from '../../../../components/Icon';
 import Icon from '../../../../components/Icon';
 import Button from '../../../../components/Button';
 import Button from '../../../../components/Button';
+import Switch from '../../../../components/Switch';
 import Tabs from '../../../../components/Tabs';
 import Tabs from '../../../../components/Tabs';
 import Progress from '../../../../components/Progress';
 import Progress from '../../../../components/Progress';
 import HardInput from '../../../../components/HardInput';
 import HardInput from '../../../../components/HardInput';
@@ -113,23 +114,78 @@ export default class extends Component {
     return stem;
     return stem;
   }
   }
 
 
+  renderHeader() {
+    const { mode } = this.props;
+    switch (mode) {
+      case 'process':
+        return this.renderProcessHeader();
+      default:
+        return this.renderQuestionHeader();
+    }
+  }
+
+  renderProcessHeader() {
+    const { userQuestion, singleTime, paper, flow } = this.props;
+    return (
+      <div className="layout-header">
+        <div className="left">
+          <div className="title">{paper.title}</div>
+        </div>
+        <div className="right">
+          <div className="text">
+            <Assets name="timecost_icon" />
+            Time cost {formatSecond(userQuestion.userTime || singleTime)}
+          </div>
+          <Icon name="star" active={userQuestion.collect} onClick={() => flow.toggleCollect()} />
+        </div>
+      </div>
+    );
+  }
+
+  renderQuestionHeader() {
+    const { userQuestion, questionNo, paper, flow } = this.props;
+    return (
+      <div className="layout-header">
+        <div className="left">
+          <div className="title">{paper.title}</div>
+        </div>
+        <div className="right">
+          <span className="b">
+            用时:
+            <span
+              dangerouslySetInnerHTML={{
+                __html: formatSeconds(userQuestion.userTime).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2'),
+              }}
+            />
+            {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
+          </span>
+          <span className="b">
+            全站:
+            <span
+              dangerouslySetInnerHTML={{
+                __html: formatSeconds(questionNo.totalTime / questionNo.totalNumber).replace(
+                  /([0-9]+)([msh])/g,
+                  '<span class="s">$1</span>$2',
+                ),
+              }}
+            />
+            {/* 全站:<span className="s">1</span>m<span className="s">39</span>s */}
+          </span>
+          <span className="b">
+            <span className="s">{formatPercent(questionNo.totalCorrect, questionNo.totalNumber)}</span>%
+          </span>
+          <Icon name="star" active={userQuestion.collect} onClick={() => flow.toggleCollect()} />
+        </div>
+      </div>
+    );
+  }
+
   render() {
   render() {
-    const { flow, paper, userQuestion, singleTime } = this.props;
+    const { flow, paper, userQuestion } = this.props;
     return (
     return (
       <div id="paper-process-sentence">
       <div id="paper-process-sentence">
         <div className="layout">
         <div className="layout">
-          <div className="layout-header">
-            <div className="left">
-              <div className="title">{paper.title}</div>
-            </div>
-            <div className="right">
-              <div className="text">
-                <Assets name="timecost_icon" />
-                Time cost {formatSecond(userQuestion.userTime || singleTime)}
-              </div>
-              <Icon name="star" active={userQuestion.collect} onClick={() => flow.toggleCollect()} />
-            </div>
-          </div>
+          {this.renderHeader()}
           {this.renderBody()}
           {this.renderBody()}
           <div className="layout-footer">
           <div className="layout-footer">
             <div className="left">
             <div className="left">
@@ -245,44 +301,63 @@ export default class extends Component {
   }
   }
 
 
   renderAnswer() {
   renderAnswer() {
-    const { analysisTab, question, userQuestion, stem } = this.state;
+    const { mode } = this.props;
+    const { analysisTab, question, userQuestion, stem, showAnswer } = this.state;
     const { userAnswer = {} } = userQuestion;
     const { userAnswer = {} } = userQuestion;
     const { answer } = question;
     const { answer } = question;
     return (
     return (
       <div className="layout-body">
       <div className="layout-body">
-        <div className="title">
-          <Icon name="question" />
-          请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。
-        </div>
+        {mode === 'question' ? (
+          <Switch
+            checked={showAnswer}
+            onChange={value => {
+              this.setState({ showAnswer: value });
+            }}
+          >
+            {showAnswer ? '显示答案' : '关闭答案'}
+          </Switch>
+        ) : (
+          <div className="title">
+            <Icon name="question" />
+            请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。
+          </div>
+        )}
+
         <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} />
         <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} />
         <div className="label">主语</div>
         <div className="label">主语</div>
         <div className="input">
         <div className="input">
-          <HardInput show list={userAnswer.subject || []} answer={answer.subject} />
+          <HardInput show={showAnswer} list={userAnswer.subject || []} answer={answer.subject} />
         </div>
         </div>
         <div className="label">谓语</div>
         <div className="label">谓语</div>
         <div className="input">
         <div className="input">
-          <HardInput show list={userAnswer.predicate || []} answer={answer.predicate} />
+          <HardInput show={showAnswer} list={userAnswer.predicate || []} answer={answer.predicate} />
         </div>
         </div>
         <div className="label">宾语</div>
         <div className="label">宾语</div>
         <div className="input">
         <div className="input">
-          <HardInput show list={userAnswer.object || []} answer={answer.object} />
+          <HardInput show={showAnswer} list={userAnswer.object || []} answer={answer.object} />
         </div>
         </div>
         <div className="select">
         <div className="select">
           <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
           <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
-          <AnswerCheckbox show list={SentenceOption} selected={userAnswer.options} answer={answer.options} />
-        </div>
-        <div className="analysis">
-          <Tabs
-            type="division"
-            active={analysisTab}
-            space={3}
-            tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
-            onChange={key => {
-              this.setState({ analysisTab: key });
-            }}
+          <AnswerCheckbox
+            show={showAnswer}
+            list={SentenceOption}
+            selected={userAnswer.options}
+            answer={answer.options}
           />
           />
-          {this.renderText()}
         </div>
         </div>
+        {showAnswer && (
+          <div className="analysis">
+            <Tabs
+              type="division"
+              active={analysisTab}
+              tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
+              onChange={key => {
+                this.setState({ analysisTab: key });
+              }}
+            />
+            {this.renderText()}
+          </div>
+        )}
       </div>
       </div>
     );
     );
   }
   }

+ 12 - 0
front/project/www/routes/paper/process/sentence/index.less

@@ -41,6 +41,18 @@
             margin-right: 5px;
             margin-right: 5px;
           }
           }
         }
         }
+
+        .b {
+          margin-left: 30px;
+
+          .s {
+            color: #4299FF;
+          }
+        }
+
+        .icon {
+          margin-left: 10px;
+        }
       }
       }
     }
     }
   }
   }

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

@@ -210,51 +210,69 @@ export default class extends Page {
     const { report = {} } = this.state;
     const { report = {} } = this.state;
     switch (report.paperModule) {
     switch (report.paperModule) {
       case 'sentence':
       case 'sentence':
-        return <Sentence {...this.state} flow={this} scene='answer' />;
+        return <Sentence {...this.state} flow={this} scene='answer' mode='question' />;
       default:
       default:
         return <div className='base'>{this.renderBase()}</div>;
         return <div className='base'>{this.renderBase()}</div>;
     }
     }
   }
   }
 
 
-  renderBase() {
-    const { questionStatus, userQuestion = {}, questionNo = {}, paper = {}, showIds, questionNos = [] } = this.state;
+  renderHeader() {
+    const { report = {} } = this.state;
+    switch (report.paperModule) {
+      case 'examination':
+        return this.renderExaminationHeader();
+      default:
+        return this.renderExerciseHeader();
+    }
+  }
+
+  renderExaminationHeader() {
 
 
+  }
+
+  renderExerciseHeader() {
+    const { userQuestion = {}, questionNo = {}, paper = {}, showIds, questionNos = [] } = this.state;
+    return <div className="layout-header">
+      <div className="left">
+        <div className="no">No.{userQuestion.stageNo || userQuestion.no}</div>
+        <div className="title"><Assets name='book' />{paper.title}</div>
+      </div>
+      <div className="center">
+        <div className="menu-wrap">
+          ID:{questionNo.title}
+          {questionNos && questionNos.length > 0 && <Icon name="more" onClick={() => {
+            this.setState({ showIds: true });
+          }} />}
+          {showIds && <div className='menu-content'>
+            <p>题源汇总</p>
+            {(questionNos || []).map((row) => <p>ID:{row.title}</p>)}
+          </div>}
+        </div>
+      </div>
+      <div className="right">
+        <span className="b">
+          用时:<span dangerouslySetInnerHTML={{ __html: formatSeconds(userQuestion.userTime).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2') }} />
+          {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
+        </span>
+        <span className="b">
+          全站:<span dangerouslySetInnerHTML={{ __html: formatSeconds(questionNo.totalTime / questionNo.totalNumber).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2') }} />
+          {/* 全站:<span className="s">1</span>m<span className="s">39</span>s */}
+        </span>
+        <span className="b">
+          <span className="s">{formatPercent(questionNo.totalCorrect, questionNo.totalNumber)}</span>%
+        </span>
+        <Icon name="question" />
+        <Icon name="star" active={userQuestion.collect} onClick={() => this.toggleCollect()} />
+      </div>
+    </div>;
+  }
+
+  renderBase() {
+    const { questionStatus, userQuestion = {}, showIds } = this.state;
     return <div className="layout" onClick={() => {
     return <div className="layout" onClick={() => {
       if (showIds) this.setState({ showIds: false });
       if (showIds) this.setState({ showIds: false });
     }}>
     }}>
-      <div className="layout-header">
-        <div className="left">
-          <div className="no">No.{userQuestion.no}</div>
-          <div className="title"><Assets name='book' />{paper.title}13</div>
-        </div>
-        <div className="center">
-          <div className="menu-wrap">
-            ID:{questionNo.title}
-            {questionNos && questionNos.length > 0 && <Icon name="more" onClick={() => {
-              this.setState({ showIds: true });
-            }} />}
-            {showIds && <div className='menu-content'>
-              <p>题源汇总</p>
-              {(questionNos || []).map((row) => <p>ID:{row.title}</p>)}
-            </div>}
-          </div>
-        </div>
-        <div className="right">
-          <span className="b">
-            用时:<span dangerouslySetInnerHTML={{ __html: formatSeconds(userQuestion.userTime).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2') }} />
-            {/* 用时:<span className="s">1</span>m<span className="s">39</span>s */}
-          </span>
-          <span className="b">
-            全站:<span dangerouslySetInnerHTML={{ __html: formatSeconds(questionNo.totalTime / questionNo.totalNumber).replace(/([0-9]+)([msh])/g, '<span class="s">$1</span>$2') }} />
-            {/* 全站:<span className="s">1</span>m<span className="s">39</span>s */}
-          </span>
-          <span className="b">
-            <span className="s">{formatPercent(questionNo.totalCorrect, questionNo.totalNumber)}</span>%
-          </span>
-          <Icon name="question" />
-          <Icon name="star" active={userQuestion.collect} onClick={() => this.toggleCollect()} />
-        </div>
-      </div>
+      {this.renderHeader()}
       <div className="layout-body">{this.renderBody()}</div>
       <div className="layout-body">{this.renderBody()}</div>
       <div className="layout-footer">
       <div className="layout-footer">
         <div className="left">
         <div className="left">
@@ -276,8 +294,8 @@ export default class extends Page {
           <AnswerButton className="item" onClick={() => this.setState({ feedbackModal: true })}>纠错</AnswerButton>
           <AnswerButton className="item" onClick={() => this.setState({ feedbackModal: true })}>纠错</AnswerButton>
         </div>
         </div>
         <div className="right">
         <div className="right">
-          <Icon name="prev" onClick={() => this.prevQuestion()} />
-          <Icon name="next" onClick={() => this.nextQuestion()} />
+          {userQuestion.no !== 1 && <Icon name="prev" onClick={() => this.prevQuestion()} />}
+          {userQuestion.questionNumber !== userQuestion.no && <Icon name="next" onClick={() => this.nextQuestion()} />}
         </div>
         </div>
       </div>
       </div>
       {this.state.askModal && this.renderAsk()}
       {this.state.askModal && this.renderAsk()}

+ 1 - 0
front/project/www/routes/paper/report/index.js

@@ -3,6 +3,7 @@ export default {
   key: 'paper-report',
   key: 'paper-report',
   title: '报告',
   title: '报告',
   needLogin: true,
   needLogin: true,
+  hideHeader: true,
   component() {
   component() {
     return import('./page');
     return import('./page');
   },
   },

+ 46 - 16
front/project/www/routes/paper/report/page.js

@@ -210,8 +210,13 @@ const pieOption = {
 };
 };
 
 
 export default class extends Page {
 export default class extends Page {
+  initState() {
+    return { report: { paperModule: 'exercise' } };
+  }
+
   initData() {
   initData() {
     const { id } = this.params;
     const { id } = this.params;
+    const { page = '' } = this.state.search;
     Question.detailReport(id).then(result => {
     Question.detailReport(id).then(result => {
       switch (result.paperModule) {
       switch (result.paperModule) {
         case 'sentence':
         case 'sentence':
@@ -230,22 +235,49 @@ export default class extends Page {
       }
       }
       this.setState({ report: result });
       this.setState({ report: result });
     });
     });
+    switch (page) {
+      case 'question':
+        // 题目回顾列表
+        Question.questionReport(id).then(result => {
+          this.setState({ list: result });
+        });
+        break;
+      default:
+        break;
+    }
   }
   }
 
 
   refreshSentence() {
   refreshSentence() {
-
+    const { page = '' } = this.state.search;
+    switch (page) {
+      case 'question':
+        break;
+      default:
+    }
   }
   }
 
 
   refreshTextbook() {
   refreshTextbook() {
-
+    this.refreshExercise();
   }
   }
 
 
   refreshExamination() {
   refreshExamination() {
-
+    const { page = '' } = this.state.search;
+    switch (page) {
+      case 'total':
+        break;
+      case 'question':
+        break;
+      default:
+    }
   }
   }
 
 
   refreshExercise() {
   refreshExercise() {
-
+    const { page = '' } = this.state.search;
+    switch (page) {
+      case 'question':
+        break;
+      default:
+    }
   }
   }
 
 
   renderView() {
   renderView() {
@@ -269,22 +301,20 @@ export default class extends Page {
   }
   }
 
 
   renderTextbook() {
   renderTextbook() {
-    return <div />;
+    return this.renderExercise();
   }
   }
 
 
   renderExercise() {
   renderExercise() {
-    return (
-      <div>
-        <div className="content">
-          <LineChart option={lineOption} />
-          <BarChart option={bar1Option} />
-          <BarChart option={bar2Option} />
-          <BarChart option={bar3Option} />
-          <BarChart option={barOption} />
-          <PieChart option={pieOption} />
-        </div>
+    return <div>
+      <div className="content">
+        <LineChart option={lineOption} />
+        <BarChart option={bar1Option} />
+        <BarChart option={bar2Option} />
+        <BarChart option={bar3Option} />
+        <BarChart option={barOption} />
+        <PieChart option={pieOption} />
       </div>
       </div>
-    );
+    </div>;
   }
   }
 
 
   renderExamination() {
   renderExamination() {

+ 10 - 0
front/project/www/routes/preview/list/index.js

@@ -0,0 +1,10 @@
+export default {
+  path: '/preview/list/:id',
+  key: 'preview',
+  title: '预习作业列表',
+  needLogin: false,
+  tab: 'exercise',
+  component() {
+    return import('./page');
+  },
+};

+ 59 - 0
front/project/www/routes/preview/list/index.less

@@ -0,0 +1,59 @@
+@charset "utf-8";
+
+#exercise-list {
+  .code-module {
+    padding: 80px 250px;
+    text-align: center;
+
+    .title {
+      font-size: 18px;
+      margin-bottom: 24px;
+    }
+
+    .input-block {
+      margin-bottom: 24px;
+
+      .input {
+        width: 350px;
+
+        input {
+          border-top-left-radius: 22px;
+          border-bottom-left-radius: 22px;
+        }
+      }
+
+      .button {
+        width: 150px;
+        border-top-right-radius: 22px;
+        border-bottom-right-radius: 22px;
+      }
+    }
+
+    .tip {
+      .left {
+        float: left;
+      }
+
+      .right {
+        float: right;
+      }
+    }
+  }
+
+  .work-body {
+    .work-nav {
+      margin-bottom: 20px;
+
+      .left {
+        display: inline-block;
+        padding-left: 5px;
+        font-size: 16px;
+        font-weight: 600;
+      }
+
+      .right {
+        float: right;
+      }
+    }
+  }
+}

+ 286 - 0
front/project/www/routes/preview/list/page.js

@@ -0,0 +1,286 @@
+import React from 'react';
+import './index.less';
+import Page from '@src/containers/Page';
+import { asyncConfirm } from '@src/services/AsyncTools';
+import { formatPercent, formatSeconds, formatDate } from '@src/services/Tools';
+import Tabs from '../../../components/Tabs';
+import Module from '../../../components/Module';
+import ListTable from '../../../components/ListTable';
+import ProgressText from '../../../components/ProgressText';
+import IconButton from '../../../components/IconButton';
+import { Main } from '../../../stores/main';
+import { Question } from '../../../stores/question';
+import { QuestionDifficult } from '../../../../Constant';
+
+const LOGIC_NO = 'no';
+const LOGIC_PLACE = 'place';
+const LOGIC_DIFFICULT = 'difficult';
+const LOGIC_ERROR = 'error';
+
+export default class extends Page {
+  initState() {
+    this.columns = [
+      {
+        title: '练习册',
+        width: 250,
+        align: 'left',
+        render: (record) => {
+          let progress = 0;
+          if (record.report) {
+            progress = formatPercent(record.report.userNumber, record.report.questionNumber);
+          }
+          return (
+            <div className="table-row">
+              <div className="night f-s-16">{record.title}</div>
+              <div>
+                <ProgressText progress={progress} size="small" />
+              </div>
+            </div>
+          );
+        },
+      },
+      {
+        title: '正确率',
+        width: 150,
+        align: 'left',
+        render: (record) => {
+          let correct = '--';
+          if (record.report) {
+            correct = formatPercent(record.report.userCorrect, record.report.userNumber, false);
+          }
+          return (
+            <div className="table-row">
+              <div className="night f-s-16 f-w-b">{correct}</div>
+              <div className="f-s-12">全站{formatPercent(record.stat.totalCorrect, record.stat.totalNumber, false)}</div>
+            </div>
+          );
+        },
+      },
+      {
+        title: '全站用时',
+        width: 150,
+        align: 'left',
+        render: (record) => {
+          let time = '--';
+          if (record.paper) {
+            time = formatSeconds(record.paper.report.userTime / record.paper.report.userNumber);
+          }
+          return (
+            <div className="table-row">
+              <div className="night f-s-16 f-w-b">{time}</div>
+              <div className="f-s-12">全站{formatSeconds(record.stat.totalTime / record.stat.totalNumber)}</div>
+            </div>
+          );
+        },
+      },
+      {
+        title: '最近做题',
+        width: 150,
+        align: 'left',
+        render: (record) => {
+          if (!record.report) return null;
+          return (
+            <div className="table-row">
+              <div>{formatDate(record.report.updateTime, 'YYYY-MM-DD')}</div>
+              <div>{formatDate(record.report.updateTime, 'HH:mm')}</div>
+            </div>
+          );
+        },
+      },
+      {
+        title: '操作',
+        width: 180,
+        align: 'left',
+        render: (record) => {
+          return (
+            <div className="table-row p-t-1">
+              {!record.report && <IconButton type="start" tip="Start" onClick={() => {
+                Question.startLink('exercise', record);
+              }} />}
+              {(record.report && !record.report.isFinish) && <IconButton className="m-r-2" type="continue" tip="Continue" onClick={() => {
+                Question.continueLink('exercise', record);
+              }} />}
+              <IconButton type="restart" tip="Restart" onClick={() => {
+                this.restart(record);
+              }} />
+            </div>
+          );
+        },
+      },
+      {
+        title: '报告',
+        width: 30,
+        align: 'right',
+        render: (record) => {
+          if (!record.report || !record.report.isFinish) return null;
+          return (
+            <div className="table-row p-t-1">
+              <IconButton type="report" tip="Report" onClick={() => {
+                Question.reportLink(record);
+              }} />
+            </div>
+          );
+        },
+      },
+    ];
+    this.placeList = [];
+    this.inited = false;
+    return {
+      logic: LOGIC_NO,
+      logicExtend: '',
+      logics: [{
+        key: LOGIC_NO,
+        title: '按顺序练习',
+      }, {
+        key: LOGIC_PLACE,
+        title: '按考点练习',
+      }, {
+        key: LOGIC_DIFFICULT,
+        title: '按难度练习',
+      }, {
+        key: LOGIC_ERROR,
+        title: '按易错度练习',
+      }],
+    };
+  }
+
+  init() {
+    const { id } = this.params;
+    Main.getExerciseParent(id).then(result => {
+      const navs = result;
+      this.inited = true;
+      this.setState({ navs });
+    });
+  }
+
+  initData() {
+    const data = Object.assign(this.state, this.state.search);
+    this.setState(data);
+    this.refreshData();
+  }
+
+  refreshData(newLogic) {
+    const { logic } = this.state;
+    let handler = null;
+    switch (newLogic || logic) {
+      case LOGIC_PLACE:
+        handler = this.refreshPlace();
+        break;
+      case LOGIC_DIFFICULT:
+        handler = this.refreshDifficult();
+        break;
+      default:
+        handler = Promise.resolve();
+    }
+    handler.then(() => {
+      this.refreshExercise();
+    });
+  }
+
+  refreshPlace() {
+    const { id } = this.params;
+    let handler;
+    if (this.placeList.length > 0) {
+      this.setState({ logicExtends: this.placeList });
+      handler = Promise.resolve();
+    } else {
+      handler = Question.getExercisePlace(id).then(result => {
+        this.placeList = result.map(row => {
+          return {
+            name: row,
+            key: row,
+          };
+        });
+        this.setState({ logicExtends: this.placeList });
+      });
+    }
+    return handler.then(() => {
+      let { logicExtend } = this.state;
+      if (logicExtend === '') {
+        logicExtend = this.placeList[0].key;
+        this.setState({ logicExtend });
+      }
+    });
+  }
+
+  refreshDifficult() {
+    let { logicExtend } = this.state;
+    this.setState({
+      logicExtends: QuestionDifficult.map(difficult => {
+        difficult.name = difficult.label;
+        difficult.key = difficult.value;
+        return difficult;
+      }),
+    });
+    return Promise.resolve().then(() => {
+      if (logicExtend === '') {
+        logicExtend = QuestionDifficult[0].key;
+        this.setState({ logicExtend });
+      }
+    });
+  }
+
+  refreshExercise() {
+    const { logic, logicExtend } = this.state;
+    Question.getExerciseList(Object.assign({ structId: this.params.id, logic, logicExtend }, this.state.search))
+      .then((result) => {
+        this.setState({ list: result.list, total: result.total });
+      });
+  }
+
+  onChangeTab(key, value) {
+    const { logic } = this.state;
+    const data = {};
+    if (key === 'logicExtend') {
+      data.logic = logic;
+      data.logicExtend = value;
+    } else {
+      data.logic = value;
+    }
+    // this.refreshData(tab);
+    this.refreshQuery(data);
+  }
+
+  restart(item) {
+    asyncConfirm('提示', '是否重置', () => {
+      Question.restart(item.paper.id).then(() => {
+        this.refresh();
+      });
+    });
+  }
+
+  renderView() {
+    const { logic, logicExtend, logics = [], logicExtends = [], list } = this.state;
+    return (
+      <div>
+        <div className="content">
+          <Module className="m-t-2">
+            <Tabs
+              active={logic}
+              border
+              width="180px"
+              space="0"
+              tabs={logics}
+              onChange={(key) => {
+                this.onChangeTab('logic', key);
+              }}
+            />
+            {logicExtends.length > 0 && <Tabs
+              active={logicExtend}
+              type="text"
+              tabs={logicExtends}
+              onChange={(key) => {
+                this.onChangeTab('logicExtend', key);
+              }}
+            />}
+          </Module>
+
+          <ListTable
+            data={list}
+            columns={this.columns}
+          />
+        </div>
+      </div>
+    );
+  }
+}

+ 0 - 10
front/project/www/routes/sentence/process/index.js

@@ -1,10 +0,0 @@
-export default {
-  path: '/sentence/process/:id',
-  key: 'sentence-process',
-  title: '长难句',
-  needLogin: true,
-  hideHeader: true,
-  component() {
-    return import('./page');
-  },
-};

+ 0 - 0
front/project/www/routes/sentence/process/page.js


+ 29 - 26
front/project/www/routes/sentence/read/page.js

@@ -6,6 +6,8 @@ import Icon from '../../../components/Icon';
 import Progress from '../../../components/Progress';
 import Progress from '../../../components/Progress';
 import Assets from '../../../../../src/components/Assets';
 import Assets from '../../../../../src/components/Assets';
 import { Sentence } from '../../../stores/sentence';
 import { Sentence } from '../../../stores/sentence';
+import { Main } from '../../../stores/main';
+import { formatMoney } from '../../../../../src/services/Tools';
 
 
 export default class extends Page {
 export default class extends Page {
   constructor(props) {
   constructor(props) {
@@ -40,6 +42,9 @@ export default class extends Page {
       }
       }
       this.jumpPage(page);
       this.jumpPage(page);
     });
     });
+    Main.getSentence().then(result => {
+      this.setState({ info: result });
+    });
   }
   }
 
 
   refreshSentence() {
   refreshSentence() {
@@ -204,7 +209,7 @@ export default class extends Page {
   }
   }
 
 
   renderBody() {
   renderBody() {
-    const { showMenu, article, index, chapterMap = {} } = this.state;
+    const { showMenu, article, index, chapterMap = {}, info = {} } = this.state;
     return article ? (
     return article ? (
       <div className="layout-body">
       <div className="layout-body">
         <div className="crumb">千行长难句解析 >> {(chapterMap[article.chapter] || {}).title}</div>
         <div className="crumb">千行长难句解析 >> {(chapterMap[article.chapter] || {}).title}</div>
@@ -214,20 +219,20 @@ export default class extends Page {
         </div>
         </div>
         {showMenu && this.renderMenu()}
         {showMenu && this.renderMenu()}
       </div>
       </div>
-    ) : (
-      <div className="layout-body">
-        <div className="free-over">
-          <div className="free-over-title">试读已结束,购买后可继续阅读。</div>
-          <div className="free-over-btn">¥ 20.00 | 立即购买</div>
-          <div className="free-over-desc">
-            <div className="free-over-desc-title">张小爱笑笑笑 2019-07-13</div>
-            <div className="free-over-desc-content">
-              韩瑞祥/文 移民文学(Migrations
-              literatur)成为当今德国文坛上一个备受关注的文学现象,一批又一批脱颖而出的移民文学作家为当今德国文学的发展不断地
-            </div>
+    ) : (<div className="layout-body">
+      <div className="free-over">
+        <div className="free-over-title">试读已结束,购买后可继续阅读。</div>
+        <div className="free-over-btn" onClick={() => {
+          window.location.href = info.link;
+        }}>{formatMoney(info.price)} | 立即购买</div>
+        <div className="free-over-desc">
+          <div className="free-over-desc-title">{info.title}</div>
+          <div className="free-over-desc-content">
+            {info.description}
           </div>
           </div>
         </div>
         </div>
       </div>
       </div>
+    </div>
     );
     );
   }
   }
 
 
@@ -264,13 +269,12 @@ export default class extends Page {
                 {chapter.title}
                 {chapter.title}
                 <div className="page">{chapter.startPage}</div>
                 <div className="page">{chapter.startPage}</div>
               </div>
               </div>
-            ) : (
-              <Tooltip title={message}>
-                <div className={'chapter-item trail'}>
-                  {chapter.title}
-                  <div className="page">{chapter.startPage}</div>
-                </div>
-              </Tooltip>
+            ) : (<Tooltip title={message}>
+              <div className={'chapter-item trail'}>
+                {chapter.title}
+                <div className="page">{chapter.startPage}</div>
+              </div>
+            </Tooltip>
             );
             );
             const list = [_item];
             const list = [_item];
             if (chapter.value) {
             if (chapter.value) {
@@ -287,13 +291,12 @@ export default class extends Page {
                     {article.title}
                     {article.title}
                     <div className="page">{article.startPage}</div>
                     <div className="page">{article.startPage}</div>
                   </div>
                   </div>
-                ) : (
-                  <Tooltip title={message}>
-                    <div className={'part-item trail'}>
-                      {article.title}
-                      <div className="page">{article.startPage}</div>
-                    </div>
-                  </Tooltip>
+                ) : (<Tooltip title={message}>
+                  <div className={'part-item trail'}>
+                    {article.title}
+                    <div className="page">{article.startPage}</div>
+                  </div>
+                </Tooltip>
                 );
                 );
                 list.push(item);
                 list.push(item);
               });
               });

+ 10 - 2
front/project/www/stores/course.js

@@ -4,8 +4,16 @@ export default class CourseStore extends BaseStore {
   /**
   /**
    * 获取课程进度
    * 获取课程进度
    */
    */
-  classProgress() {
-    return this.apiGet('/course/progress');
+  progress(courseModules, structId) {
+    return this.apiGet('/course/progress', { courseModules, structId });
+  }
+
+  /**
+   * 获取预习作业列表
+   * @param {*} param0
+   */
+  listPreview({ page, size, isFinish, endTime }) {
+    return this.apiGet('/course/preview', { page, size, isFinish, endTime });
   }
   }
 }
 }
 
 

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

@@ -24,6 +24,20 @@ export default class MainStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取长难句信息
+   */
+  getSentence() {
+    return this.apiGet('/base/sentence');
+  }
+
+  /**
+   * 获取心经信息
+   */
+  getExperience() {
+    return this.apiGet('/base/experience');
+  }
+
+  /**
    * 获取考分排行信息
    * 获取考分排行信息
    */
    */
   getScore(total, quant) {
   getScore(total, quant) {

+ 15 - 3
front/project/www/stores/question.js

@@ -2,15 +2,19 @@ import BaseStore from '@src/stores/base';
 
 
 export default class QuestionStore extends BaseStore {
 export default class QuestionStore extends BaseStore {
   startLink(type, item) {
   startLink(type, item) {
-    linkTo(`/paper/process/${type}/${item.id}`);
+    openLink(`/paper/process/${type}/${item.id}`);
   }
   }
 
 
   continueLink(type, item) {
   continueLink(type, item) {
-    linkTo(`/paper/process/${type}/${item.id}?r=${item.report.id}`);
+    // const w = window.open('about:blank');
+    // w.location.href = `/paper/process/${type}/${item.id}?r=${item.report.id}`;
+    openLink(`/paper/process/${type}/${item.id}?r=${item.report.id}`);
   }
   }
 
 
   reportLink(item) {
   reportLink(item) {
-    linkTo(`/paper/report/${item.report.id}`);
+    // const w = window.open('about:blank');
+    // w.location.href = `/paper/report/${item.report.id}`;
+    openLink(`/paper/report/${item.report.id}`);
   }
   }
 
 
   /**
   /**
@@ -135,6 +139,14 @@ export default class QuestionStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取做题题目记录
+   * @param {*} userReportId
+   */
+  questionReport(userReportId) {
+    return this.apiGet('/question/report/detail', { userReportId });
+  }
+
+  /**
    * 开始考试
    * 开始考试
    * @param {*} type
    * @param {*} type
    * @param {*} paperId
    * @param {*} paperId

+ 25 - 23
front/project/www/stores/user.js

@@ -27,20 +27,28 @@ export default class UserStore extends BaseStore {
   }
   }
 
 
   needLogin() {
   needLogin() {
-    // if (this.state.login) {
-    //   return Promise.resolve();
-    // }
-    return new Promise(resolve => {
-      this.loginCB = resolve;
+    if (this.state.login) {
+      return Promise.resolve();
+    }
+    return new Promise((resolve, reject) => {
+      this.successCB = resolve;
+      this.failCB = reject;
       this.setState({ needLogin: true });
       this.setState({ needLogin: true });
     });
     });
   }
   }
 
 
-  closeLogin() {
-    this.setState({ needLogin: false });
+  closeLogin(err) {
+    this.setState({ needLogin: !!err });
+    if (err) {
+      if (this.failCB) this.failCB();
+    } else if (this.loginCB) this.loginCB();
     this.loginCB = null;
     this.loginCB = null;
+    this.failCB = null;
   }
   }
 
 
+  /**
+   * 验证token
+   */
   refreshToken() {
   refreshToken() {
     return this.apiPost('/auth/token')
     return this.apiPost('/auth/token')
       .then(result => {
       .then(result => {
@@ -54,8 +62,6 @@ export default class UserStore extends BaseStore {
   infoHandle(result) {
   infoHandle(result) {
     if (result.token) this.setToken(result.token);
     if (result.token) this.setToken(result.token);
     this.setState({ login: true, needLogin: false, info: result, username: result.username });
     this.setState({ login: true, needLogin: false, info: result, username: result.username });
-    if (this.loginCB) this.loginCB();
-    this.loginCB = null;
   }
   }
 
 
   originInviteCode(inviteCode) {
   originInviteCode(inviteCode) {
@@ -79,35 +85,31 @@ export default class UserStore extends BaseStore {
   }
   }
 
 
   /**
   /**
-   * 验证token
-   */
-  token() {
-    return this.apiPost('/auth/token');
-  }
-
-  /**
    * 登陆
    * 登陆
    * @param {*} mobile 手机号
    * @param {*} mobile 手机号
    * @param {*} mobileVerifyCode 手机验证码
    * @param {*} mobileVerifyCode 手机验证码
    * @param {*} inviteCode 邀请人手机/邀请码
    * @param {*} inviteCode 邀请人手机/邀请码
    */
    */
-  login(mobile, mobileVerifyCode, inviteCode) {
+  login(area, mobile, mobileVerifyCode, inviteCode) {
     if (!inviteCode) {
     if (!inviteCode) {
       ({ inviteCode } = this.state);
       ({ inviteCode } = this.state);
     }
     }
-    return this.apiPost('/auth/login', { mobile, mobileVerifyCode, inviteCode });
+    return this.apiPost('/auth/login', { area, mobile, mobileVerifyCode, inviteCode }).then(result => {
+      this.infoHandle(result);
+      return result;
+    });
   }
   }
 
 
   loginWechat(code) {
   loginWechat(code) {
-    return this.apiGet('/auth/wechat_pc', { code }).then(() => {
-      this.setState({ login: true });
+    return this.apiGet('/auth/wechat_pc', { code }).then(result => {
+      this.infoHandle(result);
+      return result;
     });
     });
   }
   }
 
 
   /**
   /**
    * 登出
    * 登出
    */
    */
-
   logout(login = true) {
   logout(login = true) {
     return Promise.resolve()
     return Promise.resolve()
       .then(() => {
       .then(() => {
@@ -130,8 +132,8 @@ export default class UserStore extends BaseStore {
    * @param {*} mobileVerifyCode 手机验证码
    * @param {*} mobileVerifyCode 手机验证码
    * @param {*} inviteCode 邀请人手机/邀请码
    * @param {*} inviteCode 邀请人手机/邀请码
    */
    */
-  bind(mobile, mobileVerifyCode, inviteCode) {
-    return this.apiPost('/auth/bind', { mobile, mobileVerifyCode, inviteCode });
+  bind(area, mobile, mobileVerifyCode, inviteCode) {
+    return this.apiPost('/auth/bind', { area, mobile, mobileVerifyCode, inviteCode });
   }
   }
 
 
   /**
   /**

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

@@ -3,7 +3,7 @@ package com.qxgmat.data.constants.enums;
 public enum ServiceKey {
 public enum ServiceKey {
     VIP("vip", 0, 0), // 收藏和错题处的组卷、导出;笔记导出功能;部分解析只有VIP可以看;下载模考报告; 解锁完整版模考报告;“提问开放”期间有提问权限
     VIP("vip", 0, 0), // 收藏和错题处的组卷、导出;笔记导出功能;部分解析只有VIP可以看;下载模考报告; 解锁完整版模考报告;“提问开放”期间有提问权限
     TEXTBOOK("textbook", 180, 30),
     TEXTBOOK("textbook", 180, 30),
-    QX_CAT("qx_cat", 180, 0), // 可以考2次
+    QX_CAT("qx_cat", 180, 180), // 可以考2次
 
 
     ;
     ;
     public String key;
     public String key;

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

@@ -28,6 +28,8 @@ public enum SettingKey {
     COURSE_INDEX("course_index"), // 课程首页设置
     COURSE_INDEX("course_index"), // 课程首页设置
     PROMOTE("course_promote"), // 促销
     PROMOTE("course_promote"), // 促销
     EXPERIENCE_INFO("experience_info"), // 心经信息
     EXPERIENCE_INFO("experience_info"), // 心经信息
+    SENTENCE_INFO("sentence_info"), // 长难句信息
+    WECHAT_INFO("wechat_info"), // 微信公众号信息
 
 
     TIPS("tips"); // 页面提示信息
     TIPS("tips"); // 页面提示信息
 
 

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

@@ -1,5 +1,7 @@
 package com.qxgmat.data.constants.enums.logic;
 package com.qxgmat.data.constants.enums.logic;
 
 
+import com.qxgmat.data.constants.enums.QuestionType;
+
 public enum TextbookLogic {
 public enum TextbookLogic {
     DS("ds"), PS("ps"), DS_PS("ds+ps");
     DS("ds"), PS("ps"), DS_PS("ds+ps");
     public String key;
     public String key;
@@ -11,4 +13,19 @@ public enum TextbookLogic {
         if (name == null) return null;
         if (name == null) return null;
         return TextbookLogic.valueOf(name.toUpperCase());
         return TextbookLogic.valueOf(name.toUpperCase());
     }
     }
+
+    public static TextbookLogic[] all(){
+        return new TextbookLogic[]{DS, PS, DS_PS};
+    }
+
+    public boolean contain(QuestionType questionType){
+        switch(this){
+            case DS:
+                return questionType == QuestionType.DS;
+            case PS:
+                return questionType == QuestionType.PS;
+            default:
+                return questionType == QuestionType.DS || questionType == QuestionType.PS;
+        }
+    }
 }
 }

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

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

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

@@ -105,14 +105,14 @@ public class Course implements Serializable {
     /**
     /**
      * 1v1课时有效天数
      * 1v1课时有效天数
      */
      */
-    @Column(name = "`expire_days`")
-    private Integer expireDays;
+    @Column(name = "`expire_pre_days`")
+    private Integer expirePreDays;
 
 
     /**
     /**
      * 视频课程开通有效时长
      * 视频课程开通有效时长
      */
      */
-    @Column(name = "`expire_time`")
-    private Integer expireTime;
+    @Column(name = "`expire_days`")
+    private Integer expireDays;
 
 
     /**
     /**
      * 使用有效时长
      * 使用有效时长
@@ -505,37 +505,37 @@ public class Course implements Serializable {
     /**
     /**
      * 获取1v1课时有效天数
      * 获取1v1课时有效天数
      *
      *
-     * @return expire_days - 1v1课时有效天数
+     * @return expire_pre_days - 1v1课时有效天数
      */
      */
-    public Integer getExpireDays() {
-        return expireDays;
+    public Integer getExpirePreDays() {
+        return expirePreDays;
     }
     }
 
 
     /**
     /**
      * 设置1v1课时有效天数
      * 设置1v1课时有效天数
      *
      *
-     * @param expireDays 1v1课时有效天数
+     * @param expirePreDays 1v1课时有效天数
      */
      */
-    public void setExpireDays(Integer expireDays) {
-        this.expireDays = expireDays;
+    public void setExpirePreDays(Integer expirePreDays) {
+        this.expirePreDays = expirePreDays;
     }
     }
 
 
     /**
     /**
      * 获取视频课程开通有效时长
      * 获取视频课程开通有效时长
      *
      *
-     * @return expire_time - 视频课程开通有效时长
+     * @return expire_days - 视频课程开通有效时长
      */
      */
-    public Integer getExpireTime() {
-        return expireTime;
+    public Integer getExpireDays() {
+        return expireDays;
     }
     }
 
 
     /**
     /**
      * 设置视频课程开通有效时长
      * 设置视频课程开通有效时长
      *
      *
-     * @param expireTime 视频课程开通有效时长
+     * @param expireDays 视频课程开通有效时长
      */
      */
-    public void setExpireTime(Integer expireTime) {
-        this.expireTime = expireTime;
+    public void setExpireDays(Integer expireDays) {
+        this.expireDays = expireDays;
     }
     }
 
 
     /**
     /**
@@ -876,8 +876,8 @@ public class Course implements Serializable {
         sb.append(", cover=").append(cover);
         sb.append(", cover=").append(cover);
         sb.append(", minNumber=").append(minNumber);
         sb.append(", minNumber=").append(minNumber);
         sb.append(", maxNumber=").append(maxNumber);
         sb.append(", maxNumber=").append(maxNumber);
+        sb.append(", expirePreDays=").append(expirePreDays);
         sb.append(", expireDays=").append(expireDays);
         sb.append(", expireDays=").append(expireDays);
-        sb.append(", expireTime=").append(expireTime);
         sb.append(", useExpireTime=").append(useExpireTime);
         sb.append(", useExpireTime=").append(useExpireTime);
         sb.append(", wechatAvatar=").append(wechatAvatar);
         sb.append(", wechatAvatar=").append(wechatAvatar);
         sb.append(", trailNumber=").append(trailNumber);
         sb.append(", trailNumber=").append(trailNumber);
@@ -1092,20 +1092,20 @@ public class Course implements Serializable {
         /**
         /**
          * 设置1v1课时有效天数
          * 设置1v1课时有效天数
          *
          *
-         * @param expireDays 1v1课时有效天数
+         * @param expirePreDays 1v1课时有效天数
          */
          */
-        public Builder expireDays(Integer expireDays) {
-            obj.setExpireDays(expireDays);
+        public Builder expirePreDays(Integer expirePreDays) {
+            obj.setExpirePreDays(expirePreDays);
             return this;
             return this;
         }
         }
 
 
         /**
         /**
          * 设置视频课程开通有效时长
          * 设置视频课程开通有效时长
          *
          *
-         * @param expireTime 视频课程开通有效时长
+         * @param expireDays 视频课程开通有效时长
          */
          */
-        public Builder expireTime(Integer expireTime) {
-            obj.setExpireTime(expireTime);
+        public Builder expireDays(Integer expireDays) {
+            obj.setExpireDays(expireDays);
             return this;
             return this;
         }
         }
 
 

+ 0 - 195
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentOnline.java

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

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

@@ -23,7 +23,7 @@ public class ExaminationPaper implements Serializable {
     private Integer structThree;
     private Integer structThree;
 
 
     /**
     /**
-     * 是否适应难度
+     * 是否适应难度: 0非适应性,1适应性,2千行
      */
      */
     @Column(name = "`is_adapt`")
     @Column(name = "`is_adapt`")
     private Integer isAdapt;
     private Integer isAdapt;
@@ -123,18 +123,18 @@ public class ExaminationPaper implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取是否适应难度
+     * 获取是否适应难度: 0非适应性,1适应性,2千行
      *
      *
-     * @return is_adapt - 是否适应难度
+     * @return is_adapt - 是否适应难度: 0非适应性,1适应性,2千行
      */
      */
     public Integer getIsAdapt() {
     public Integer getIsAdapt() {
         return isAdapt;
         return isAdapt;
     }
     }
 
 
     /**
     /**
-     * 设置是否适应难度
+     * 设置是否适应难度: 0非适应性,1适应性,2千行
      *
      *
-     * @param isAdapt 是否适应难度
+     * @param isAdapt 是否适应难度: 0非适应性,1适应性,2千行
      */
      */
     public void setIsAdapt(Integer isAdapt) {
     public void setIsAdapt(Integer isAdapt) {
         this.isAdapt = isAdapt;
         this.isAdapt = isAdapt;
@@ -327,9 +327,9 @@ public class ExaminationPaper implements Serializable {
         }
         }
 
 
         /**
         /**
-         * 设置是否适应难度
+         * 设置是否适应难度: 0非适应性,1适应性,2千行
          *
          *
-         * @param isAdapt 是否适应难度
+         * @param isAdapt 是否适应难度: 0非适应性,1适应性,2千行
          */
          */
         public Builder isAdapt(Integer isAdapt) {
         public Builder isAdapt(Integer isAdapt) {
             obj.setIsAdapt(isAdapt);
             obj.setIsAdapt(isAdapt);

+ 92 - 22
server/data/src/main/java/com/qxgmat/data/dao/entity/TextbookLibraryHistory.java

@@ -57,10 +57,22 @@ public class TextbookLibraryHistory implements Serializable {
     private Date createTime;
     private Date createTime;
 
 
     /**
     /**
-     * 更新日志
+     * 数学更新日志
      */
      */
-    @Column(name = "`content`")
-    private String content;
+    @Column(name = "`quant_contennt`")
+    private String quantContennt;
+
+    /**
+     * 阅读更新日志
+     */
+    @Column(name = "`rc_content`")
+    private String rcContent;
+
+    /**
+     * 综合推理更新日志
+     */
+    @Column(name = "`ir_content`")
+    private String irContent;
 
 
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
@@ -219,21 +231,57 @@ public class TextbookLibraryHistory implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取更新日志
+     * 获取数学更新日志
+     *
+     * @return quant_contennt - 数学更新日志
+     */
+    public String getQuantContennt() {
+        return quantContennt;
+    }
+
+    /**
+     * 设置数学更新日志
+     *
+     * @param quantContennt 数学更新日志
+     */
+    public void setQuantContennt(String quantContennt) {
+        this.quantContennt = quantContennt;
+    }
+
+    /**
+     * 获取阅读更新日志
+     *
+     * @return rc_content - 阅读更新日志
+     */
+    public String getRcContent() {
+        return rcContent;
+    }
+
+    /**
+     * 设置阅读更新日志
+     *
+     * @param rcContent 阅读更新日志
+     */
+    public void setRcContent(String rcContent) {
+        this.rcContent = rcContent;
+    }
+
+    /**
+     * 获取综合推理更新日志
      *
      *
-     * @return content - 更新日志
+     * @return ir_content - 综合推理更新日志
      */
      */
-    public String getContent() {
-        return content;
+    public String getIrContent() {
+        return irContent;
     }
     }
 
 
     /**
     /**
-     * 设置更新日志
+     * 设置综合推理更新日志
      *
      *
-     * @param content 更新日志
+     * @param irContent 综合推理更新日志
      */
      */
-    public void setContent(String content) {
-        this.content = content;
+    public void setIrContent(String irContent) {
+        this.irContent = irContent;
     }
     }
 
 
     @Override
     @Override
@@ -251,7 +299,9 @@ public class TextbookLibraryHistory implements Serializable {
         sb.append(", ir=").append(ir);
         sb.append(", ir=").append(ir);
         sb.append(", irVersion=").append(irVersion);
         sb.append(", irVersion=").append(irVersion);
         sb.append(", createTime=").append(createTime);
         sb.append(", createTime=").append(createTime);
-        sb.append(", content=").append(content);
+        sb.append(", quantContennt=").append(quantContennt);
+        sb.append(", rcContent=").append(rcContent);
+        sb.append(", irContent=").append(irContent);
         sb.append("]");
         sb.append("]");
         return sb.toString();
         return sb.toString();
     }
     }
@@ -296,6 +346,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置数学更新日志
+         *
+         * @param quantContennt 数学更新日志
+         */
+        public Builder quantContennt(String quantContennt) {
+            obj.setQuantContennt(quantContennt);
+            return this;
+        }
+
+        /**
          * 设置数学版本
          * 设置数学版本
          *
          *
          * @param quantVersion 数学版本
          * @param quantVersion 数学版本
@@ -316,6 +376,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置阅读更新日志
+         *
+         * @param rcContent 阅读更新日志
+         */
+        public Builder rcContent(String rcContent) {
+            obj.setRcContent(rcContent);
+            return this;
+        }
+
+        /**
          * 设置阅读版本
          * 设置阅读版本
          *
          *
          * @param rcVersion 阅读版本
          * @param rcVersion 阅读版本
@@ -336,6 +406,16 @@ public class TextbookLibraryHistory implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置综合推理更新日志
+         *
+         * @param irContent 综合推理更新日志
+         */
+        public Builder irContent(String irContent) {
+            obj.setIrContent(irContent);
+            return this;
+        }
+
+        /**
          * 设置综合推理版本
          * 设置综合推理版本
          *
          *
          * @param irVersion 综合推理版本
          * @param irVersion 综合推理版本
@@ -353,16 +433,6 @@ public class TextbookLibraryHistory implements Serializable {
             return this;
             return this;
         }
         }
 
 
-        /**
-         * 设置更新日志
-         *
-         * @param content 更新日志
-         */
-        public Builder content(String content) {
-            obj.setContent(content);
-            return this;
-        }
-
         public TextbookLibraryHistory build() {
         public TextbookLibraryHistory build() {
             return this.obj;
             return this.obj;
         }
         }

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

@@ -12,12 +12,6 @@ public class TextbookPaper implements Serializable {
     private Integer id;
     private Integer id;
 
 
     /**
     /**
-     * 所属时间
-     */
-    @Column(name = "`time`")
-    private String time;
-
-    /**
      * 标题
      * 标题
      */
      */
     @Column(name = "`title`")
     @Column(name = "`title`")
@@ -59,6 +53,12 @@ public class TextbookPaper implements Serializable {
     @Column(name = "`status`")
     @Column(name = "`status`")
     private Integer status;
     private Integer status;
 
 
+    /**
+     * 所属年份
+     */
+    @Column(name = "`year`")
+    private String year;
+
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     /**
     /**
@@ -76,24 +76,6 @@ public class TextbookPaper implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取所属时间
-     *
-     * @return time - 所属时间
-     */
-    public String getTime() {
-        return time;
-    }
-
-    /**
-     * 设置所属时间
-     *
-     * @param time 所属时间
-     */
-    public void setTime(String time) {
-        this.time = time;
-    }
-
-    /**
      * 获取标题
      * 获取标题
      *
      *
      * @return title - 标题
      * @return title - 标题
@@ -229,6 +211,24 @@ public class TextbookPaper implements Serializable {
         this.status = status;
         this.status = status;
     }
     }
 
 
+    /**
+     * 获取所属年份
+     *
+     * @return year - 所属年份
+     */
+    public String getYear() {
+        return year;
+    }
+
+    /**
+     * 设置所属年份
+     *
+     * @param year 所属年份
+     */
+    public void setYear(String year) {
+        this.year = year;
+    }
+
     @Override
     @Override
     public String toString() {
     public String toString() {
         StringBuilder sb = new StringBuilder();
         StringBuilder sb = new StringBuilder();
@@ -236,7 +236,6 @@ public class TextbookPaper implements Serializable {
         sb.append(" [");
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
-        sb.append(", time=").append(time);
         sb.append(", title=").append(title);
         sb.append(", title=").append(title);
         sb.append(", logic=").append(logic);
         sb.append(", logic=").append(logic);
         sb.append(", no=").append(no);
         sb.append(", no=").append(no);
@@ -245,6 +244,7 @@ public class TextbookPaper implements Serializable {
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", createTime=").append(createTime);
         sb.append(", createTime=").append(createTime);
         sb.append(", status=").append(status);
         sb.append(", status=").append(status);
+        sb.append(", year=").append(year);
         sb.append("]");
         sb.append("]");
         return sb.toString();
         return sb.toString();
     }
     }
@@ -269,16 +269,6 @@ public class TextbookPaper implements Serializable {
         }
         }
 
 
         /**
         /**
-         * 设置所属时间
-         *
-         * @param time 所属时间
-         */
-        public Builder time(String time) {
-            obj.setTime(time);
-            return this;
-        }
-
-        /**
          * 设置标题
          * 设置标题
          *
          *
          * @param title 标题
          * @param title 标题
@@ -354,6 +344,16 @@ public class TextbookPaper implements Serializable {
             return this;
             return this;
         }
         }
 
 
+        /**
+         * 设置所属年份
+         *
+         * @param year 所属年份
+         */
+        public Builder year(String year) {
+            obj.setYear(year);
+            return this;
+        }
+
         public TextbookPaper build() {
         public TextbookPaper build() {
             return this.obj;
             return this.obj;
         }
         }

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

@@ -53,10 +53,10 @@ public class TextbookQuestion implements Serializable {
     private Integer totalCorrect;
     private Integer totalCorrect;
 
 
     /**
     /**
-     * 所属时间
+     * 所属年份
      */
      */
-    @Column(name = "`time`")
-    private String time;
+    @Column(name = "`year`")
+    private String year;
 
 
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
@@ -201,21 +201,21 @@ public class TextbookQuestion implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取所属时间
+     * 获取所属年份
      *
      *
-     * @return time - 所属时间
+     * @return year - 所属年份
      */
      */
-    public String getTime() {
-        return time;
+    public String getYear() {
+        return year;
     }
     }
 
 
     /**
     /**
-     * 设置所属时间
+     * 设置所属年份
      *
      *
-     * @param time 所属时间
+     * @param year 所属年份
      */
      */
-    public void setTime(String time) {
-        this.time = time;
+    public void setYear(String year) {
+        this.year = year;
     }
     }
 
 
     @Override
     @Override
@@ -232,7 +232,7 @@ public class TextbookQuestion implements Serializable {
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalTime=").append(totalTime);
         sb.append(", totalNumber=").append(totalNumber);
         sb.append(", totalNumber=").append(totalNumber);
         sb.append(", totalCorrect=").append(totalCorrect);
         sb.append(", totalCorrect=").append(totalCorrect);
-        sb.append(", time=").append(time);
+        sb.append(", year=").append(year);
         sb.append("]");
         sb.append("]");
         return sb.toString();
         return sb.toString();
     }
     }
@@ -327,12 +327,12 @@ public class TextbookQuestion implements Serializable {
         }
         }
 
 
         /**
         /**
-         * 设置所属时间
+         * 设置所属年份
          *
          *
-         * @param time 所属时间
+         * @param year 所属年份
          */
          */
-        public Builder time(String time) {
-            obj.setTime(time);
+        public Builder year(String year) {
+            obj.setYear(year);
             return this;
             return this;
         }
         }
 
 

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

@@ -78,6 +78,12 @@ public class UserOrderRecord implements Serializable {
     private Integer vsNo;
     private Integer vsNo;
 
 
     /**
     /**
+     * 小班课时间段
+     */
+    @Column(name = "`time_id`")
+    private Integer timeId;
+
+    /**
      * 回复时长
      * 回复时长
      */
      */
     @Column(name = "`ask_time`")
     @Column(name = "`ask_time`")
@@ -379,6 +385,24 @@ public class UserOrderRecord implements Serializable {
     }
     }
 
 
     /**
     /**
+     * 获取小班课时间段
+     *
+     * @return time_id - 小班课时间段
+     */
+    public Integer getTimeId() {
+        return timeId;
+    }
+
+    /**
+     * 设置小班课时间段
+     *
+     * @param timeId 小班课时间段
+     */
+    public void setTimeId(Integer timeId) {
+        this.timeId = timeId;
+    }
+
+    /**
      * 获取回复时长
      * 获取回复时长
      *
      *
      * @return ask_time - 回复时长
      * @return ask_time - 回复时长
@@ -662,6 +686,7 @@ public class UserOrderRecord implements Serializable {
         sb.append(", teacherId=").append(teacherId);
         sb.append(", teacherId=").append(teacherId);
         sb.append(", number=").append(number);
         sb.append(", number=").append(number);
         sb.append(", vsNo=").append(vsNo);
         sb.append(", vsNo=").append(vsNo);
+        sb.append(", timeId=").append(timeId);
         sb.append(", askTime=").append(askTime);
         sb.append(", askTime=").append(askTime);
         sb.append(", cctalkName=").append(cctalkName);
         sb.append(", cctalkName=").append(cctalkName);
         sb.append(", isSubscribe=").append(isSubscribe);
         sb.append(", isSubscribe=").append(isSubscribe);
@@ -811,6 +836,16 @@ public class UserOrderRecord implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置小班课时间段
+         *
+         * @param timeId 小班课时间段
+         */
+        public Builder timeId(Integer timeId) {
+            obj.setTimeId(timeId);
+            return this;
+        }
+
+        /**
          * 设置回复时长
          * 设置回复时长
          *
          *
          * @param askTime 回复时长
          * @param askTime 回复时长

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

@@ -36,12 +36,24 @@ public class UserPaper implements Serializable {
     private String paperOrigin;
     private String paperOrigin;
 
 
     /**
     /**
+     * 模考:是否适应难度: 0非适应性,1适应性,2千行
+     */
+    @Column(name = "`is_adapt`")
+    private Integer isAdapt;
+
+    /**
      * 对应来源id
      * 对应来源id
      */
      */
     @Column(name = "`origin_id`")
     @Column(name = "`origin_id`")
     private Integer originId;
     private Integer originId;
 
 
     /**
     /**
+     * 关联记录id
+     */
+    @Column(name = "`record_id`")
+    private Integer recordId;
+
+    /**
      * 题目编号id列表:json
      * 题目编号id列表:json
      */
      */
     @Column(name = "`question_no_ids`")
     @Column(name = "`question_no_ids`")
@@ -190,6 +202,24 @@ public class UserPaper implements Serializable {
     }
     }
 
 
     /**
     /**
+     * 获取模考:是否适应难度: 0非适应性,1适应性,2千行
+     *
+     * @return is_adapt - 模考:是否适应难度: 0非适应性,1适应性,2千行
+     */
+    public Integer getIsAdapt() {
+        return isAdapt;
+    }
+
+    /**
+     * 设置模考:是否适应难度: 0非适应性,1适应性,2千行
+     *
+     * @param isAdapt 模考:是否适应难度: 0非适应性,1适应性,2千行
+     */
+    public void setIsAdapt(Integer isAdapt) {
+        this.isAdapt = isAdapt;
+    }
+
+    /**
      * 获取对应来源id
      * 获取对应来源id
      *
      *
      * @return origin_id - 对应来源id
      * @return origin_id - 对应来源id
@@ -208,6 +238,24 @@ public class UserPaper implements Serializable {
     }
     }
 
 
     /**
     /**
+     * 获取关联记录id
+     *
+     * @return record_id - 关联记录id
+     */
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    /**
+     * 设置关联记录id
+     *
+     * @param recordId 关联记录id
+     */
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    /**
      * 获取题目编号id列表:json
      * 获取题目编号id列表:json
      *
      *
      * @return question_no_ids - 题目编号id列表:json
      * @return question_no_ids - 题目编号id列表:json
@@ -398,7 +446,9 @@ public class UserPaper implements Serializable {
         sb.append(", title=").append(title);
         sb.append(", title=").append(title);
         sb.append(", paperModule=").append(paperModule);
         sb.append(", paperModule=").append(paperModule);
         sb.append(", paperOrigin=").append(paperOrigin);
         sb.append(", paperOrigin=").append(paperOrigin);
+        sb.append(", isAdapt=").append(isAdapt);
         sb.append(", originId=").append(originId);
         sb.append(", originId=").append(originId);
+        sb.append(", recordId=").append(recordId);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", times=").append(times);
         sb.append(", times=").append(times);
@@ -473,6 +523,16 @@ public class UserPaper implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置模考:是否适应难度: 0非适应性,1适应性,2千行
+         *
+         * @param isAdapt 模考:是否适应难度: 0非适应性,1适应性,2千行
+         */
+        public Builder isAdapt(Integer isAdapt) {
+            obj.setIsAdapt(isAdapt);
+            return this;
+        }
+
+        /**
          * 设置对应来源id
          * 设置对应来源id
          *
          *
          * @param originId 对应来源id
          * @param originId 对应来源id
@@ -483,6 +543,16 @@ public class UserPaper implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置关联记录id
+         *
+         * @param recordId 关联记录id
+         */
+        public Builder recordId(Integer recordId) {
+            obj.setRecordId(recordId);
+            return this;
+        }
+
+        /**
          * 设置题目编号id列表:json
          * 设置题目编号id列表:json
          *
          *
          * @param questionNoIds 题目编号id列表:json
          * @param questionNoIds 题目编号id列表:json

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

@@ -105,6 +105,12 @@ public class UserReport implements Serializable {
     @Column(name = "`is_finish`")
     @Column(name = "`is_finish`")
     private Integer isFinish;
     private Integer isFinish;
 
 
+    /**
+     * 是否完成报告
+     */
+    @Column(name = "`is_stat`")
+    private Integer isStat;
+
     @Column(name = "`create_time`")
     @Column(name = "`create_time`")
     private Date createTime;
     private Date createTime;
 
 
@@ -412,6 +418,24 @@ public class UserReport implements Serializable {
     }
     }
 
 
     /**
     /**
+     * 获取是否完成报告
+     *
+     * @return is_stat - 是否完成报告
+     */
+    public Integer getIsStat() {
+        return isStat;
+    }
+
+    /**
+     * 设置是否完成报告
+     *
+     * @param isStat 是否完成报告
+     */
+    public void setIsStat(Integer isStat) {
+        this.isStat = isStat;
+    }
+
+    /**
      * @return create_time
      * @return create_time
      */
      */
     public Date getCreateTime() {
     public Date getCreateTime() {
@@ -462,6 +486,7 @@ public class UserReport implements Serializable {
         sb.append(", score=").append(score);
         sb.append(", score=").append(score);
         sb.append(", detail=").append(detail);
         sb.append(", detail=").append(detail);
         sb.append(", isFinish=").append(isFinish);
         sb.append(", isFinish=").append(isFinish);
+        sb.append(", isStat=").append(isStat);
         sb.append(", createTime=").append(createTime);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
         sb.append(", updateTime=").append(updateTime);
         sb.append("]");
         sb.append("]");
@@ -646,6 +671,16 @@ public class UserReport implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置是否完成报告
+         *
+         * @param isStat 是否完成报告
+         */
+        public Builder isStat(Integer isStat) {
+            obj.setIsStat(isStat);
+            return this;
+        }
+
+        /**
          * @param createTime
          * @param createTime
          */
          */
         public Builder createTime(Date createTime) {
         public Builder createTime(Date createTime) {

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

@@ -29,6 +29,12 @@ public class UserService implements Serializable {
     @Column(name = "`is_subscribe`")
     @Column(name = "`is_subscribe`")
     private Integer isSubscribe;
     private Integer isSubscribe;
 
 
+    /**
+     * 模考是否重置
+     */
+    @Column(name = "`is_reset`")
+    private Integer isReset;
+
     @Column(name = "`start_time`")
     @Column(name = "`start_time`")
     private Date startTime;
     private Date startTime;
 
 
@@ -106,6 +112,24 @@ public class UserService implements Serializable {
     }
     }
 
 
     /**
     /**
+     * 获取模考是否重置
+     *
+     * @return is_reset - 模考是否重置
+     */
+    public Integer getIsReset() {
+        return isReset;
+    }
+
+    /**
+     * 设置模考是否重置
+     *
+     * @param isReset 模考是否重置
+     */
+    public void setIsReset(Integer isReset) {
+        this.isReset = isReset;
+    }
+
+    /**
      * @return start_time
      * @return start_time
      */
      */
     public Date getStartTime() {
     public Date getStartTime() {
@@ -143,6 +167,7 @@ public class UserService implements Serializable {
         sb.append(", userId=").append(userId);
         sb.append(", userId=").append(userId);
         sb.append(", service=").append(service);
         sb.append(", service=").append(service);
         sb.append(", isSubscribe=").append(isSubscribe);
         sb.append(", isSubscribe=").append(isSubscribe);
+        sb.append(", isReset=").append(isReset);
         sb.append(", startTime=").append(startTime);
         sb.append(", startTime=").append(startTime);
         sb.append(", expireTime=").append(expireTime);
         sb.append(", expireTime=").append(expireTime);
         sb.append("]");
         sb.append("]");
@@ -199,6 +224,16 @@ public class UserService implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置模考是否重置
+         *
+         * @param isReset 模考是否重置
+         */
+        public Builder isReset(Integer isReset) {
+            obj.setIsReset(isReset);
+            return this;
+        }
+
+        /**
          * @param startTime
          * @param startTime
          */
          */
         public Builder startTime(Date startTime) {
         public Builder startTime(Date startTime) {

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

@@ -21,8 +21,8 @@
     <result column="cover" jdbcType="VARCHAR" property="cover" />
     <result column="cover" jdbcType="VARCHAR" property="cover" />
     <result column="min_number" jdbcType="INTEGER" property="minNumber" />
     <result column="min_number" jdbcType="INTEGER" property="minNumber" />
     <result column="max_number" jdbcType="INTEGER" property="maxNumber" />
     <result column="max_number" jdbcType="INTEGER" property="maxNumber" />
+    <result column="expire_pre_days" jdbcType="INTEGER" property="expirePreDays" />
     <result column="expire_days" jdbcType="INTEGER" property="expireDays" />
     <result column="expire_days" jdbcType="INTEGER" property="expireDays" />
-    <result column="expire_time" jdbcType="INTEGER" property="expireTime" />
     <result column="use_expire_time" jdbcType="INTEGER" property="useExpireTime" />
     <result column="use_expire_time" jdbcType="INTEGER" property="useExpireTime" />
     <result column="wechat_avatar" jdbcType="VARCHAR" property="wechatAvatar" />
     <result column="wechat_avatar" jdbcType="VARCHAR" property="wechatAvatar" />
     <result column="trail_number" jdbcType="INTEGER" property="trailNumber" />
     <result column="trail_number" jdbcType="INTEGER" property="trailNumber" />
@@ -53,8 +53,8 @@
     -->
     -->
     `id`, `struct_id`, `parent_struct_id`, `course_module`, `no_number`, `vs_type`, `video_type`, 
     `id`, `struct_id`, `parent_struct_id`, `course_module`, `no_number`, `vs_type`, `video_type`, 
     `extend`, `title`, `comment`, `crowd`, `price`, `teacher`, `cover`, `min_number`, 
     `extend`, `title`, `comment`, `crowd`, `price`, `teacher`, `cover`, `min_number`, 
-    `max_number`, `expire_days`, `expire_time`, `use_expire_time`, `wechat_avatar`, `trail_number`, 
-    `sale_number`, `package_sale_number`, `create_time`, `update_time`
+    `max_number`, `expire_pre_days`, `expire_days`, `use_expire_time`, `wechat_avatar`, 
+    `trail_number`, `sale_number`, `package_sale_number`, `create_time`, `update_time`
   </sql>
   </sql>
   <sql id="Blob_Column_List">
   <sql id="Blob_Column_List">
     <!--
     <!--

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

@@ -1,20 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.qxgmat.data.dao.CourseStudentOnlineMapper">
-  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.CourseStudentOnline">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    <id column="id" jdbcType="INTEGER" property="id" />
-    <result column="course_id" jdbcType="INTEGER" property="courseId" />
-    <result column="time_id" jdbcType="INTEGER" property="timeId" />
-    <result column="user_id" jdbcType="INTEGER" property="userId" />
-    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
-  </resultMap>
-  <sql id="Base_Column_List">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    `id`, `course_id`, `time_id`, `user_id`, `create_time`
-  </sql>
-</mapper>

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

@@ -19,7 +19,9 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+    <result column="quant_contennt" jdbcType="LONGVARCHAR" property="quantContennt" />
+    <result column="rc_content" jdbcType="LONGVARCHAR" property="rcContent" />
+    <result column="ir_content" jdbcType="LONGVARCHAR" property="irContent" />
   </resultMap>
   </resultMap>
   <sql id="Base_Column_List">
   <sql id="Base_Column_List">
     <!--
     <!--
@@ -32,6 +34,6 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `content`
+    `quant_contennt`, `rc_content`, `ir_content`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -6,7 +6,6 @@
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
-    <result column="time" jdbcType="VARCHAR" property="time" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="logic" jdbcType="VARCHAR" property="logic" />
     <result column="logic" jdbcType="VARCHAR" property="logic" />
     <result column="no" jdbcType="INTEGER" property="no" />
     <result column="no" jdbcType="INTEGER" property="no" />
@@ -15,12 +14,13 @@
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="status" jdbcType="INTEGER" property="status" />
     <result column="status" jdbcType="INTEGER" property="status" />
+    <result column="year" jdbcType="VARCHAR" property="year" />
   </resultMap>
   </resultMap>
   <sql id="Base_Column_List">
   <sql id="Base_Column_List">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `time`, `title`, `logic`, `no`, `library_id`, `question_no_ids`, `question_number`, 
-    `create_time`, `status`
+    `id`, `title`, `logic`, `no`, `library_id`, `question_no_ids`, `question_number`, 
+    `create_time`, `status`, `year`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -13,13 +13,13 @@
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_time" jdbcType="INTEGER" property="totalTime" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
     <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
     <result column="total_correct" jdbcType="INTEGER" property="totalCorrect" />
-    <result column="time" jdbcType="VARCHAR" property="time" />
+    <result column="year" jdbcType="VARCHAR" property="year" />
   </resultMap>
   </resultMap>
   <sql id="Base_Column_List">
   <sql id="Base_Column_List">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
     `id`, `title`, `no`, `library_id`, `question_id`, `total_time`, `total_number`, `total_correct`, 
     `id`, `title`, `no`, `library_id`, `question_id`, `total_time`, `total_number`, `total_correct`, 
-    `time`
+    `year`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -17,6 +17,7 @@
     <result column="teacher_id" jdbcType="INTEGER" property="teacherId" />
     <result column="teacher_id" jdbcType="INTEGER" property="teacherId" />
     <result column="number" jdbcType="INTEGER" property="number" />
     <result column="number" jdbcType="INTEGER" property="number" />
     <result column="vs_no" jdbcType="INTEGER" property="vsNo" />
     <result column="vs_no" jdbcType="INTEGER" property="vsNo" />
+    <result column="time_id" jdbcType="INTEGER" property="timeId" />
     <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="cctalk_name" jdbcType="VARCHAR" property="cctalkName" />
     <result column="cctalk_name" jdbcType="VARCHAR" property="cctalkName" />
     <result column="is_subscribe" jdbcType="INTEGER" property="isSubscribe" />
     <result column="is_subscribe" jdbcType="INTEGER" property="isSubscribe" />
@@ -38,8 +39,9 @@
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
     `id`, `user_id`, `order_id`, `parent_id`, `product_type`, `product_id`, `service`, 
     `id`, `user_id`, `order_id`, `parent_id`, `product_type`, `product_id`, `service`, 
-    `param`, `source`, `teacher_id`, `number`, `vs_no`, `ask_time`, `cctalk_name`, `is_subscribe`, 
-    `start_time`, `end_time`, `use_start_time`, `use_end_time`, `is_used`, `use_time`, 
-    `is_stop`, `stop_time`, `is_suspend`, `suspend_time`, `restore_time`, `create_time`
+    `param`, `source`, `teacher_id`, `number`, `vs_no`, `time_id`, `ask_time`, `cctalk_name`, 
+    `is_subscribe`, `start_time`, `end_time`, `use_start_time`, `use_end_time`, `is_used`, 
+    `use_time`, `is_stop`, `stop_time`, `is_suspend`, `suspend_time`, `restore_time`, 
+    `create_time`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -10,7 +10,9 @@
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="paper_module" jdbcType="VARCHAR" property="paperModule" />
     <result column="paper_module" jdbcType="VARCHAR" property="paperModule" />
     <result column="paper_origin" jdbcType="VARCHAR" property="paperOrigin" />
     <result column="paper_origin" jdbcType="VARCHAR" property="paperOrigin" />
+    <result column="is_adapt" jdbcType="INTEGER" property="isAdapt" />
     <result column="origin_id" jdbcType="INTEGER" property="originId" />
     <result column="origin_id" jdbcType="INTEGER" property="originId" />
+    <result column="record_id" jdbcType="INTEGER" property="recordId" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="question_number" jdbcType="INTEGER" property="questionNumber" />
     <result column="times" jdbcType="INTEGER" property="times" />
     <result column="times" jdbcType="INTEGER" property="times" />
@@ -26,8 +28,8 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `title`, `paper_module`, `paper_origin`, `origin_id`, `question_no_ids`, 
-    `question_number`, `times`, `time`, `latest_time`, `total_time`, `total_number`, 
-    `total_correct`, `delete_time`, `is_reset`
+    `id`, `user_id`, `title`, `paper_module`, `paper_origin`, `is_adapt`, `origin_id`, 
+    `record_id`, `question_no_ids`, `question_number`, `times`, `time`, `latest_time`, 
+    `total_time`, `total_number`, `total_correct`, `delete_time`, `is_reset`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -22,6 +22,7 @@
     <result column="score" jdbcType="VARCHAR" property="score" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="score" jdbcType="VARCHAR" property="score" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="detail" jdbcType="VARCHAR" property="detail" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="detail" jdbcType="VARCHAR" property="detail" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
     <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
+    <result column="is_stat" jdbcType="INTEGER" property="isStat" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
   </resultMap>
@@ -31,6 +32,6 @@
     -->
     -->
     `id`, `user_id`, `paper_id`, `paper_module`, `paper_origin`, `origin_id`, `question_no_ids`, 
     `id`, `user_id`, `paper_id`, `paper_module`, `paper_origin`, `origin_id`, `question_no_ids`, 
     `question_number`, `time`, `user_number`, `user_time`, `user_correct`, `finish_time`, 
     `question_number`, `time`, `user_number`, `user_time`, `user_correct`, `finish_time`, 
-    `setting`, `score`, `detail`, `is_finish`, `create_time`, `update_time`
+    `setting`, `score`, `detail`, `is_finish`, `is_stat`, `create_time`, `update_time`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -9,6 +9,7 @@
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="service" jdbcType="VARCHAR" property="service" />
     <result column="service" jdbcType="VARCHAR" property="service" />
     <result column="is_subscribe" jdbcType="INTEGER" property="isSubscribe" />
     <result column="is_subscribe" jdbcType="INTEGER" property="isSubscribe" />
+    <result column="is_reset" jdbcType="INTEGER" property="isReset" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
   </resultMap>
   </resultMap>
@@ -16,6 +17,6 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `service`, `is_subscribe`, `start_time`, `expire_time`
+    `id`, `user_id`, `service`, `is_subscribe`, `is_reset`, `start_time`, `expire_time`
   </sql>
   </sql>
 </mapper>
 </mapper>

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/relation/PreviewAssignRelationMapper.java

@@ -0,0 +1,36 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.ExercisePaper;
+import com.qxgmat.data.dao.entity.PreviewAssign;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface PreviewAssignRelationMapper {
+
+    List<PreviewAssign> listByCourse(
+            @Param("courseId") Number courseId,
+            @Param("userId") Number userId,
+            @Param("times") Integer times
+    );
+
+    List<PreviewAssign> listByAppointment(
+            @Param("courseId") Number courseId,
+            @Param("appointmentIds") Collection appointmentIds,
+            @Param("userId") Number userId,
+            @Param("endTime") String endTime,
+            @Param("times") Integer times
+    );
+
+    List<PreviewAssign> listByTime(
+            @Param("courseId") Number courseId,
+            @Param("timeId") Number timeId,
+            @Param("userId") Number userId,
+            @Param("endTime") String endTime,
+            @Param("times") Integer times
+    );
+}

+ 19 - 0
server/data/src/main/java/com/qxgmat/data/relation/TextbookPaperRelationMapper.java

@@ -0,0 +1,19 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.ExercisePaper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface TextbookPaperRelationMapper {
+
+    List<ExercisePaper> listWithUser(
+            @Param("libraryId") Number libraryId,
+            @Param("userId") Number userId,
+            @Param("logic") String logic,
+            @Param("times") Integer times
+    );
+}

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

@@ -1,20 +1,28 @@
 package com.qxgmat.data.relation;
 package com.qxgmat.data.relation;
 
 
-import com.qxgmat.data.dao.entity.UserReport;
-import com.qxgmat.data.relation.entity.UserCourseStatRelation;
+import com.qxgmat.data.relation.entity.UserModuleRecordStatRelation;
 import com.qxgmat.data.relation.entity.UserRankStatRelation;
 import com.qxgmat.data.relation.entity.UserRankStatRelation;
-import com.qxgmat.data.relation.entity.UserReportLimitRelation;
-import com.qxgmat.data.relation.entity.UserStudyStatRelation;
+import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 
 
-import java.util.Collection;
 import java.util.List;
 import java.util.List;
 
 
 /**
 /**
  * Created by gaojie on 2017/11/9.
  * Created by gaojie on 2017/11/9.
  */
  */
 public interface UserCourseRecordRelationMapper {
 public interface UserCourseRecordRelationMapper {
-    List<UserCourseStatRelation> statGroupType(
+    List<UserRecordStatRelation> stat(
+            @Param("userId") Integer userId,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime
+    );
+
+    List<UserRecordStatRelation> statAvg(
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime
+    );
+
+    List<UserModuleRecordStatRelation> statGroupType(
             @Param("userId") Integer userId,
             @Param("userId") Integer userId,
             @Param("startTime") String startTime,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime
             @Param("endTime") String endTime

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserOrderRecordRelationMapper.java

@@ -0,0 +1,36 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.UserCollectQuestion;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface UserOrderRecordRelationMapper {
+
+    List<UserOrderRecord> listWithStudyAdmin(
+            @Param("courseModules") String[] courseModules,
+            @Param("structId") Integer structId,
+            @Param("courseId") Integer courseId,
+            @Param("userId") Integer userId,
+            @Param("order") String order,
+            @Param("direction") String direction
+    );
+
+    List<UserOrderRecord> listWithVs(
+            @Param("vsType") String vsType,
+            @Param("courseId") Integer courseId,
+            @Param("userId") Integer userId,
+            @Param("order") String order,
+            @Param("direction") String direction
+    );
+
+    List<CourseStudentNumberRelation> groupByTime(
+            @Param("ids") Collection ids
+    );
+}

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

@@ -13,11 +13,6 @@ import java.util.List;
  */
  */
 public interface UserPaperRelationMapper {
 public interface UserPaperRelationMapper {
 
 
-    List<UserPaper> listPreviewGroupTop(
-            @Param("userId") Number userId,
-            @Param("top") Number top
-    );
-
     void accumulation(
     void accumulation(
             @Param("id") Number userPaperId,
             @Param("id") Number userPaperId,
             @Param("number") Integer number,
             @Param("number") Integer number,

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

@@ -0,0 +1,22 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.relation.entity.UserRecordStatRelation;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface UserQuestionRelationMapper {
+    List<UserRecordStatRelation> stat(
+            @Param("userId") Integer userId,
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime
+    );
+
+    List<UserRecordStatRelation> statAvg(
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime
+    );
+}

+ 7 - 2
server/data/src/main/java/com/qxgmat/data/relation/UserSentenceRecordRelationMapper.java

@@ -1,6 +1,6 @@
 package com.qxgmat.data.relation;
 package com.qxgmat.data.relation;
 
 
-import com.qxgmat.data.relation.entity.UserSentenceStatRelation;
+import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import org.apache.ibatis.annotations.Param;
 import org.apache.ibatis.annotations.Param;
 
 
 import java.util.List;
 import java.util.List;
@@ -9,9 +9,14 @@ import java.util.List;
  * Created by gaojie on 2017/11/9.
  * Created by gaojie on 2017/11/9.
  */
  */
 public interface UserSentenceRecordRelationMapper {
 public interface UserSentenceRecordRelationMapper {
-    List<UserSentenceStatRelation> stat(
+    List<UserRecordStatRelation> stat(
             @Param("userId") Integer userId,
             @Param("userId") Integer userId,
             @Param("startTime") String startTime,
             @Param("startTime") String startTime,
             @Param("endTime") String endTime
             @Param("endTime") String endTime
     );
     );
+
+    List<UserRecordStatRelation> statAvg(
+            @Param("startTime") String startTime,
+            @Param("endTime") String endTime
+    );
 }
 }

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

@@ -2,7 +2,7 @@ package com.qxgmat.data.relation.entity;
 
 
 import javax.persistence.Column;
 import javax.persistence.Column;
 
 
-public class UserCourseStatRelation {
+public class UserModuleRecordStatRelation {
     /**
     /**
      * 对应模块或题型
      * 对应模块或题型
      */
      */

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

@@ -2,7 +2,7 @@ package com.qxgmat.data.relation.entity;
 
 
 import javax.persistence.Column;
 import javax.persistence.Column;
 
 
-public class UserSentenceStatRelation {
+public class UserRecordStatRelation {
     /**
     /**
      * 用户做题时间
      * 用户做题时间
      */
      */

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

@@ -31,10 +31,10 @@
     </if>
     </if>
     where 1
     where 1
     <if test="structId != null">
     <if test="structId != null">
-      and ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR}
+      and (ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR})
     </if>
     </if>
     <if test="userId != null">
     <if test="userId != null">
-      and up.`id` != null
+      and up.`id` &gt; 0
     </if>
     </if>
   </select>
   </select>
 </mapper>
 </mapper>

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

@@ -43,7 +43,7 @@
     </if>
     </if>
     where 1
     where 1
     <if test="structId != null">
     <if test="structId != null">
-      and ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR}
+      and (ep.`struct_three` = #{structId,jdbcType=VARCHAR} or ep.`struct_four` = #{structId,jdbcType=VARCHAR})
     </if>
     </if>
     <if test="userId != null">
     <if test="userId != null">
       and up.`id` &gt; 0
       and up.`id` &gt; 0

+ 97 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/PreviewAssignRelationMapper.xml

@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.PreviewAssignRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.PreviewAssign">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    ep.`id`
+  </sql>
+
+  <!--
+   视频课程作业列表
+  -->
+  <select id="listByCourse" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_assign` pa
+    <if test="userId != null">
+    left join `user_paper` up on ep.`id` = up.`origin_id`
+      and up.`paper_origin` = 'preview'
+      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      <if test="times != null">
+        and up.`times` >= #{times,jdbcType=VARCHAR}
+      </if>
+    </if>
+    where 1
+    <if test="courseId != null">
+      and pa.`course_id` = #{courseId,jdbcType=VARCHAR}
+    </if>
+    <if test="userId != null">
+      and up.`id` &gt; 0
+    </if>
+  </select>
+
+  <!--
+   1v1课程作业列表
+  -->
+  <select id="listByAppointment" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_assign` pa
+    <if test="userId != null">
+      left join `user_paper` up on ep.`id` = up.`origin_id`
+      and up.`paper_origin` = 'preview'
+      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      <if test="times != null">
+        and up.`times` >= #{times,jdbcType=VARCHAR}
+      </if>
+    </if>
+    where 1
+    <if test="courseId != null">
+      and pa.`course_id` = #{courseId,jdbcType=VARCHAR}
+    </if>
+    <if test="appointmentIds != null">
+      pa.`course_appointment` IN
+      <foreach collection="appointmentIds" item="item" index="index" open="(" close=")" separator=",">
+        #{item}
+      </foreach>
+    </if>
+    <if test="userId != null">
+      and up.`id` &gt; 0
+    </if>
+  </select>
+
+  <!--
+   小班课程作业列表
+  -->
+  <select id="listByAppointment" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `preview_assign` pa
+    <if test="userId != null">
+      left join `user_paper` up on ep.`id` = up.`origin_id`
+      and up.`paper_origin` = 'preview'
+      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      <if test="times != null">
+        and up.`times` >= #{times,jdbcType=VARCHAR}
+      </if>
+    </if>
+    where 1
+    <if test="courseId != null">
+      and pa.`course_id` = #{courseId,jdbcType=VARCHAR}
+    </if>
+    <if test="timeId != null">
+      and pa.`course_time` = #{timeId,jdbcType=VARCHAR}
+    </if>
+    <if test="userId != null">
+      and up.`id` &gt; 0
+    </if>
+  </select>
+</mapper>

+ 40 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/TextbookPaperRelationMapper.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.TextbookPaperRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.TextbookPaper">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    ep.`id`
+  </sql>
+
+  <!--
+    用户机经-练习册列表: 用户端
+  -->
+  <select id="listWithUser" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `textbook_paper` tp
+    <if test="userId != null">
+    left join `user_paper` up on ep.`id` = up.`origin_id`
+      and up.`paper_origin` = 'textbook'
+      and up.`user_id` = #{userId,jdbcType=VARCHAR}
+      <if test="times != null">
+        and up.`times` >= #{times,jdbcType=VARCHAR}
+      </if>
+    </if>
+    where 1
+    <if test="libraryId != null">
+      and tp.`library_id` = #{libraryId,jdbcType=VARCHAR}
+    </if>
+    <if test="userId != null">
+      and up.`id` &gt; 0
+    </if>
+  </select>
+</mapper>

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

@@ -35,7 +35,7 @@
     </if>
     </if>
     where 1
     where 1
     <if test="paperId != null">
     <if test="paperId != null">
-      and tp.`id` != null
+      and tp.`id` &gt; 0
     </if>
     </if>
     <if test="questionNoId != null">
     <if test="questionNoId != null">
       and tq.`id` =#{questionNoId,jdbcType=VARCHAR}
       and tq.`id` =#{questionNoId,jdbcType=VARCHAR}

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

@@ -7,7 +7,13 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
   </resultMap>
   </resultMap>
-  <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserCourseStatRelation">
+  <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserRecordStatRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="user_time" jdbcType="INTEGER" property="user_time" />
+  </resultMap>
+  <resultMap id="studyModuleMap" type="com.qxgmat.data.relation.entity.UserModuleRecordStatRelation">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
@@ -29,6 +35,40 @@
   </sql>
   </sql>
 
 
   <!--
   <!--
+    用户听课记录统计
+  -->
+  <select id="stat" resultMap="studyMap">
+    select
+    sum(ucr.`user_time`) as `user_time`
+    from `user_course_record` ucr
+    where
+    ucr.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="startTime != null">
+      and ucr.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and ucr.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+  </select>
+
+  <!--
+    全站听课记录统计
+  -->
+  <select id="statAvg" resultMap="studyMap">
+    select
+    sum(ucr.`user_time`) / count(distance(ucr.`user_id`)) as `user_time`
+    from `user_course_record` ucr
+    where
+    1
+    <if test="startTime != null">
+      and ucr.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and ucr.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+  </select>
+
+  <!--
     用户听课记录统计,分题型
     用户听课记录统计,分题型
   -->
   -->
   <select id="statGroupType" resultMap="studyMap">
   <select id="statGroupType" resultMap="studyMap">

+ 88 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml

@@ -0,0 +1,88 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.UserOrderRecordRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.UserNoteQuestion">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <resultMap id="NumberMap" type="com.qxgmat.data.relation.entity.CourseStudentNumberRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <id column="number" jdbcType="INTEGER" property="number" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    up.`id`
+  </sql>
+
+  <!--
+    统计学生人数
+  -->
+  <select id="groupByTime" resultMap="NumberMap">
+    select
+    count(cs.`id`) as `number`, cs.`no` as `id`
+    from `user_order_record` uor
+    where
+    uor.`no` IN
+    <foreach collection="ids" item="item" index="index" open="(" close=")" separator=",">
+      #{item}
+    </foreach>
+  </select>
+
+  <!--
+    获取用户学习记录
+  -->
+  <select id="listWithStudyAdmin" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `user_order_record` uor
+    left join `course` c on c.`id` = uor.`product_id` and uor.`product_type` = 'course'
+    <if test="courseModules != null">
+      c.`course_module` IN
+      <foreach collection="courseModules" item="item" index="index" open="(" close=")" separator=",">
+        #{item, jdbcType=VARCHAR}
+      </foreach>
+    </if>
+    <if test="structId != null">
+      and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId,jdbcType=VARCHAR})
+    </if>
+    <if test="courseId != null">
+      and c.`id` = #{courseId,jdbcType=VARCHAR}
+    </if>
+    where
+    c.`id` &gt; 0
+    <if test="userId != null">
+      and uor.`user_id` = #{userId,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+  <!--
+    获取用户VS学习记录
+  -->
+  <select id="listWithVs" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `user_order_record` uor
+    left join `course` c on c.`id` = uor.`product_id` and uor.`product_type` = 'course'
+    <if test="vsType != null">
+      and c.`vs_type` = #{vsType,jdbcType=VARCHAR}
+    </if>
+    <if test="courseId != null">
+      and c.`id` = #{courseId,jdbcType=VARCHAR}
+    </if>
+    where
+    c.`id` &gt; 0
+    <if test="userId != null">
+      and uor.`user_id` = #{userId,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+
+</mapper>

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

@@ -27,25 +27,4 @@
     WHERE `id` = #{id, jdbcType=VARCHAR}
     WHERE `id` = #{id, jdbcType=VARCHAR}
   </update>
   </update>
 
 
-
-  <!--
-    用户预习作业Top列表: 用户端
-  -->
-  <select id="listPreviewGroupTop" resultMap="IdMap">
-    select
-    <include refid="Id_Column_List" />
-    from `user_paper` up
-    where
-    hp.`id` &gt; 0
-    and up.`module` = "preview"
-    <if test="userId != null">
-      and up.`user_id` = #{userId,jdbcType=VARCHAR}
-    </if>
-    and ( select count(up1.id)
-        from `user_paper` up1
-        where
-        up.`module_id` = up1.`module_id`
-        and up.`module` = "preview"
-        and up1.create_time &gt; up.create_time) &lt; ${top}
-  </select>
 </mapper>
 </mapper>

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

@@ -0,0 +1,56 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.UserQuestionRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.UserQuestion">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserRecordStatRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="user_time" jdbcType="INTEGER" property="user_time" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    ur.`id`
+  </sql>
+
+  <!--
+    用户做题记录统计
+  -->
+  <select id="stat" resultMap="studyMap">
+    select
+    sum(uq.`user_time`) as `user_time`
+    from `user_question` uq
+    where
+    uq.`user_id` = #{userId,jdbcType=VARCHAR}
+    <if test="startTime != null">
+      and uq.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+  </select>
+
+  <!--
+    全站做题记录统计
+  -->
+  <select id="statAvg" resultMap="studyMap">
+    select
+    sum(uq.`user_time`) /count(distance(uq.`user_id`)) as `user_time`
+    from `user_question` uq
+    where
+    1
+    <if test="startTime != null">
+      and uq.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and uq.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+  </select>
+</mapper>

+ 21 - 4
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserSentenceRecordRelationMapper.xml

@@ -7,7 +7,7 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
   </resultMap>
   </resultMap>
-  <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserSentenceStatRelation">
+  <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserRecordStatRelation">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
@@ -28,12 +28,29 @@
     sum(usr.`user_time`) as `user_time`
     sum(usr.`user_time`) as `user_time`
     from `user_sentence_record` usr
     from `user_sentence_record` usr
     where
     where
-    ucr.`user_id` = #{userId,jdbcType=VARCHAR}
+    usr.`user_id` = #{userId,jdbcType=VARCHAR}
     <if test="startTime != null">
     <if test="startTime != null">
-      and ur.`update_time` &gt; #{startTime,jdbcType=VARCHAR}
+      and usr.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
     </if>
     </if>
     <if test="endTime != null">
     <if test="endTime != null">
-      and ur.`update_time` &lt; #{endTime,jdbcType=VARCHAR}
+      and usr.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+  </select>
+
+  <!--
+    全站阅读记录统计
+  -->
+  <select id="statAvg" resultMap="studyMap">
+    select
+    sum(usr.`user_time`) / count(distance(usr.`user_id`)) as `user_time`
+    from `user_sentence_record` usr
+    where
+    1
+    <if test="startTime != null">
+      and usr.`create_time` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and usr.`create_time` &lt; #{endTime,jdbcType=VARCHAR}
     </if>
     </if>
   </select>
   </select>
 </mapper>
 </mapper>

+ 45 - 18
server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java

@@ -2,12 +2,14 @@ package com.qxgmat.controller.admin;
 
 
 import com.github.pagehelper.Page;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.*;
+import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.ExperienceDayRange;
 import com.qxgmat.data.constants.enums.ExperienceDayRange;
 import com.qxgmat.data.constants.enums.ExperienceScoreRange;
 import com.qxgmat.data.constants.enums.ExperienceScoreRange;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.module.ProductType;
 import com.qxgmat.data.constants.enums.module.ProductType;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.constants.enums.trade.RecordSource;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.dao.entity.*;
@@ -65,7 +67,10 @@ public class CourseController {
     private CourseTimeService courseTimeService;
     private CourseTimeService courseTimeService;
 
 
     @Autowired
     @Autowired
-    private CourseStudentOnlineService courseStudentOnlineService;
+    private PreviewPaperService previewPaperService;
+
+    @Autowired
+    private PreviewAssignService previewAssignService;
 
 
     @Autowired
     @Autowired
     private UserAskCourseService userAskCourseService;
     private UserAskCourseService userAskCourseService;
@@ -415,6 +420,9 @@ public class CourseController {
         // 统计课时数
         // 统计课时数
         Course course = courseService.get(in.getCourseId());
         Course course = courseService.get(in.getCourseId());
         courseService.edit(Course.builder().id(course.getId()).noNumber(course.getNoNumber() - 1).build());
         courseService.edit(Course.builder().id(course.getId()).noNumber(course.getNoNumber() - 1).build());
+        // 删除对应预习作业关系
+        previewPaperService.removeCourseNo(course.getId(), in.getId());
+        previewAssignService.removeCourseNo(course.getId(), in.getId());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -449,6 +457,8 @@ public class CourseController {
     public Response<Boolean> editTime(@RequestBody @Validated CourseTimeDto dto, HttpServletRequest request) {
     public Response<Boolean> editTime(@RequestBody @Validated CourseTimeDto dto, HttpServletRequest request) {
         CourseTime entity = Transform.dtoToEntity(dto);
         CourseTime entity = Transform.dtoToEntity(dto);
         entity = courseTimeService.edit(entity);
         entity = courseTimeService.edit(entity);
+        // 修改所有学员记录
+        userOrderRecordService.changeStudentTime(entity.getCourseId(), dto.getId(), entity.getStartTime(), entity.getEndTime());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -456,7 +466,11 @@ public class CourseController {
     @RequestMapping(value = "/time/delete", method = RequestMethod.DELETE)
     @RequestMapping(value = "/time/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除课时", httpMethod = "DELETE")
     @ApiOperation(value = "删除课时", httpMethod = "DELETE")
     public Response<Boolean> deleteTime(@RequestParam int id, HttpServletRequest request) {
     public Response<Boolean> deleteTime(@RequestParam int id, HttpServletRequest request) {
+        CourseTime in = courseTimeService.get(id);
         courseTimeService.delete(id);
         courseTimeService.delete(id);
+        // 删除对应预习作业关系
+        previewAssignService.removeCourseTime(in.getCourseId(), in.getId());
+        // todo 删除对应学生关系
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -490,7 +504,7 @@ public class CourseController {
 
 
         // 绑定学生数量
         // 绑定学生数量
         Collection timeIds = Transform.getIds(p, CourseTime.class, "id");
         Collection timeIds = Transform.getIds(p, CourseTime.class, "id");
-        List<CourseStudentNumberRelation> relations = courseStudentOnlineService.groupByCourse(timeIds);
+        List<CourseStudentNumberRelation> relations = userOrderRecordService.groupByCourse(timeIds);
         Map map = Transform.getMap(relations, CourseStudentNumberRelation.class, "id", "number");
         Map map = Transform.getMap(relations, CourseStudentNumberRelation.class, "id", "number");
         Transform.combine(pr, map, CourseTimeInfoDto.class, "id", "studentNumber");
         Transform.combine(pr, map, CourseTimeInfoDto.class, "id", "studentNumber");
 
 
@@ -499,18 +513,31 @@ public class CourseController {
 
 
     @RequestMapping(value = "/student/online/add", method = RequestMethod.POST)
     @RequestMapping(value = "/student/online/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加学员", httpMethod = "POST")
     @ApiOperation(value = "添加学员", httpMethod = "POST")
-    public Response<CourseStudentOnline> addStudentVideo(@RequestBody @Validated CourseStudentOnline entity, HttpServletRequest request) {
-//        CourseStudentOnline entity = Transform.dtoToEntity(dto);
-        entity = courseStudentOnlineService.addStudent(entity);
+    public Response<UserOrderRecord> addStudentOnline(@RequestBody @Validated CourseStudentOnlineDto dto, HttpServletRequest request) {
+        UserOrderRecord entity = Transform.dtoToEntity(dto);
+
+        CourseTime courseTime = courseTimeService.get(dto.getTimeId());
+        if (courseTime == null){
+            throw new ParameterException("时间段错误");
+        }
+        entity.setSource(RecordSource.BACKEND.key);
+        entity.setProductType(ProductType.COURSE.key);
+        entity.setTimeId(dto.getTimeId());
+        entity.setProductId(dto.getCourseId());
+        entity.setIsUsed(1);
+        entity.setUseTime(new Date());
+        entity.setStartTime(courseTime.getStartTime());
+        entity.setEndTime(courseTime.getEndTime());
+        entity = userOrderRecordService.addStudent(entity);
         managerLogService.log(request);
         managerLogService.log(request);
-        return ResponseHelp.success(Transform.convert(entity, CourseStudentOnline.class));
+        return ResponseHelp.success(Transform.convert(entity, UserOrderRecord.class));
     }
     }
 
 
     @RequestMapping(value = "/student/online/edit", method = RequestMethod.PUT)
     @RequestMapping(value = "/student/online/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "编辑学员", httpMethod = "PUT")
     @ApiOperation(value = "编辑学员", httpMethod = "PUT")
-    public Response<Boolean> editStudentVideo(@RequestBody @Validated CourseStudentOnline entity, HttpServletRequest request) {
-//        CourseStudentOnline entity = Transform.dtoToEntity(dto);
-        entity = courseStudentOnlineService.edit(entity);
+    public Response<Boolean> editStudentVideo(@RequestBody @Validated CourseStudentOnlineDto dto, HttpServletRequest request) {
+        UserOrderRecord entity = Transform.dtoToEntity(dto);
+        entity = userOrderRecordService.edit(entity);
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
@@ -518,16 +545,16 @@ public class CourseController {
     @RequestMapping(value = "/student/online/delete", method = RequestMethod.DELETE)
     @RequestMapping(value = "/student/online/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除学员", httpMethod = "DELETE")
     @ApiOperation(value = "删除学员", httpMethod = "DELETE")
     public Response<Boolean> deleteStudentOnline(@RequestParam int id, HttpServletRequest request) {
     public Response<Boolean> deleteStudentOnline(@RequestParam int id, HttpServletRequest request) {
-        courseTimeService.delete(id);
+        userOrderRecordService.delete(id);
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
     @RequestMapping(value = "/student/online/detail", method = RequestMethod.GET)
     @RequestMapping(value = "/student/online/detail", method = RequestMethod.GET)
     @ApiOperation(value = "获取学员", httpMethod = "GET")
     @ApiOperation(value = "获取学员", httpMethod = "GET")
-    public Response<CourseStudentOnline> detailStudentVideo(@RequestParam int id,HttpSession session) {
-        CourseStudentOnline entity = courseStudentOnlineService.get(id);
-        return ResponseHelp.success(Transform.convert(entity, CourseStudentOnline.class));
+    public Response<UserOrderRecord> detailStudentVideo(@RequestParam int id,HttpSession session) {
+        UserOrderRecord entity = userOrderRecordService.get(id);
+        return ResponseHelp.success(Transform.convert(entity, UserOrderRecord.class));
     }
     }
 
 
     @RequestMapping(value = "/student/online/list", method = RequestMethod.GET)
     @RequestMapping(value = "/student/online/list", method = RequestMethod.GET)
@@ -540,18 +567,18 @@ public class CourseController {
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
             HttpSession session) {
-        Page<CourseStudentOnline> p = courseStudentOnlineService.listAdmin(page, size, courseId, timeId);
+        Page<UserOrderRecord> p = userOrderRecordService.listAdminByOnline(page, size, courseId, timeId);
         List<CourseStudentOnlineListDto> pr = Transform.convert(p, CourseStudentOnlineListDto.class);
         List<CourseStudentOnlineListDto> pr = Transform.convert(p, CourseStudentOnlineListDto.class);
 
 
         // 绑定用户
         // 绑定用户
-        Collection userIds = Transform.getIds(p, CourseStudentOnline.class, "userId");
+        Collection userIds = Transform.getIds(p, UserOrderRecord.class, "userId");
         List<User> userList = usersService.select(userIds);
         List<User> userList = usersService.select(userIds);
         Transform.combine(pr, userList, CourseStudentOnlineListDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
         Transform.combine(pr, userList, CourseStudentOnlineListDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
 
 
         // 绑定时间段
         // 绑定时间段
-        Collection timeIds = Transform.getIds(p, CourseStudentOnline.class, "timeId");
+        Collection timeIds = Transform.getIds(p, UserOrderRecord.class, "no");
         List<CourseTime> timeList = courseTimeService.select(timeIds);
         List<CourseTime> timeList = courseTimeService.select(timeIds);
-        Transform.combine(pr, timeList, CourseStudentOnlineListDto.class, "timeId", "time", CourseTime.class, "id", CourseTimeExtendDto.class);
+        Transform.combine(pr, timeList, CourseStudentOnlineListDto.class, "no", "time", CourseTime.class, "id", CourseTimeExtendDto.class);
 
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
     }
@@ -637,7 +664,7 @@ public class CourseController {
         if (ids != null && ids.length > 0){
         if (ids != null && ids.length > 0){
             p = userOrderRecordService.select(ids);
             p = userOrderRecordService.select(ids);
         }else{
         }else{
-            p = userOrderRecordService.listWithStudyAdmin(page, size, CourseModule.ValueOf(courseModule), structId, courseId, userId, teacher);
+            p = userOrderRecordService.listWithStudyAdmin(page, size, new String[]{courseModule}, structId, courseId, userId, teacher, order, DirectionStatus.ValueOf(direction));
         }
         }
         List<UserCourseStudyRecordInfoDto> pr = Transform.convert(p, UserCourseStudyRecordInfoDto.class);
         List<UserCourseStudyRecordInfoDto> pr = Transform.convert(p, UserCourseStudyRecordInfoDto.class);
 
 

+ 8 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java

@@ -5,6 +5,7 @@ import com.nuliji.tools.PageMessage;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.Transform;
+import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.entity.Course;
 import com.qxgmat.data.dao.entity.Course;
@@ -60,6 +61,12 @@ public class PreviewController {
     @ApiOperation(value = "添加预习作业", httpMethod = "POST")
     @ApiOperation(value = "添加预习作业", httpMethod = "POST")
     public Response<PreviewPaper> add(@RequestBody @Validated PreviewPaperDto dto, HttpServletRequest request) {
     public Response<PreviewPaper> add(@RequestBody @Validated PreviewPaperDto dto, HttpServletRequest request) {
         PreviewPaper entity = Transform.dtoToEntity(dto);
         PreviewPaper entity = Transform.dtoToEntity(dto);
+        if (dto.getCourseNo() != null){
+            PreviewAssign assign = previewAssignService.getByCourseNo(dto.getCourseId(), dto.getCourseNo());
+            if (assign != null){
+                throw new ParameterException("该课时已经创建");
+            }
+        }
         previewPaperService.add(entity);
         previewPaperService.add(entity);
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(entity);
         return ResponseHelp.success(entity);
@@ -70,6 +77,7 @@ public class PreviewController {
     public Response<Boolean> edit(@RequestBody @Validated PreviewPaperDto dto, HttpServletRequest request) {
     public Response<Boolean> edit(@RequestBody @Validated PreviewPaperDto dto, HttpServletRequest request) {
         PreviewPaper entity = Transform.dtoToEntity(dto);
         PreviewPaper entity = Transform.dtoToEntity(dto);
         previewPaperService.edit(entity);
         previewPaperService.edit(entity);
+        // 不允许编辑课时,如果允许,该处进行处理
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }

+ 34 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java

@@ -348,6 +348,40 @@ public class SettingController {
         return ResponseHelp.success(entity.getValue());
         return ResponseHelp.success(entity.getValue());
     }
     }
 
 
+    @RequestMapping(value = "/sentence_info", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改长难句信息", httpMethod = "PUT")
+    private Response<Boolean> editSentenceInfo(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.SENTENCE_INFO);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/sentence_info", method = RequestMethod.GET)
+    @ApiOperation(value = "获取长难句信息", httpMethod = "GET")
+    private Response<JSONObject> getSentenceInfo(){
+        Setting entity = settingService.getByKey(SettingKey.SENTENCE_INFO);
+
+        return ResponseHelp.success(entity.getValue());
+    }
+
+    @RequestMapping(value = "/wechat_info", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改长难句信息", httpMethod = "PUT")
+    private Response<Boolean> editWechatInfo(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.WECHAT_INFO);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/wechat_info", method = RequestMethod.GET)
+    @ApiOperation(value = "获取长难句信息", httpMethod = "GET")
+    private Response<JSONObject> getWechatInfo(){
+        Setting entity = settingService.getByKey(SettingKey.WECHAT_INFO);
+
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/tips", method = RequestMethod.PUT)
     @RequestMapping(value = "/tips", method = RequestMethod.PUT)
     @ApiOperation(value = "修改结构说明", httpMethod = "PUT")
     @ApiOperation(value = "修改结构说明", httpMethod = "PUT")
     private Response<Boolean> editTips(@RequestBody @Validated JSONObject dto){
     private Response<Boolean> editTips(@RequestBody @Validated JSONObject dto){

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

@@ -92,6 +92,9 @@ public class UserController {
     private PreviewPaperService previewPaperService;
     private PreviewPaperService previewPaperService;
 
 
     @Autowired
     @Autowired
+    private PreviewAssignService previewAssignService;
+
+    @Autowired
     private TextbookLibraryService textbookLibraryService;
     private TextbookLibraryService textbookLibraryService;
 
 
     @Autowired
     @Autowired
@@ -155,9 +158,9 @@ public class UserController {
         UserDetailDto dto = Transform.convert(entity, UserDetailDto.class);
         UserDetailDto dto = Transform.convert(entity, UserDetailDto.class);
         Integer time = 0;
         Integer time = 0;
 
 
-        time += courseExtendService.studyTime(id);
-        time += sentenceService.studyTime(id);
-        time += questionFlowService.studyTime(id);
+        time += courseExtendService.studyTime(id, null, null);
+        time += sentenceService.studyTime(id, null, null);
+        time += questionFlowService.studyTime(id, null, null);
         dto.setTotalTime(time);
         dto.setTotalTime(time);
 
 
         return ResponseHelp.success(dto);
         return ResponseHelp.success(dto);
@@ -555,7 +558,11 @@ public class UserController {
     @RequestMapping(value = "/course/appointment/delete", method = RequestMethod.DELETE)
     @RequestMapping(value = "/course/appointment/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除课程预约", httpMethod = "DELETE")
     @ApiOperation(value = "删除课程预约", httpMethod = "DELETE")
     public Response<Boolean> deleteCourseAppointment(@RequestParam int id, HttpServletRequest request) {
     public Response<Boolean> deleteCourseAppointment(@RequestParam int id, HttpServletRequest request) {
-        userCourseAppointmentService.delete(id);
+        UserCourseAppointment in = userCourseAppointmentService.get(id);
+        // 调整课时序号
+        userCourseAppointmentService.deleteAppointment(id);
+        // 删除对应预习作业关系
+        previewAssignService.removeCourseAppointment(in.getCourseId(), in.getId());
         managerLogService.log(request);
         managerLogService.log(request);
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }

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

@@ -73,7 +73,7 @@ public class AuthController {
         }else{
         }else{
             user = usersService.getUserByToken(token);
             user = usersService.getUserByToken(token);
             // 用该token登录
             // 用该token登录
-            shiroHelp.getSession().login(shiroHelp.user(user.getMobile(), ""));
+            shiroHelp.getSession().login(shiroHelp.user(user.getArea()+":"+user.getMobile(), ""));
         }
         }
 
 
         User entity = usersService.get(user.getId());
         User entity = usersService.get(user.getId());

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

@@ -87,6 +87,27 @@ public class BaseController {
         return ResponseHelp.success(map);
         return ResponseHelp.success(map);
     }
     }
 
 
+    @RequestMapping(value = "/sentence", method = RequestMethod.GET)
+    @ApiOperation(value = "获取长难句信息", notes = "获取长难句信息", httpMethod = "GET")
+    public Response<JSONObject> sentence()  {
+        Setting entity = settingService.getByKey(SettingKey.SENTENCE_INFO);
+        return ResponseHelp.success(entity.getValue());
+    }
+
+    @RequestMapping(value = "/experience", method = RequestMethod.GET)
+    @ApiOperation(value = "获取心经信息", notes = "获取心经信息", httpMethod = "GET")
+    public Response<JSONObject> experience()  {
+        Setting entity = settingService.getByKey(SettingKey.EXPERIENCE_INFO);
+        return ResponseHelp.success(entity.getValue());
+    }
+
+    @RequestMapping(value = "/wechat", method = RequestMethod.GET)
+    @ApiOperation(value = "获取心经信息", notes = "获取心经信息", httpMethod = "GET")
+    public Response<JSONObject> wechat()  {
+        Setting entity = settingService.getByKey(SettingKey.WECHAT_INFO);
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/score", method = RequestMethod.GET)
     @RequestMapping(value = "/score", method = RequestMethod.GET)
     @ApiOperation(value = "考分计算", notes = "获取考分排行信息", httpMethod = "GET")
     @ApiOperation(value = "考分计算", notes = "获取考分排行信息", httpMethod = "GET")
     public Response<Rank> score(
     public Response<Rank> score(

+ 101 - 58
server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java

@@ -3,13 +3,17 @@ package com.qxgmat.controller.api;
 
 
 import com.github.pagehelper.Page;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.*;
+import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.ExperienceDayRange;
 import com.qxgmat.data.constants.enums.ExperienceDayRange;
 import com.qxgmat.data.constants.enums.ExperienceScoreRange;
 import com.qxgmat.data.constants.enums.ExperienceScoreRange;
 import com.qxgmat.data.constants.enums.module.CourseModule;
 import com.qxgmat.data.constants.enums.module.CourseModule;
+import com.qxgmat.data.constants.enums.module.VsCourseType;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
 import com.qxgmat.dto.extend.CourseExtendDto;
 import com.qxgmat.dto.extend.CourseExtendDto;
+import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.dto.response.*;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.extend.PreviewService;
@@ -20,9 +24,8 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.bind.annotation.*;
 
 
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSession;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
+import java.util.*;
+import java.util.stream.Collectors;
 
 
 @RestController
 @RestController
 @RequestMapping("/api/course")
 @RequestMapping("/api/course")
@@ -102,6 +105,18 @@ public class CourseController {
         return ResponseHelp.success(course);
         return ResponseHelp.success(course);
     }
     }
 
 
+    @RequestMapping(value = "/simple", method = RequestMethod.GET)
+    @ApiOperation(value = "课程基本信息", httpMethod = "GET")
+    public Response<Course> simple(
+            @RequestParam(required = true) Integer courseId
+    ) {
+        User user = (User) shiroHelp.getLoginUser();
+
+        Course course = courseService.get(courseId);
+
+        return ResponseHelp.success(course);
+    }
+
     @RequestMapping(value = "/package/list", method = RequestMethod.GET)
     @RequestMapping(value = "/package/list", method = RequestMethod.GET)
     @ApiOperation(value = "套餐列表", httpMethod = "GET")
     @ApiOperation(value = "套餐列表", httpMethod = "GET")
     public Response<PageMessage<CoursePackageListDto>> listPackage(
     public Response<PageMessage<CoursePackageListDto>> listPackage(
@@ -203,59 +218,87 @@ public class CourseController {
         return ResponseHelp.success(p, page, size, p.getTotal());
         return ResponseHelp.success(p, page, size, p.getTotal());
     }
     }
 
 
-//    @RequestMapping(value = "/progress", method = RequestMethod.GET)
-//    @ApiOperation(value = "获取课程进度", notes = "获取所有课程及状态进度", httpMethod = "GET")
-//    public Response<List<UserCourseDetailDto>> progress()  {
-//        User user = (User) shiroHelp.getLoginUser();
-//        List<UserCourse> userCourseList = userOrderRecordService.getByUser(user.getId());
-//        List<UserCourseDetailDto> dtos = Transform.convert(userCourseList, UserCourseDetailDto.class);
-//
-//        // 获取每个科目的最后2次作业
-//        Map<Object, Collection<UserPreviewPaperRelation>> previewMap = previewService.groupByCategory(user.getId(), 3);
-//        Transform.combine(dtos, previewMap, UserCourseDetailDto.class, "courseId", "previews", UserPreviewPaperExtendDto.class);
-//
-//        // 获取课程状态:已购买未开通
-//        List<UserOrderRecord> records = userOrderRecordService.listUnUse(user.getId(), ProductType.COURSE);
-//        Collection ids = Transform.getIds(userCourseList, UserCourse.class, "courseId");
-//        for(UserOrderRecord record : records){
-//            Integer courseId = record.getProductId();
-//            if (!ids.contains(courseId)){
-//                UserCourseDetailDto dto = new UserCourseDetailDto();
-//                dto.setCourseId(courseId);
-//                dto.setPayed(true);
-//                dtos.add(dto);
-//            }
-//        }
-//        // todo 区分完成状态
-//
-//        return ResponseHelp.success(dtos);
-//    }
-
-//    @RequestMapping(value = "/preview/list", method = RequestMethod.GET)
-//    @ApiOperation(value = "获取预习作业列表", notes = "获取预习作业列表", httpMethod = "GET")
-//    public Response<PageMessage<UserPreviewPaperExtendDto>> listPreview(
-//            @RequestParam(required = false, defaultValue = "1") int page,
-//            @RequestParam(required = false, defaultValue = "100") int size,
-//            @RequestParam(required = false) Number category,
-//            @RequestParam(required = false) String endTime,
-//            @RequestParam(required = false) Boolean finish
-//    )  {
-//        User user = (User) shiroHelp.getLoginUser();
-//        PageResult<UserPreviewPaperRelation> p = previewService.list(page, size, category, user.getId(), endTime, finish);
-//
-//        List<UserPreviewPaperExtendDto> pr = Transform.convert(p, UserPreviewPaperExtendDto.class);
-//
-//        // 获取试卷统计信息
-//        Map map = Transform.getMap(p, UserPreviewPaperRelation.class, "id", "paper");
-//        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
-//        for(Object value : map.keySet()){
-//            Integer key = (Integer) value;
-//            PreviewPaper preview = (PreviewPaper) map.get(key);
-//            questionNoIdsMap.put(key, preview.getQuestionNoIds());
-//        }
-//        Map statMap = questionNoService.statPaperMap(questionNoIdsMap);
-//        Transform.combine(pr, statMap, UserPreviewPaperExtendDto.class, "id", "stat");
-//
-//        return ResponseHelp.success(pr, page, size, p.getTotal());
-//    }
+    @RequestMapping(value = "/record", method = RequestMethod.GET)
+    @ApiOperation(value = "获取课程记录信息", notes = "获取所有课程及状态进度", httpMethod = "GET")
+    public Response<UserCourseDetailDto> record(
+            @RequestParam(required = true) Integer recordId
+    )  {
+        User user = (User) shiroHelp.getLoginUser();
+        UserOrderRecord userOrderRecord = userOrderRecordService.get(recordId);
+        if (userOrderRecord == null){
+            throw new ParameterException("记录不存在");
+        }
+        if (!userOrderRecord.getUserId().equals(user.getId())){
+            throw new ParameterException("记录不存在");
+        }
+        UserCourseDetailDto dto = Transform.convert(userOrderRecord, UserCourseDetailDto.class);
+        Course course = courseService.get(userOrderRecord.getProductId());
+        dto.setCourse(Transform.convert(course, CourseExtendDto.class));
+        return ResponseHelp.success(dto);
+    }
+
+    @RequestMapping(value = "/progress", method = RequestMethod.GET)
+    @ApiOperation(value = "获取课程进度", notes = "获取所有课程及状态进度", httpMethod = "GET")
+    public Response<List<UserCourseProgressDto>> progress(
+            @RequestParam(required = false) String courseModule,
+            @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) Integer courseId
+    )  {
+        User user = (User) shiroHelp.getLoginUser();
+        List<UserOrderRecord> userOrderRecordList;
+        CourseModule module = CourseModule.ValueOf(courseModule);
+        if (module == CourseModule.VIDEO){
+            // 视频课程包含:小班课程
+            userOrderRecordList = userOrderRecordService.listWithStudyAdmin(1, 1000, new String[]{CourseModule.VIDEO.key, CourseModule.ONLINE.key}, structId, courseId, user.getId(), null,null, null);
+        } else if (module == CourseModule.VS){
+            // 1v1课程:只有系统授课有作业
+            userOrderRecordList = userOrderRecordService.listWithVs(1, 1000, VsCourseType.COACH, courseId, user.getId(), null, null);
+        }else{
+            throw new ParameterException("课程类型错误");
+        }
+        List<UserCourseProgressDto> dtos = Transform.convert(userOrderRecordList, UserCourseProgressDto.class);
+
+        // 绑定课程
+        Collection courseIds = Transform.getIds(userOrderRecordList, UserOrderRecord.class, "productId");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(dtos, courseList, UserCourseProgressDto.class, "productId", "course", Course.class, "id", CourseExtendDto.class);
+
+        // 获取每个科目的最后2次作业: 正在进行中的
+        Date now = new Date();
+        List<UserOrderRecord> processList = userOrderRecordList.stream().filter(row-> row.getIsUsed() > 0 && row.getUseEndTime().after(now)).collect(Collectors.toList());
+        Collection processIds = Transform.getIds(processList, UserOrderRecord.class, "id");
+        Map<Object, Collection<UserPreviewPaperRelation>> previewMap = previewService.groupByCourseId(user.getId(), processIds, 2);
+        Transform.combine(dtos, previewMap, UserCourseProgressDto.class, "productId", "previews", UserPaperBaseExtendDto.class);
+
+        return ResponseHelp.success(dtos);
+    }
+
+    @RequestMapping(value = "/preview/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取预习作业列表", notes = "获取预习作业列表", httpMethod = "GET")
+    public Response<List<UserExercisePaperDto>> listPreview(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer recordId,
+            @RequestParam(required = false) String endTime,
+            @RequestParam(required = false) Integer times
+    )  {
+        User user = (User) shiroHelp.getLoginUser();
+
+        List<UserPreviewPaperRelation> p = previewService.list(page, size, recordId, user.getId(), endTime, times);
+        List<UserExercisePaperDto> pr = Transform.convert(p, UserExercisePaperDto.class);
+
+        // 获取试卷统计信息
+        Map map = Transform.getMap(p, UserPreviewPaperRelation.class, "id", "paper");
+        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
+        for(Object value : map.keySet()){
+            Integer key = (Integer) value;
+            PreviewPaper preview = (PreviewPaper) map.get(key);
+            questionNoIdsMap.put(key, preview.getQuestionNoIds());
+        }
+        Map statMap = questionNoService.statPaperMap(questionNoIdsMap);
+        Transform.combine(pr, statMap, UserExercisePaperDto.class, "id", "stat");
+
+        return ResponseHelp.success(pr);
+    }
 }
 }
+

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

@@ -25,8 +25,10 @@ import com.qxgmat.help.AiHelp;
 import com.qxgmat.help.MailHelp;
 import com.qxgmat.help.MailHelp;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.*;
 import com.qxgmat.service.*;
+import com.qxgmat.service.extend.CourseExtendService;
 import com.qxgmat.service.extend.OrderFlowService;
 import com.qxgmat.service.extend.OrderFlowService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.extend.QuestionFlowService;
+import com.qxgmat.service.extend.SentenceService;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import io.swagger.annotations.ApiOperation;
@@ -147,6 +149,12 @@ public class MyController {
     private QuestionFlowService questionFlowService;
     private QuestionFlowService questionFlowService;
 
 
     @Autowired
     @Autowired
+    private SentenceService sentenceService;
+
+    @Autowired
+    private CourseExtendService courseExtendService;
+
+    @Autowired
     private OrderFlowService orderFlowService;
     private OrderFlowService orderFlowService;
 
 
     @RequestMapping(value = "/email", method = RequestMethod.POST)
     @RequestMapping(value = "/email", method = RequestMethod.POST)
@@ -459,92 +467,31 @@ public class MyController {
 
 
     @RequestMapping(value = "/study/week", method = RequestMethod.GET)
     @RequestMapping(value = "/study/week", method = RequestMethod.GET)
     @ApiOperation(value = "获取本周记录", notes = "获取本周学习记录", httpMethod = "GET")
     @ApiOperation(value = "获取本周记录", notes = "获取本周学习记录", httpMethod = "GET")
-    public Response<UserStudyDetailDto> studyWeekTime()  {
+    public Response<UserStudyDetailDto> studyWeekTime(
+            @RequestParam(required = false) Integer week
+    )  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
         UserStudyDetailDto dto = new UserStudyDetailDto();
         UserStudyDetailDto dto = new UserStudyDetailDto();
         dto.setCreateTime(user.getCreateTime());
         dto.setCreateTime(user.getCreateTime());
         dto.setDays((int)((user.getCreateTime().getTime() - new Date().getTime()) / (1000*3600*24)));
         dto.setDays((int)((user.getCreateTime().getTime() - new Date().getTime()) / (1000*3600*24)));
-        Integer totalTime = 0;
-        Map<String, Integer> categoryMap = new HashMap<>();
-        // 按模块来源分组查询: module=> sentence, examination, collect+error, 忽略exercise,preview
-        List<UserStudyStatRelation> moduleList = userReportService.statGroupModule(user.getId());
-        for(UserStudyStatRelation module:moduleList){
-            // 练习时间过滤
-            if (module.getModule().equals(PaperModule.EXERCISE.key)){
-                continue;
-            }
-            Integer time = module.getUserTime();
-            String key = module.getModule();
-            totalTime += time;
-            // 收藏及错误组卷合并
-            if (module.getModule().equals(PaperOrigin.COLLECT.key)
-                    || module.getModule().equals(PaperOrigin.ERROR.key)){
-                key = "freedom";
-                time += categoryMap.getOrDefault(key, 0);
-            }else if (module.getModule().equals(PaperOrigin.PREVIEW.key)){
-                key = PaperOrigin.EXERCISE.key;
-            }
-            categoryMap.put(key, time);
-        }
-        // 按题型统计练习
-        List<UserStudyStatRelation> exerciseList = userReportService.statGroupExerciseType(user.getId(), null, null);
-        for(UserStudyStatRelation type:exerciseList){
-            totalTime += type.getUserTime();
-            categoryMap.put(type.getModule(), type.getUserTime());
-        }
-        // 按题型统计预习作业
-        List<UserStudyStatRelation> previewList = userReportService.statGroupExerciseType(user.getId(), null, null);
-        for(UserStudyStatRelation type:previewList){
-            totalTime += type.getUserTime();
-            categoryMap.put(type.getModule(), type.getUserTime());
-        }
-        // 按题型统计课程
-        List<UserCourseStatRelation> recordList = userCourseRecordService.statGroupType(user.getId(), null, null);
-        for (UserCourseStatRelation record : recordList){
-            totalTime += record.getUserTime();
-            // 累加同类型时间
-            Integer time = categoryMap.getOrDefault(record.getModule(), 0);
-            categoryMap.put(record.getModule(), time);
-        }
-        // 获取长难句阅读统计
-        UserSentenceStatRelation sentenceStatRelation = userSentenceRecordService.stat(user.getId(), null, null);
-        if (sentenceStatRelation != null){
-            Integer sentenceTime = categoryMap.getOrDefault(PaperModule.SENTENCE.key, 0);
-            categoryMap.put(PaperModule.SENTENCE.key, sentenceTime + sentenceStatRelation.getUserTime());
-        }
 
 
-        List<ExerciseStruct> p = exerciseStructService.main();
-        Map<String, String> m = new HashMap<>();
-        for (ExerciseStruct struct : p){
-            if (struct.getExtend() == null || struct.getExtend().isEmpty()) continue;
-            m.put(struct.getExtend(), struct.getTitleZh() + (struct.getTitleEn().isEmpty() ? "":" "+struct.getTitleEn()));
-        }
+        Date now = Tools.today();
+        int day = Tools.getDayOfWeek(now);
+        Date start = Tools.addDate(now, -1 * (day + week * 7));
+        Date end = Tools.addDate(start, 7);
 
 
-        // 组装数据
-        List<UserStudyExtendDto> categorys = new ArrayList<>();
-        if (categoryMap.containsKey(PaperModule.SENTENCE.key)) categorys.add(new UserStudyExtendDto(m.get(PaperModule.SENTENCE.key), categoryMap.get(PaperModule.SENTENCE.key)));
-        if (categoryMap.containsKey(QuestionType.SC.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionType.SC.key), categoryMap.get(QuestionType.SC.key)));
-        if (categoryMap.containsKey(QuestionType.RC.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionType.RC.key), categoryMap.get(QuestionType.RC.key)));
-        if (categoryMap.containsKey(QuestionType.CR.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionType.CR.key), categoryMap.get(QuestionType.CR.key)));
-        if (categoryMap.containsKey(QuestionType.PS.key)){
-            // 累加数学
-            Integer time = categoryMap.getOrDefault(QuestionSubject.QUANT.key, 0);
-            categoryMap.put(QuestionSubject.QUANT.key, time + categoryMap.get(QuestionType.PS.key));
-        }
-        if (categoryMap.containsKey(QuestionType.DS.key)){
-            // 累加数学
-            Integer time = categoryMap.getOrDefault(QuestionSubject.QUANT.key, 0);
-            categoryMap.put(QuestionSubject.QUANT.key, time + categoryMap.get(QuestionType.DS.key));
-        }
-        if (categoryMap.containsKey(QuestionSubject.QUANT.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionSubject.QUANT.key), categoryMap.get(QuestionSubject.QUANT.key)));
+        Integer time = 0;
+        time += courseExtendService.studyTime(user.getId(), start, end);
+        time += sentenceService.studyTime(user.getId(), start, end);
+        time += questionFlowService.studyTime(user.getId(), start, end);
+        dto.setTime(time);
 
 
-        if (categoryMap.containsKey(QuestionType.IR.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionType.IR.key), categoryMap.get(QuestionType.IR.key)));
-        if (categoryMap.containsKey(QuestionType.AWA.key)) categorys.add(new UserStudyExtendDto(m.get(QuestionType.AWA.key), categoryMap.get(QuestionType.AWA.key)));
-        if (categoryMap.containsKey(PaperModule.EXAMINATION.key)) categorys.add(new UserStudyExtendDto("模考", categoryMap.get(PaperModule.EXAMINATION.key)));
-        if (categoryMap.containsKey("freedom")) categorys.add(new UserStudyExtendDto("自由组卷", categoryMap.get("freedom")));
+        Integer avgTime = 0;
+        avgTime += courseExtendService.studyAvgTime(start, end);
+        avgTime += sentenceService.studyAvgTime(start, end);
+        avgTime += questionFlowService.studyAvgTime(start, end);
+        dto.setAvgTime(avgTime);
 
 
-        dto.setTime(totalTime);
-        dto.setCategorys(categorys);
         return ResponseHelp.success(dto);
         return ResponseHelp.success(dto);
     }
     }
 
 
@@ -590,15 +537,15 @@ public class MyController {
             categoryMap.put(type.getModule(), type.getUserTime());
             categoryMap.put(type.getModule(), type.getUserTime());
         }
         }
         // 按题型统计课程
         // 按题型统计课程
-        List<UserCourseStatRelation> recordList = userCourseRecordService.statGroupType(user.getId(), null, null);
-        for (UserCourseStatRelation record : recordList){
+        List<UserModuleRecordStatRelation> recordList = userCourseRecordService.statGroupType(user.getId(), null, null);
+        for (UserModuleRecordStatRelation record : recordList){
             totalTime += record.getUserTime();
             totalTime += record.getUserTime();
             // 累加同类型时间
             // 累加同类型时间
             Integer time = categoryMap.getOrDefault(record.getModule(), 0);
             Integer time = categoryMap.getOrDefault(record.getModule(), 0);
             categoryMap.put(record.getModule(), time);
             categoryMap.put(record.getModule(), time);
         }
         }
         // 获取长难句阅读统计
         // 获取长难句阅读统计
-        UserSentenceStatRelation sentenceStatRelation = userSentenceRecordService.stat(user.getId(), null, null);
+        UserRecordStatRelation sentenceStatRelation = userSentenceRecordService.stat(user.getId(), null, null);
         if (sentenceStatRelation != null){
         if (sentenceStatRelation != null){
             Integer sentenceTime = categoryMap.getOrDefault(PaperModule.SENTENCE.key, 0);
             Integer sentenceTime = categoryMap.getOrDefault(PaperModule.SENTENCE.key, 0);
             categoryMap.put(PaperModule.SENTENCE.key, sentenceTime + sentenceStatRelation.getUserTime());
             categoryMap.put(PaperModule.SENTENCE.key, sentenceTime + sentenceStatRelation.getUserTime());

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

@@ -2,9 +2,9 @@ package com.qxgmat.controller.api;
 
 
 
 
 import com.alibaba.fastjson.JSONObject;
 import com.alibaba.fastjson.JSONObject;
-import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.nuliji.tools.*;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
 import com.qxgmat.data.constants.enums.logic.ExerciseLogic;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.constants.enums.module.QuestionModule;
 import com.qxgmat.data.constants.enums.module.QuestionModule;
@@ -57,6 +57,9 @@ public class QuestionController {
     private ExaminationPaperService examinationPaperService;
     private ExaminationPaperService examinationPaperService;
 
 
     @Autowired
     @Autowired
+    private ExaminationStructService examinationStructService;
+
+    @Autowired
     private ExaminationService examinationService;
     private ExaminationService examinationService;
 
 
     @Autowired
     @Autowired
@@ -71,7 +74,6 @@ public class QuestionController {
     @Autowired
     @Autowired
     private TextbookQuestionService textbookQuestionService;
     private TextbookQuestionService textbookQuestionService;
 
 
-
     @Autowired
     @Autowired
     private SentencePaperService sentencePaperService;
     private SentencePaperService sentencePaperService;
 
 
@@ -97,12 +99,18 @@ public class QuestionController {
     private UserOrderService userOrderService;
     private UserOrderService userOrderService;
 
 
     @Autowired
     @Autowired
+    private UserOrderRecordService userOrderRecordService;
+
+    @Autowired
     private UserReportService userReportService;
     private UserReportService userReportService;
 
 
     @Autowired
     @Autowired
     private UserPaperService userPaperService;
     private UserPaperService userPaperService;
 
 
     @Autowired
     @Autowired
+    private UserServiceService userServiceService;
+
+    @Autowired
     private QuestionFlowService questionFlowService;
     private QuestionFlowService questionFlowService;
 
 
 
 
@@ -142,6 +150,7 @@ public class QuestionController {
                     for(UserQuestionStat stat : userQuestionStatMap.values()){
                     for(UserQuestionStat stat : userQuestionStatMap.values()){
                         if(stat.getUserNumber() > minTimes) userNumber += 1;
                         if(stat.getUserNumber() > minTimes) userNumber += 1;
                     }
                     }
+                    dto.setMinTimes(minTimes);
                     dto.setUserNumber(userNumber);
                     dto.setUserNumber(userNumber);
                 }
                 }
             }
             }
@@ -183,16 +192,16 @@ public class QuestionController {
                     childrenDtos.add(extendDto);
                     childrenDtos.add(extendDto);
                 }
                 }
 
 
-                Collection ids = Transform.getIds(p, ExercisePaper.class, "id");
-                List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXERCISE, ids);
+                Collection ids = Transform.getIds(paperList, ExercisePaper.class, "id");
+                List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXERCISE, ids, null);
                 // 绑定userPaperId,用于关联report
                 // 绑定userPaperId,用于关联report
                 Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
                 Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
-                Transform.combine(childrenDtos, userPaperMap, UserSentencePaperDto.class, "id", "userPaperId");
+                Transform.combine(childrenDtos, userPaperMap, UserExerciseGroupExtendDto.class, "id", "userPaperId");
 
 
                 // 获取最后一次作业结果
                 // 获取最后一次作业结果
-                Collection paperIds = Transform.getIds(paperList, ExercisePaper.class, "id");
+                Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
                 List<UserReport> reportList = userReportService.listWithLater(paperIds);
                 List<UserReport> reportList = userReportService.listWithLater(paperIds);
-                Transform.combine(childrenDtos, reportList, UserSentencePaperDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
+                Transform.combine(childrenDtos, reportList, UserExerciseGroupExtendDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
 
 
                 dto.setChildren(childrenDtos);
                 dto.setChildren(childrenDtos);
             }else{
             }else{
@@ -270,7 +279,7 @@ public class QuestionController {
         if (user != null){
         if (user != null){
             // 获取做题记录
             // 获取做题记录
             Collection ids = Transform.getIds(p, ExercisePaper.class, "id");
             Collection ids = Transform.getIds(p, ExercisePaper.class, "id");
-            List<UserPaper> paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXERCISE, ids);
+            List<UserPaper> paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXERCISE, ids, null);
             Transform.combine(pr, paperList, UserExercisePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             Transform.combine(pr, paperList, UserExercisePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
@@ -288,15 +297,52 @@ public class QuestionController {
 
 
     @RequestMapping(value = "/examination/progress", method = RequestMethod.GET)
     @RequestMapping(value = "/examination/progress", method = RequestMethod.GET)
     @ApiOperation(value = "模考进度", httpMethod = "GET")
     @ApiOperation(value = "模考进度", httpMethod = "GET")
-    public Response<PageMessage<ExercisePaper>> examinationProgress(
-            @RequestParam(required = false, defaultValue = "1") int page,
-            @RequestParam(required = false, defaultValue = "100") int size,
+    public Response<List<UserExaminationGroupDto>> examinationProgress(
+            @RequestParam(required = true) Integer structId, // 第一层,查询第三层,以及第二层汇总
             HttpSession session) {
             HttpSession session) {
-        Page<ExercisePaper> p = null;
+        User user = (User) shiroHelp.getLoginUser();
+
+        List<ExaminationStruct> two = examinationStructService.children(structId, 0);
+        List<UserExaminationGroupDto> p = new ArrayList<>(two.size());
+        for(ExaminationStruct struct : two){
+            UserExaminationGroupDto dto = Transform.convert(struct, UserExaminationGroupDto.class);
+            ServiceKey serviceKey = ServiceKey.ValueOf(struct.getExtend());
+            dto.setHasService(true);
+            // 获取第三层节点
+            // 以下属的paper作为children
+            List<ExaminationPaper> paperList = examinationPaperService.listByTwo(struct.getId());
+            dto.setPaperNumber(paperList.size());
+            dto.setMinTimes(0);
+
+            if(user != null){
+                dto.setHasService(userServiceService.hasService(user.getId(), serviceKey));
+                if (serviceKey != null){
+                    // 服务, 判断对应服务状态
+                    UserOrderRecord record = userOrderRecordService.getUnUseService(user.getId(), serviceKey);
+                    dto.setUnUseRecord(Transform.convert(record, UserServiceRecordExtendDto.class));
+                }
+                Collection ids = Transform.getIds(paperList, ExaminationPaper.class, "id");
+                List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXAMINATION, ids, null);
 
 
-        // todo
+                if (paperList.size() > userPaperList.size()){
+                    dto.setUserNumber(userPaperList.size());
+                    dto.setMinTimes(0);
+                }else{
+                    int minTimes = 0;
+                    // 统计最小轮的已做题数
+                    for(UserPaper userPaper : userPaperList){
+                        if(userPaper.getTimes() < minTimes || minTimes == 0) minTimes = userPaper.getTimes();
+                    }
+                    int userNumber = 0;
+                    for(UserPaper userPaper : userPaperList){
+                        if(userPaper.getTimes() > minTimes) userNumber += 1;
+                    }
+                    dto.setUserNumber(userNumber);
+                }
+            }
+        }
 
 
-        return ResponseHelp.success(p, page, size, p.getTotal());
+        return ResponseHelp.success(p);
     }
     }
 
 
     @RequestMapping(value = "/examination/list", method = RequestMethod.GET)
     @RequestMapping(value = "/examination/list", method = RequestMethod.GET)
@@ -315,7 +361,7 @@ public class QuestionController {
         if (user != null){
         if (user != null){
             // 获取做题记录
             // 获取做题记录
             Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
             Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
-            List<UserPaper> paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXAMINATION, ids);
+            List<UserPaper> paperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.EXAMINATION, ids, null);
             Transform.combine(pr, paperList, UserExaminationPaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             Transform.combine(pr, paperList, UserExaminationPaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
             Map userPaperMap = Transform.getMap(paperList, UserPaper.class, "originId", "id");
@@ -701,14 +747,21 @@ public class QuestionController {
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
-    @RequestMapping(value = "/restart/examination", method = RequestMethod.POST)
+    @RequestMapping(value = "/reset/cat", method = RequestMethod.POST)
     @ApiOperation(value = "重置整套模拟卷", notes = "重置考试", httpMethod = "POST")
     @ApiOperation(value = "重置整套模拟卷", notes = "重置考试", httpMethod = "POST")
-    public Response<Boolean> restartExamination(@RequestBody @Validated ExaminationRestartDto dto)  {
+    public Response<Boolean> resetCat()  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
 
 
-        // todo 判断是否已经重置达到上限
+        UserService userService = userServiceService.getService(user.getId(), ServiceKey.QX_CAT);
+        if (userService == null){
+            throw new ParameterException("无重置权限");
+        }
+        if (userService.getIsReset() > 0){
+            throw new ParameterException("已重置,请再次购买服务");
+        }
         // reset当前考卷的所有状态
         // reset当前考卷的所有状态
-        questionFlowService.restart(dto.getStructId(), user.getId());
+        examinationService.resetCat(user.getId(), false);
+        userServiceService.edit(UserService.builder().id(userService.getId()).isReset(1).build());
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 }
 }

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

@@ -114,11 +114,7 @@ public class SentenceController
     public Response<Boolean> active(@RequestBody @Validated UserSentenceCodeDto dto) {
     public Response<Boolean> active(@RequestBody @Validated UserSentenceCodeDto dto) {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
         if (user == null) throw new AuthException("需要登录");
         if (user == null) throw new AuthException("需要登录");
-
-        if (sentenceCodeService.isActive(user.getId()) == null){
-            sentenceCodeService.active(user.getId(), dto.getCode());
-        }
-
+        sentenceService.active(user.getId(), dto.getCode());
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
@@ -220,7 +216,7 @@ public class SentenceController
         if (user != null){
         if (user != null){
             // 获取做题记录
             // 获取做题记录
             Collection ids = Transform.getIds(p, SentencePaper.class, "id");
             Collection ids = Transform.getIds(p, SentencePaper.class, "id");
-            List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.SENTENCE, ids);
+            List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.SENTENCE, ids, null);
             Transform.combine(pr, userPaperList, UserSentencePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             Transform.combine(pr, userPaperList, UserSentencePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
             Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");

+ 163 - 11
server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java

@@ -1,21 +1,28 @@
 package com.qxgmat.controller.api;
 package com.qxgmat.controller.api;
 
 
 import com.github.pagehelper.Page;
 import com.github.pagehelper.Page;
-import com.nuliji.tools.PageMessage;
-import com.nuliji.tools.Response;
-import com.nuliji.tools.ResponseHelp;
-import com.nuliji.tools.Tools;
+import com.nuliji.tools.*;
 import com.nuliji.tools.exception.AuthException;
 import com.nuliji.tools.exception.AuthException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.ServiceKey;
+import com.qxgmat.data.constants.enums.logic.TextbookLogic;
+import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
-import com.qxgmat.data.dao.entity.TextbookLibrary;
-import com.qxgmat.data.dao.entity.TextbookLibraryHistory;
-import com.qxgmat.data.dao.entity.TextbookTopic;
-import com.qxgmat.data.dao.entity.User;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.data.inline.UserQuestionStat;
+import com.qxgmat.data.relation.entity.TextbookQuestionRelation;
+import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
+import com.qxgmat.dto.extend.UserReportExtendDto;
+import com.qxgmat.dto.extend.UserServiceRecordExtendDto;
+import com.qxgmat.dto.extend.UserTextbookGroupExtendDto;
+import com.qxgmat.dto.response.UserTextbookGroupDto;
 import com.qxgmat.dto.response.UserTextbookInfoDto;
 import com.qxgmat.dto.response.UserTextbookInfoDto;
+import com.qxgmat.dto.response.UserTextbookPaperDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.help.ShiroHelp;
+import com.qxgmat.service.UserPaperService;
+import com.qxgmat.service.UserQuestionService;
 import com.qxgmat.service.UserServiceService;
 import com.qxgmat.service.UserServiceService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.extend.QuestionFlowService;
 import com.qxgmat.service.extend.QuestionFlowService;
@@ -28,8 +35,8 @@ import org.springframework.web.bind.annotation.*;
 import javax.servlet.http.HttpSession;
 import javax.servlet.http.HttpSession;
 import java.text.DateFormat;
 import java.text.DateFormat;
 import java.text.ParseException;
 import java.text.ParseException;
-import java.util.Date;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 
 @RestController
 @RestController
 @RequestMapping("/api/textbook")
 @RequestMapping("/api/textbook")
@@ -49,6 +56,15 @@ public class TextbookController
     private UsersService usersService;
     private UsersService usersService;
 
 
     @Autowired
     @Autowired
+    private UserPaperService userPaperService;
+
+    @Autowired
+    private UserQuestionService userQuestionService;
+
+    @Autowired
+    private UserReportService userReportService;
+
+    @Autowired
     private UserServiceService userServiceService;
     private UserServiceService userServiceService;
 
 
     @Autowired
     @Autowired
@@ -58,6 +74,12 @@ public class TextbookController
     private QuestionFlowService questionFlowService;
     private QuestionFlowService questionFlowService;
 
 
     @Autowired
     @Autowired
+    private TextbookPaperService textbookPaperService;
+
+    @Autowired
+    private TextbookQuestionService textbookQuestionService;
+
+    @Autowired
     private TextbookLibraryService textbookLibraryService;
     private TextbookLibraryService textbookLibraryService;
 
 
     @Autowired
     @Autowired
@@ -66,6 +88,82 @@ public class TextbookController
     @Autowired
     @Autowired
     private TextbookTopicService textbookTopicService;
     private TextbookTopicService textbookTopicService;
 
 
+    @RequestMapping(value = "/progress", method = RequestMethod.GET)
+    @ApiOperation(value = "练习进度", httpMethod = "GET")
+    public Response<List<UserTextbookGroupDto>> progress(HttpSession session) {
+        User user = (User) shiroHelp.getLoginUser();
+
+        TextbookLibrary latest = textbookLibraryService.getLatest();
+        TextbookLibrary second = textbookLibraryService.getSecond();
+        List<UserTextbookGroupDto> p = new ArrayList<>(2);
+
+        for(TextbookLibrary library : new ArrayList<TextbookLibrary>(2){{add(latest);add(second);}}){
+            UserTextbookGroupDto dto = Transform.convert(library, UserTextbookGroupDto.class);
+            // 获取第三层所有题目,并获取题目统计
+            List<TextbookQuestion> list = textbookQuestionService.listByLibrary(library.getId());
+            List<TextbookQuestionRelation> relations = textbookQuestionService.relation(list);
+            dto.setStat(textbookQuestionService.statPaper(list));
+            dto.setQuestionNumber(list.size());
+            Map<Object, UserQuestionStat> userQuestionStatMap = null;
+            if(user != null){
+                Collection questionNoIds = Transform.getIds(list, QuestionNo.class, "id");
+                List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), questionNoIds);
+                userQuestionStatMap = userQuestionService.statQuestionNoMap(userQuestionList);
+
+                dto.setUserStat(userQuestionService.statQuestion(userQuestionList));
+
+                if (list.size() > userQuestionStatMap.size()){
+                    dto.setUserNumber(userQuestionStatMap.size());
+                    dto.setMinTimes(0);
+                }else{
+                    int minTimes = 0;
+                    // 统计最小轮的已做题数
+                    for(UserQuestionStat stat : userQuestionStatMap.values()){
+                        if(stat.getUserNumber() < minTimes || minTimes == 0) minTimes = stat.getUserNumber();
+                    }
+                    int userNumber = 0;
+                    for(UserQuestionStat stat : userQuestionStatMap.values()){
+                        if(stat.getUserNumber() > minTimes) userNumber += 1;
+                    }
+                    dto.setMinTimes(minTimes);
+                    dto.setUserNumber(userNumber);
+                }
+            }
+
+            List<UserTextbookGroupExtendDto> childrenDtos = new ArrayList<>(TextbookLogic.all().length);
+            for(TextbookLogic logic : TextbookLogic.all()){
+                UserTextbookGroupExtendDto extendDto = new UserTextbookGroupExtendDto();
+                extendDto.setLogic(logic.key);
+                List<TextbookQuestionRelation> childQuestionList = relations.stream().filter((q)-> logic.contain(QuestionType.ValueOf(q.getQuestion().getQuestionType()))).collect(Collectors.toList());
+                extendDto.setQuestionNumber(childQuestionList.size());
+                if (user != null){
+                    int minTimes = 0;
+                    int userQuestionNumber = 0;
+                    boolean flag = true;
+                    for(TextbookQuestion questionNo : childQuestionList){
+                        UserQuestionStat stat = userQuestionStatMap.get(questionNo.getId());
+                        if (stat == null) {
+                            flag = false;
+                            break;
+                        }
+                        if (stat.getUserNumber() < minTimes || minTimes == 0) minTimes = stat.getUserNumber();
+                    }
+                    if (!flag) minTimes = 0;
+                    for(TextbookQuestion questionNo : childQuestionList){
+                        UserQuestionStat stat = userQuestionStatMap.get(questionNo.getId());
+                        if (stat != null && stat.getUserNumber() > minTimes)  userQuestionNumber += 1;
+                    }
+                    extendDto.setUserNumber(userQuestionNumber);
+                    extendDto.setMinTimes(minTimes);
+                }
+                childrenDtos.add(extendDto);
+            }
+            dto.setChildren(childrenDtos);
+            p.add(dto);
+        }
+
+        return ResponseHelp.success(p);
+    }
 
 
     @RequestMapping(value = "/info", method = RequestMethod.GET)
     @RequestMapping(value = "/info", method = RequestMethod.GET)
     @ApiOperation(value = "机经信息", httpMethod = "GET")
     @ApiOperation(value = "机经信息", httpMethod = "GET")
@@ -77,7 +175,8 @@ public class TextbookController
         dto.setLatest(latest);
         dto.setLatest(latest);
         if (user != null){
         if (user != null){
             dto.setHasService(userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK));
             dto.setHasService(userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK));
-            dto.setUnUseRecord(userOrderRecordService.getUnUseService(user.getId(), ServiceKey.TEXTBOOK));
+            UserOrderRecord record = userOrderRecordService.getUnUseService(user.getId(), ServiceKey.TEXTBOOK);
+            dto.setUnUseRecord(Transform.convert(record, UserServiceRecordExtendDto.class));
         }
         }
         TextbookLibrary second = textbookLibraryService.getSecond();
         TextbookLibrary second = textbookLibraryService.getSecond();
         dto.setSecond(second);
         dto.setSecond(second);
@@ -154,4 +253,57 @@ public class TextbookController
 
 
         return ResponseHelp.success(p, page, size, p.getTotal());
         return ResponseHelp.success(p, page, size, p.getTotal());
     }
     }
+
+
+    @RequestMapping(value = "/paper/list", method = RequestMethod.GET)
+    @ApiOperation(value = "机经组卷列表", httpMethod = "GET")
+    public Response<List<UserTextbookPaperDto>> listPaper(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = true) boolean latest,
+            @RequestParam(required = true) String logic,
+            @RequestParam(required = false)  Integer times,
+            HttpSession session) {
+        User user = (User) shiroHelp.getLoginUser();
+        TextbookLibrary library;
+        if (latest){
+            if (user == null){
+                throw new AuthException("请先登录");
+            }
+            if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)){
+                throw new ParameterException("没有机经查看权限");
+            }
+            library = textbookLibraryService.getLatest();
+        }else{
+            // 获取往期:倒数第二
+            library = textbookLibraryService.getSecond();
+        }
+        List<TextbookPaper> p = textbookPaperService.list(page, size, library.getId(), user != null ? user.getId():null, TextbookLogic.ValueOf(logic), times);
+        List<UserTextbookPaperDto> pr = Transform.convert(p, UserTextbookPaperDto.class);
+
+        // 获取试卷统计信息
+        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
+        for(TextbookPaper paper : p){
+            questionNoIdsMap.put(paper.getId(), paper.getQuestionNoIds());
+        }
+        Map statMap = textbookQuestionService.statPaperMap(questionNoIdsMap);
+        Transform.combine(pr, statMap, UserTextbookPaperDto.class, "id", "stat");
+
+        if (user != null){
+            // 获取做题记录
+            Collection ids = Transform.getIds(p, TextbookPaper.class, "id");
+            List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.TEXTBOOK, ids, null);
+            Transform.combine(pr, userPaperList, UserTextbookPaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
+            // 绑定userPaperId,用于关联report
+            Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
+            Transform.combine(pr, userPaperMap, UserTextbookPaperDto.class, "id", "userPaperId");
+
+            // 获取最后一次作业结果
+            Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
+            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            Transform.combine(pr, reportList, UserTextbookPaperDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
+        }
+
+        return ResponseHelp.success(pr);
+    }
 }
 }

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

@@ -1,5 +0,0 @@
-package com.qxgmat.controller.api;
-
-public class WechatController {
-
-}

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

@@ -0,0 +1,37 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+
+@Dto(entity = UserOrderRecord.class)
+public class CourseStudentOnlineDto {
+    private Integer userId;
+
+    private Integer timeId;
+
+    private Integer courseId;
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getTimeId() {
+        return timeId;
+    }
+
+    public void setTimeId(Integer timeId) {
+        this.timeId = timeId;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+}

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

@@ -7,14 +7,18 @@ import com.qxgmat.data.dao.entity.TextbookLibraryHistory;
 public class TextbookLibraryHistoryDto {
 public class TextbookLibraryHistoryDto {
     private Integer libraryId;
     private Integer libraryId;
 
 
-    private String content;
-
     private String quant = "";
     private String quant = "";
 
 
+    private String quantContent = "";
+
     private String ir = "";
     private String ir = "";
 
 
+    private String irContent = "";
+
     private String rc = "";
     private String rc = "";
 
 
+    private String rcContent = "";
+
     public Integer getLibraryId() {
     public Integer getLibraryId() {
         return libraryId;
         return libraryId;
     }
     }
@@ -23,14 +27,6 @@ public class TextbookLibraryHistoryDto {
         this.libraryId = libraryId;
         this.libraryId = libraryId;
     }
     }
 
 
-    public String getContent() {
-        return content;
-    }
-
-    public void setContent(String content) {
-        this.content = content;
-    }
-
     public String getQuant() {
     public String getQuant() {
         return quant;
         return quant;
     }
     }
@@ -54,4 +50,28 @@ public class TextbookLibraryHistoryDto {
     public void setRc(String rc) {
     public void setRc(String rc) {
         this.rc = rc;
         this.rc = rc;
     }
     }
+
+    public String getQuantContent() {
+        return quantContent;
+    }
+
+    public void setQuantContent(String quantContent) {
+        this.quantContent = quantContent;
+    }
+
+    public String getIrContent() {
+        return irContent;
+    }
+
+    public void setIrContent(String irContent) {
+        this.irContent = irContent;
+    }
+
+    public String getRcContent() {
+        return rcContent;
+    }
+
+    public void setRcContent(String rcContent) {
+        this.rcContent = rcContent;
+    }
 }
 }

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

@@ -1,12 +1,12 @@
 package com.qxgmat.dto.admin.response;
 package com.qxgmat.dto.admin.response;
 
 
 import com.nuliji.tools.annotation.Dto;
 import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.CourseStudentOnline;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
 import com.qxgmat.dto.admin.extend.CourseTimeExtendDto;
 import com.qxgmat.dto.admin.extend.CourseTimeExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 
 
 
 
-@Dto(entity = CourseStudentOnline.class)
+@Dto(entity = UserOrderRecord.class)
 public class CourseStudentOnlineListDto {
 public class CourseStudentOnlineListDto {
     private Integer id;
     private Integer id;
 
 
@@ -18,7 +18,7 @@ public class CourseStudentOnlineListDto {
 
 
     private CourseTimeExtendDto time;
     private CourseTimeExtendDto time;
 
 
-    private Integer courseId;
+    private Integer productId;
 
 
     public Integer getId() {
     public Integer getId() {
         return id;
         return id;
@@ -44,27 +44,27 @@ public class CourseStudentOnlineListDto {
         this.user = user;
         this.user = user;
     }
     }
 
 
-    public Integer getTimeId() {
-        return timeId;
+    public CourseTimeExtendDto getTime() {
+        return time;
     }
     }
 
 
-    public void setTimeId(Integer timeId) {
-        this.timeId = timeId;
+    public void setTime(CourseTimeExtendDto time) {
+        this.time = time;
     }
     }
 
 
-    public Integer getCourseId() {
-        return courseId;
+    public Integer getProductId() {
+        return productId;
     }
     }
 
 
-    public void setCourseId(Integer courseId) {
-        this.courseId = courseId;
+    public void setProductId(Integer productId) {
+        this.productId = productId;
     }
     }
 
 
-    public CourseTimeExtendDto getTime() {
-        return time;
+    public Integer getTimeId() {
+        return timeId;
     }
     }
 
 
-    public void setTime(CourseTimeExtendDto time) {
-        this.time = time;
+    public void setTimeId(Integer timeId) {
+        this.timeId = timeId;
     }
     }
 }
 }

+ 140 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserCourseAppointmentExtendDto.java

@@ -0,0 +1,140 @@
+package com.qxgmat.dto.extend;
+
+import com.alibaba.fastjson.JSONArray;
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserCourseAppointment;
+
+import java.util.Date;
+
+@Dto(entity = UserCourseAppointment.class)
+public class UserCourseAppointmentExtendDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer no;
+
+    private String title;
+
+    private Integer recordId;
+
+    private Integer courseId;
+
+    private String cctalkChannel;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Integer paperId;
+
+    private Integer isFinish;
+
+    private JSONArray supplyList;
+
+    private JSONArray noteList;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getNo() {
+        return no;
+    }
+
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public String getCctalkChannel() {
+        return cctalkChannel;
+    }
+
+    public void setCctalkChannel(String cctalkChannel) {
+        this.cctalkChannel = cctalkChannel;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
+    }
+
+    public JSONArray getSupplyList() {
+        return supplyList;
+    }
+
+    public void setSupplyList(JSONArray supplyList) {
+        this.supplyList = supplyList;
+    }
+
+    public JSONArray getNoteList() {
+        return noteList;
+    }
+
+    public void setNoteList(JSONArray noteList) {
+        this.noteList = noteList;
+    }
+}

+ 109 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserServiceRecordExtendDto.java

@@ -0,0 +1,109 @@
+package com.qxgmat.dto.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+
+import java.util.Date;
+
+@Dto(entity = UserOrderRecord.class)
+public class UserServiceRecordExtendDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer isSubscribe;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    private Integer isUsed;
+
+    private Date useTime;
+
+    private Date createTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getIsSubscribe() {
+        return isSubscribe;
+    }
+
+    public void setIsSubscribe(Integer isSubscribe) {
+        this.isSubscribe = isSubscribe;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getIsUsed() {
+        return isUsed;
+    }
+
+    public void setIsUsed(Integer isUsed) {
+        this.isUsed = isUsed;
+    }
+
+    public Date getUseTime() {
+        return useTime;
+    }
+
+    public void setUseTime(Date useTime) {
+        this.useTime = useTime;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}

+ 73 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserTextbookGroupExtendDto.java

@@ -0,0 +1,73 @@
+package com.qxgmat.dto.extend;
+
+public class UserTextbookGroupExtendDto {
+    private String logic;
+
+    private String title;
+
+    private Integer questionNumber;
+
+    private Integer userNumber;
+
+    private Integer minTimes;
+
+    private Integer userPaperId;
+
+    private UserReportExtendDto report;
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getQuestionNumber() {
+        return questionNumber;
+    }
+
+    public void setQuestionNumber(Integer questionNumber) {
+        this.questionNumber = questionNumber;
+    }
+
+    public Integer getUserNumber() {
+        return userNumber;
+    }
+
+    public void setUserNumber(Integer userNumber) {
+        this.userNumber = userNumber;
+    }
+
+    public Integer getMinTimes() {
+        return minTimes;
+    }
+
+    public void setMinTimes(Integer minTimes) {
+        this.minTimes = minTimes;
+    }
+
+    public UserReportExtendDto getReport() {
+        return report;
+    }
+
+    public void setReport(UserReportExtendDto report) {
+        this.report = report;
+    }
+
+    public Integer getUserPaperId() {
+        return userPaperId;
+    }
+
+    public void setUserPaperId(Integer userPaperId) {
+        this.userPaperId = userPaperId;
+    }
+
+    public String getLogic() {
+        return logic;
+    }
+
+    public void setLogic(String logic) {
+        this.logic = logic;
+    }
+}

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

@@ -7,6 +7,7 @@ import io.swagger.annotations.ApiModelProperty;
  * Created by GaoJie on 2017/11/1.
  * Created by GaoJie on 2017/11/1.
  */
  */
 public class MyDto extends UserDto {
 public class MyDto extends UserDto {
+    private Integer id;
 
 
     private String nickname;
     private String nickname;
 
 
@@ -130,4 +131,13 @@ public class MyDto extends UserDto {
     public void setVip(Boolean vip) {
     public void setVip(Boolean vip) {
         this.vip = vip;
         this.vip = vip;
     }
     }
+
+    @Override
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
 }
 }

+ 18 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/PaperBaseDto.java

@@ -11,6 +11,8 @@ public class PaperBaseDto {
     private String title;
     private String title;
     private Integer time;
     private Integer time;
     private Integer questionNumber;
     private Integer questionNumber;
+    private Integer times;
+    private Integer isAdapt;
 
 
     public Integer getQuestionNumber() {
     public Integer getQuestionNumber() {
         return questionNumber;
         return questionNumber;
@@ -59,4 +61,20 @@ public class PaperBaseDto {
     public void setTime(Integer time) {
     public void setTime(Integer time) {
         this.time = time;
         this.time = time;
     }
     }
+
+    public Integer getIsAdapt() {
+        return isAdapt;
+    }
+
+    public void setIsAdapt(Integer isAdapt) {
+        this.isAdapt = isAdapt;
+    }
+
+    public Integer getTimes() {
+        return times;
+    }
+
+    public void setTimes(Integer times) {
+        this.times = times;
+    }
 }
 }

+ 102 - 21
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseDetailDto.java

@@ -1,21 +1,38 @@
 package com.qxgmat.dto.response;
 package com.qxgmat.dto.response;
 
 
 import com.nuliji.tools.annotation.Dto;
 import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.UserCourse;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.dto.extend.CourseExtendDto;
 import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
 import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
 
 
 import java.util.Date;
 import java.util.Date;
 import java.util.List;
 import java.util.List;
 
 
-@Dto(entity = UserCourse.class)
+@Dto(entity = UserOrderRecord.class)
 public class UserCourseDetailDto {
 public class UserCourseDetailDto {
-    private Integer courseId;
+    private Integer id;
+
+    private Integer productId;
+
+    private CourseExtendDto course;
 
 
     private Date startTime;
     private Date startTime;
 
 
-    private Date expireTime;
+    private Date endTime;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    private Integer isUse;
+
+    private Integer isStop;
 
 
-    private Boolean payed;
+    private Integer isSuspend;
+
+    private Date suspendTime;
+
+    private Date restoreTime;
 
 
     private List<UserPaperBaseExtendDto> papers;
     private List<UserPaperBaseExtendDto> papers;
 
 
@@ -27,35 +44,99 @@ public class UserCourseDetailDto {
         this.startTime = startTime;
         this.startTime = startTime;
     }
     }
 
 
-    public Date getExpireTime() {
-        return expireTime;
+    public List<UserPaperBaseExtendDto> getPapers() {
+        return papers;
+    }
+
+    public void setPapers(List<UserPaperBaseExtendDto> papers) {
+        this.papers = papers;
     }
     }
 
 
-    public void setExpireTime(Date expireTime) {
-        this.expireTime = expireTime;
+    public Integer getId() {
+        return id;
     }
     }
 
 
-    public Boolean getPayed() {
-        return payed;
+    public void setId(Integer id) {
+        this.id = id;
     }
     }
 
 
-    public void setPayed(Boolean payed) {
-        this.payed = payed;
+    public Integer getProductId() {
+        return productId;
     }
     }
 
 
-    public List<UserPaperBaseExtendDto> getPapers() {
-        return papers;
+    public void setProductId(Integer productId) {
+        this.productId = productId;
     }
     }
 
 
-    public void setPapers(List<UserPaperBaseExtendDto> papers) {
-        this.papers = papers;
+    public CourseExtendDto getCourse() {
+        return course;
+    }
+
+    public void setCourse(CourseExtendDto course) {
+        this.course = course;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getIsUse() {
+        return isUse;
+    }
+
+    public void setIsUse(Integer isUse) {
+        this.isUse = isUse;
+    }
+
+    public Integer getIsStop() {
+        return isStop;
+    }
+
+    public void setIsStop(Integer isStop) {
+        this.isStop = isStop;
+    }
+
+    public Integer getIsSuspend() {
+        return isSuspend;
+    }
+
+    public void setIsSuspend(Integer isSuspend) {
+        this.isSuspend = isSuspend;
+    }
+
+    public Date getSuspendTime() {
+        return suspendTime;
+    }
+
+    public void setSuspendTime(Date suspendTime) {
+        this.suspendTime = suspendTime;
     }
     }
 
 
-    public Integer getCourseId() {
-        return courseId;
+    public Date getRestoreTime() {
+        return restoreTime;
     }
     }
 
 
-    public void setCourseId(Integer courseId) {
-        this.courseId = courseId;
+    public void setRestoreTime(Date restoreTime) {
+        this.restoreTime = restoreTime;
     }
     }
 }
 }

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


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