1
0
Go 5 лет назад
Родитель
Сommit
ffeffec5b5
100 измененных файлов с 7338 добавлено и 242 удалено
  1. 31 0
      front/project/Constant.js
  2. 9 0
      front/project/admin/app.js
  3. 276 0
      front/project/admin/app.less
  4. 6 1
      front/project/admin/index.js
  5. 2 2
      front/project/admin/routes/course/askDetail/page.js
  6. 15 0
      front/project/admin/routes/course/data/index.js
  7. 3 0
      front/project/admin/routes/course/data/index.less
  8. 142 0
      front/project/admin/routes/course/data/page.js
  9. 16 0
      front/project/admin/routes/course/dataDetail/index.js
  10. 3 0
      front/project/admin/routes/course/dataDetail/index.less
  11. 373 0
      front/project/admin/routes/course/dataDetail/page.js
  12. 16 0
      front/project/admin/routes/course/detail/index.js
  13. 19 0
      front/project/admin/routes/course/detail/index.less
  14. 717 0
      front/project/admin/routes/course/detail/page.js
  15. 15 0
      front/project/admin/routes/course/experience/index.js
  16. 3 0
      front/project/admin/routes/course/experience/index.less
  17. 189 0
      front/project/admin/routes/course/experience/page.js
  18. 16 0
      front/project/admin/routes/course/experienceDetail/index.js
  19. 3 0
      front/project/admin/routes/course/experienceDetail/index.less
  20. 105 0
      front/project/admin/routes/course/experienceDetail/page.js
  21. 7 1
      front/project/admin/routes/course/index.js
  22. 213 1
      front/project/admin/routes/course/list/page.js
  23. 1 2
      front/project/admin/routes/course/package/page.js
  24. 16 0
      front/project/admin/routes/course/student/index.js
  25. 3 0
      front/project/admin/routes/course/student/index.less
  26. 199 0
      front/project/admin/routes/course/student/page.js
  27. 1 1
      front/project/admin/routes/setting/comment/page.js
  28. 5 20
      front/project/admin/routes/setting/index/page.js
  29. 16 16
      front/project/admin/routes/setting/promote/page.js
  30. 9 9
      front/project/admin/routes/setting/service/page.js
  31. 1 26
      front/project/admin/routes/subject/preview/page.js
  32. 3 3
      front/project/admin/routes/subject/textbookLibrary/page.js
  33. 2 2
      front/project/admin/routes/user/askDetail/page.js
  34. 3 2
      front/project/admin/routes/user/index.js
  35. 3 3
      front/project/admin/routes/user/pay/index.js
  36. 1 1
      front/project/admin/routes/user/pay/index.less
  37. 0 0
      front/project/admin/routes/user/order/page.js
  38. 15 0
      front/project/admin/routes/user/orderDetail/index.js
  39. 3 0
      front/project/admin/routes/user/orderDetail/index.less
  40. 39 0
      front/project/admin/routes/user/orderDetail/page.js
  41. 149 1
      front/project/admin/stores/course.js
  42. 8 0
      front/project/admin/stores/system.js
  43. 1 1
      front/project/www/routes/paper/question/page.js
  44. 2 2
      front/project/www/stores/my.js
  45. 2 0
      front/src/containers/Async.js
  46. 8 4
      front/src/services/Api.js
  47. 1 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  48. 1 1
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/CourseModule.java
  49. 5 5
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/PayModule.java
  50. 17 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/user/DataType.java
  51. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseDataHistoryMapper.java
  52. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseExperienceMapper.java
  53. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseStudentOnlineMapper.java
  54. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseStudentVsMapper.java
  55. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseTeacherMapper.java
  56. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/CourseTimeMapper.java
  57. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/UserCollectExperienceMapper.java
  58. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/UserCourseAppointmentMapper.java
  59. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/UserOrderRecordMapper.java
  60. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/UserServiceRecordMapper.java
  61. 778 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/Course.java
  62. 614 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseData.java
  63. 300 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseDataHistory.java
  64. 291 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseExperience.java
  65. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseNo.java
  66. 12 12
      server/data/src/main/java/com/qxgmat/data/dao/entity/CoursePackage.java
  67. 195 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentOnline.java
  68. 317 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentVs.java
  69. 230 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseTeacher.java
  70. 230 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseTime.java
  71. 0 70
      server/data/src/main/java/com/qxgmat/data/dao/entity/PreviewPaper.java
  72. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/User.java
  73. 42 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserAskQuestion.java
  74. 160 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCollectExperience.java
  75. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourse.java
  76. 335 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourseAppointment.java
  77. 307 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrder.java
  78. 182 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserServiceRecord.java
  79. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserService.java
  80. 34 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseDataHistoryMapper.xml
  81. 36 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseDataMapper.xml
  82. 34 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseExperienceMapper.xml
  83. 39 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseMapper.xml
  84. 5 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseNoMapper.xml
  85. 2 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CoursePackageMapper.xml
  86. 20 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseStudentOnlineMapper.xml
  87. 7 7
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceRecordMapper.xml
  88. 21 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseTeacherMapper.xml
  89. 21 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseTimeMapper.xml
  90. 2 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PreviewPaperMapper.xml
  91. 4 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserAskQuestionMapper.xml
  92. 19 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCollectExperienceMapper.xml
  93. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseAppointmentMapper.xml
  94. 12 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseMapper.xml
  95. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserMapper.xml
  96. 27 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderMapper.xml
  97. 30 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml
  98. 12 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceMapper.xml
  99. 17 0
      server/data/src/main/java/com/qxgmat/data/relation/CourseStudentOnlineRelationMapper.java
  100. 0 0
      server/data/src/main/java/com/qxgmat/data/relation/entity/CourseStudentNumberRelation.java

+ 31 - 0
front/project/Constant.js

@@ -50,6 +50,20 @@ export const ExaminationSubject = [{ short: 'V', value: 'verbal', label: '语文
 
 export const ExaminationOrder = [{ list: ['awa', 'ir', 'quant', 'verbal'] }, { list: ['quant', 'verbal', 'ir', 'awa'] }, { list: ['verbal', 'quant', 'ir', 'awa'] }];
 
+export const DataType = [{ label: '电子', value: 'electron' }, { label: '纸质', value: 'paper' }];
+
+export const ExperienceScore = [{ label: '650+', value: '_650' }, { label: '700+', value: '_700' }, { label: '750+', value: '_750' }];
+
+export const ExperiencePercent = [{ label: '50+', value: '_50' }, { label: '100+', value: '_100' }, { label: '150+', value: '_150' }, { label: '200+', value: '_200' }];
+
+export const CourseModule = [{ label: '视频课程', value: 'video' }, { label: '在线课程', value: 'online' }, { label: '1v1课程', value: 'vs' }];
+
+export const CourseVsType = [{ label: '新手辅导', value: 'novel' }, { label: '诊断辅导', value: '' }, { label: '系统授课', value: 'system' }, { label: '答疑课', value: 'answer' }];
+
+export const CrowdList = [{ label: '新手', value: 'novice' }, { label: '非新手', value: 'veteran' }];
+
+export const CourseStatus = [{ label: '未开始', value: 0 }, { label: '进行中', value: 1 }, { label: '已结束', value: 2 }];
+
 // const content = {
 //   steps: [{
 //     title: '',
@@ -205,3 +219,20 @@ export const ExaminationOrder = [{ list: ['awa', 'ir', 'quant', 'verbal'] }, { l
 //     weiboImage: '',
 //   },
 // };
+
+// service信息
+// const service = {
+//   price: 0,
+//   title: '',
+//   description: '',
+//   expire_info: '',
+//   refund_policy: '',
+//   copyright_notes: '',
+// }
+
+// 心经配置
+// const exerienceInfo = {
+//   score: [],
+//   percent: [],
+//   period: 0,
+// };

+ 9 - 0
front/project/admin/app.js

@@ -0,0 +1,9 @@
+// import React from 'react';
+import './app.less';
+import AdminLeft from '@src/containers/AdminLeft';
+import '@src/layouts/FilterLayout';
+import '@src/layouts/ActionLayout';
+import '@src/layouts/TableLayout';
+
+
+export default class extends AdminLeft { }

+ 276 - 0
front/project/admin/app.less

@@ -0,0 +1,276 @@
+@charset "utf-8";
+@cornflower: #6865fd;
+@cornflower_bg: #e4eaf4;
+@dark-sky-blue: #4292f0;
+@night-blue: #050930;
+@slate-grey: #5e677b;
+@bluey-grey: #8897a8;
+@coral: #f36565;
+@butterscotch: #fcb750;
+@ice-blue: #f7fcff;
+
+@theme_color: @dark-sky-blue;
+@theme_holder_color: #7bb3f3;
+@theme_color_hover: darken(@dark-sky-blue, 10);
+@holder_color: @bluey-grey;
+@base_color: @slate-grey;
+@theme_bg_color: #e9eff8;
+@line_color: #c7d0d9;
+@base_size: 14px;
+@base_bg_color: #f4f4f4;
+@base_select_color: #f4f7fd;
+@content_width: 1000px;
+
+.theme,
+.theme a,
+.theme a:hover {
+  color: @theme_color;
+}
+
+.night {
+  color: @night-blue;
+}
+
+.link {
+  // text-decoration: underline;
+  // text-decoration-style: dashed;
+  // text-decoration-color: @theme_color;
+  border-bottom: 1px dashed @theme_color;
+}
+
+.f-s-16 {
+  font-size: 16px;
+}
+
+.f-s-12 {
+  font-size: 12px;
+}
+
+.t-d-l {
+  text-decoration: underline;
+}
+
+.f-w-b {
+  font-weight: bold;
+}
+
+.t-l {
+  text-align: left;
+}
+
+.t-r {
+  text-align: right;
+}
+
+.t-c {
+  text-align: center;
+}
+
+.f-l {
+  float: left;
+}
+
+.f-r {
+  float: right;
+}
+
+.p-a {
+  position: absolute;
+}
+
+.d-i-b {
+  display: inline-block;
+}
+
+.m-l-5 {
+  margin-left: 5px;
+}
+
+.m-l-1 {
+  margin-left: 10px;
+}
+
+.m-l-2 {
+  margin-left: 20px;
+}
+
+.m-r-5 {
+  margin-right: 5px;
+}
+
+.m-r-1 {
+  margin-right: 10px;
+}
+
+.m-r-2 {
+  margin-right: 20px;
+}
+
+.m-t-5 {
+  margin-top: 5px;
+}
+
+.m-t-1 {
+  margin-top: 10px;
+}
+
+.m-t-2 {
+  margin-top: 20px;
+}
+
+.m-b-5 {
+  margin-bottom: 5px;
+}
+
+.m-b-1 {
+  margin-bottom: 10px;
+}
+
+.m-b-2 {
+  margin-bottom: 20px;
+}
+
+.p-l-5 {
+  padding-left: 5px;
+}
+
+.p-l-1 {
+  padding-left: 10px;
+}
+
+.p-l-2 {
+  padding-left: 20px;
+}
+
+.p-r-5 {
+  padding-right: 5px;
+}
+
+.p-r-1 {
+  padding-right: 10px;
+}
+
+.p-r-2 {
+  padding-right: 10px;
+}
+
+.p-t-5 {
+  padding-top: 5px;
+}
+
+.p-t-1 {
+  padding-top: 10px;
+}
+
+.p-t-2 {
+  padding-top: 20px;
+}
+
+.p-b-5 {
+  padding-bottom: 5px;
+}
+
+.p-b-1 {
+  padding-bottom: 10px;
+}
+
+.p-b-2 {
+  padding-bottom: 20px;
+}
+
+.c-p {
+  cursor: pointer;
+}
+
+.w-1 {
+  width: 10%;
+}
+
+.w-2 {
+  width: 20%;
+}
+
+.w-3 {
+  width: 30%;
+}
+
+.w-4 {
+  width: 40%;
+}
+
+.w-5 {
+  width: 50%;
+}
+
+input,
+textarea {
+  outline: none;
+}
+
+input::-webkit-input-placeholder,
+textarea::-webkit-input-placeholder {
+  color: @holder_color;
+}
+
+.d-i-b {
+  display: inline-block;
+  overflow: hidden;
+}
+
+.nowrap {
+  white-space: nowrap;
+  text-overflow: ellipsis;
+}
+
+body {
+  color: @base_color;
+  font-size: @base_size;
+  line-height: 1.7;
+  font-family: 'PingFang SC', 'Microsoft YaHei', '微软雅黑', 'Hiragino Sans GB', Helvetica, Arial, sans-serif;
+  -webkit-font-smoothing: subpixel-antialiased;
+  background: @base_bg_color;
+}
+
+* {
+  box-sizing: border-box;
+}
+
+html,
+body,
+#root {
+  margin: 0;
+  padding: 0;
+  height: 100%;
+  overflow: hidden;
+  overflow-y: auto;
+
+  #page {
+    height: 100%;
+  }
+
+  #full-page {
+    height: 100%;
+    background: #fff;
+  }
+
+  .content {
+    width: @content_width;
+    margin: 0 auto;
+  }
+}
+
+#root {}
+
+body {
+  .ant-tooltip {
+
+    .ant-tooltip-arrow {
+      border-top-color: #fff;
+    }
+
+    .ant-tooltip-inner {
+      background: #fff;
+      color: @base_color;
+    }
+  }
+}

+ 6 - 1
front/project/admin/index.js

@@ -1,5 +1,10 @@
+// import React from 'react';
+import App from './app';
+
 export default {
-  mode: 'adminLeft',
+  mode: () => {
+    return Promise.resolve({ default: App });
+  },
   rootPath: '/dashboard',
   apiToken: 'token',
   loginAuth(route, { user }) {

+ 2 - 2
front/project/admin/routes/course/askDetail/page.js

@@ -8,7 +8,7 @@ import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
 import { formatFormError, formatDate } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-// import { AskTarget } from '../../../../Constant';
+import { UserUrl } from '../../../../Constant';
 // import { User } from '../../../stores/user';
 import { Course } from '../../../stores/course';
 
@@ -129,7 +129,7 @@ export default class extends Page {
           this.orderQuestion(oldIndex, newIndex);
         }}
         renderItem={(item) => (
-          <List.Item actions={[<Icon type='bars' className='icon' />, <Typography.Text copyable={{ text: 'url' }} />]}>
+          <List.Item actions={[<Icon type='bars' className='icon' />, <Typography.Text copyable={{ text: `${UserUrl}/course/ask?askId=${item.id}` }} />]}>
             <Row style={{ width: '100%' }}>
               <Col span={11}>问题:{item.content}</Col>
               <Col span={11} offset={1}>答复:{item.answer}</Col>

+ 15 - 0
front/project/admin/routes/course/data/index.js

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

+ 3 - 0
front/project/admin/routes/course/data/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#course-data {}

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

@@ -0,0 +1,142 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button } from 'antd';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, formatTreeData } from '@src/services/Tools';
+// import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
+import { DataType, SwitchSelect } from '../../../../Constant';
+// import { User } from '../../../stores/user';
+import { Exercise } from '../../../stores/exercise';
+import { Course } from '../../../stores/course';
+
+const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
+const DataTypeMap = getMap(DataType, 'value', 'label');
+export default class extends Page {
+  init() {
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '创建',
+      render: (item) => {
+        return <Button onClick={() => {
+          linkTo('/course/data/detail');
+        }}>{item.name}</Button>;
+      },
+    }];
+    this.exerciseMap = {};
+    this.filterForm = [{
+      key: 'structId',
+      type: 'tree',
+      allowClear: true,
+      name: '学科',
+      select: [],
+      placeholder: '请选择',
+      number: true,
+    }, {
+      key: 'dataType',
+      type: 'select',
+      allowClear: true,
+      name: '资料形式',
+      select: DataType,
+      placeholder: '请选择',
+    }];
+    this.columns = [
+      {
+        title: '学科',
+        dataIndex: 'structId',
+        render: (text, record) => {
+          return `${record.parentStructId ? `${this.exerciseMap[record.parentStructId]}-` : ''}${this.exerciseMap[record.structId]}`;
+        },
+      },
+      {
+        title: '资料形式',
+        dataIndex: 'dataType',
+        render: (text) => {
+          return DataTypeMap[text] || text;
+        },
+      },
+      {
+        title: '适合新手',
+        dataIndex: 'isNovice',
+        render: (text) => {
+          return SwitchSelectMap[text];
+        },
+      },
+      {
+        title: '原创资料',
+        dataIndex: 'isOriginal',
+        render: (text) => {
+          return SwitchSelectMap[text];
+        },
+      }, {
+        title: '资料名称',
+        dataIndex: 'title',
+      }, {
+        title: '查看人数',
+        dataIndex: 'viewNumber',
+      }, {
+        title: '购买人数',
+        dataIndex: 'saleNumber',
+      }, {
+        title: '操作',
+        dataIndex: 'handler',
+        render: (text, record) => {
+          return <div className="table-button">
+            {(
+              <Link to={`/course/data/detail/${record.id}`}>编辑</Link>
+            )}
+          </div>;
+        },
+      },
+    ];
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
+  }
+
+  initData() {
+    Course.listData(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  renderView() {
+    const { exercise } = this.state;
+    return <Block flex>
+      {exercise && <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />}
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+    </Block>;
+  }
+}

+ 16 - 0
front/project/admin/routes/course/dataDetail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/data/detail',
+  matchPath: '/course/data/detail/:id?',
+  key: 'course-data-detail',
+  title: '资料管理',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'course-data',
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/course/dataDetail/index.less

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

+ 373 - 0
front/project/admin/routes/course/dataDetail/page.js

@@ -0,0 +1,373 @@
+import React from 'react';
+import { Form, Button, Row, Col, Icon, Input, InputNumber, Upload } from 'antd';
+import './index.less';
+import Editor from '@src/components/Editor';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import Radio from '@src/components/Radio';
+import TreeSelect from '@src/components/TreeSelect';
+import EditTableCell from '@src/components/EditTableCell';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { formatFormError, formatTreeData, getMap, formatDate } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { SwitchSelect, DataType } from '../../../../Constant';
+// import { User } from '../../../stores/user';
+import { Exercise } from '../../../stores/exercise';
+import { Course } from '../../../stores/course';
+import { System } from '../../../stores/system';
+
+export default class extends Page {
+  initState() {
+    return { history: false };
+  }
+
+  init() {
+    this.exerciseMap = {};
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '上传pdf文件',
+      render: (item) => {
+        return <Upload
+          showUploadList={false}
+          beforeUpload={(file) => System.uploadImage(file).then((result) => {
+            return Course.addDataHistory({ resource: result.url });
+          }).then(() => {
+            this.refreshHistory();
+          })}
+        >
+          <Button>{item.name}</Button>
+        </Upload>;
+      },
+    }];
+    this.columns = [{
+      title: '上传时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
+      },
+    }, {
+      title: '文件地址',
+      dataIndex: 'resource',
+      render: (text) => {
+        return <a href={text} target='_blank'>下载</a>;
+      },
+    }, {
+      title: '版本名称',
+      dataIndex: 'version',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeHistory('version', record.id, v);
+        }} />;
+      },
+    }, {
+      title: '变更页数',
+      dataIndex: 'changePage',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeHistory('changePage', record.id, v);
+        }} />;
+      },
+    }, {
+      title: '原文',
+      dataIndex: 'originContent',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeHistory('originContent', record.id, v);
+        }} />;
+      },
+    }, {
+      title: '更正为',
+      dataIndex: 'content',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeHistory('content', record.id, v);
+        }} />;
+      },
+    }];
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id');
+
+      this.setState({ exercise: tree });
+    });
+  }
+
+  initData() {
+    const { id } = this.params;
+    let handler;
+    if (id) {
+      handler = Course.getData({ id });
+    } else {
+      handler = Promise.resolve({ structId: 0 });
+    }
+    handler
+      .then(result => {
+        const { setFieldsValue } = this.props.form;
+        result.structId = `${result.structId}`;
+        // getFieldDecorator('id');
+        // getFieldDecorator('structId');
+        // getFieldDecorator('dataType');
+        // getFieldDecorator('isNovice');
+        // getFieldDecorator('isOriginal');
+        // getFieldDecorator('title');
+        // getFieldDecorator('price');
+        // getFieldDecorator('pages');
+        // getFieldDecorator('content');
+        // getFieldDecorator('content');
+        // getFieldDecorator('authorContent');
+        // getFieldDecorator('methondContent');
+        setFieldsValue(result);
+        this.setState({ data: result });
+        if (result.dataType === 'electron') {
+          this.refreshHistory();
+        }
+      });
+  }
+
+  refreshHistory() {
+    const { id } = this.params;
+    Course.listDataHistory({ dataId: id }).then(result => {
+      this.setState({ list: result.list, total: result.total, history: true });
+    });
+  }
+
+  changeHistory(field, id, value) {
+    Course.editDataHistory({ id, [field]: value }).then(() => {
+      this.refreshHistory();
+    });
+  }
+
+  submit() {
+    const { form } = this.props;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        data.parentStructId = this.exerciseMap[data.structId] ? this.exerciseMap[data.structId].parentId : 0;
+        Course.editData(data).then(() => {
+          asyncSMessage('保存成功');
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderBase() {
+    const { exercise, data } = this.state;
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <h1>基本信息</h1>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        {exercise && data.structId && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
+          {getFieldDecorator('structId', {
+            rules: [{
+              required: true, message: '请选择学科',
+            }],
+            initialValue: data.structId,
+          })(
+            <TreeSelect treeData={exercise} />,
+          )}
+        </Form.Item>}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='资料形式'>
+          {getFieldDecorator('dataType', {
+            rules: [{
+              required: true, message: '请选择类型',
+            }],
+          })(
+            <Radio select={DataType} onChange={(e) => {
+              if (e.target.value === 'electron') {
+                this.refreshHistory();
+              } else {
+                this.setState({ history: false });
+              }
+            }} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='适合新手'>
+          {getFieldDecorator('isNovice', {
+            rules: [{
+              required: true, message: '请选择',
+            }],
+          })(
+            <Radio select={SwitchSelect} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='原创资料'>
+          {getFieldDecorator('isOriginal', {
+            rules: [{
+              required: true, message: '请选择',
+            }],
+          })(
+            <Radio select={SwitchSelect} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='资料名称'>
+          {getFieldDecorator('title', {
+            rules: [{
+              required: true, message: '请输入名称',
+            }],
+          })(
+            <Input placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='价格'>
+          {getFieldDecorator('price', {
+            rules: [{
+              required: true, message: '请输入价格',
+            }],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='页数'>
+          {getFieldDecorator('pages', {
+            rules: [{
+              required: true, message: '请输入页数',
+            }],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='链接地址'>
+          {getFieldDecorator('link', {
+            rules: [{
+              required: true, message: '请输入地址',
+            }],
+          })(
+            <Input placeholder='请输入' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderInfo() {
+    const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
+    const cover = getFieldValue('cover');
+    return <Block>
+      <h1>宣传信息</h1>
+      <Form>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='资料封面'>
+          {getFieldDecorator('cover', {
+            rules: [
+              { required: true, message: '上传图片' },
+            ],
+          })(
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                setFieldsValue({ cover: result.url });
+                return Promise.reject();
+              })}
+            >
+              {cover ? <img src={cover} 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: 5 }} wrapperCol={{ span: 16 }} label='摘要介绍'>
+          {getFieldDecorator('description', {
+            rules: [{
+              required: true, message: '请输入摘要',
+            }],
+          })(
+            <Input placeholder='请输入' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderHistory() {
+    return <Block>
+      <h1>资料版本</h1>
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        columns={this.columns}
+        list={this.state.list}
+        pagination={false}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+    </Block>;
+  }
+
+  renderContent() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='资料介绍'>
+          {getFieldDecorator('content', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderAuthor() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='作者介绍'>
+          {getFieldDecorator('authorContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderMethod() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='获取方式'>
+          {getFieldDecorator('methodContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderView() {
+    const { history } = this.state;
+    return <div flex>
+      {this.renderBase()}
+      {this.renderInfo()}
+      {history && this.renderHistory()}
+      {this.renderContent()}
+      {this.renderAuthor()}
+      {this.renderMethod()}
+
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

+ 16 - 0
front/project/admin/routes/course/detail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/detail',
+  matchPath: '/course/detail/:id?',
+  key: 'course-detail',
+  title: '课程管理',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'course',
+  component() {
+    return import('./page');
+  },
+};

+ 19 - 0
front/project/admin/routes/course/detail/index.less

@@ -0,0 +1,19 @@
+@charset "utf-8";
+
+#course-detail {
+
+  .ant-card.plus {
+    text-align: center;
+    cursor: pointer;
+  }
+
+  .ant-card {
+    margin-bottom: 20px;
+  }
+
+  .delete-button {
+    position: absolute;
+    right: 10px;
+    top: 10px;
+  }
+}

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

@@ -0,0 +1,717 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import moment from 'moment';
+import { Form, Input, Button, Row, Col, InputNumber, Upload, DatePicker, Card, Icon } from 'antd';
+import './index.less';
+import Editor from '@src/components/Editor';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import TreeSelect from '@src/components/TreeSelect';
+import EditTableCell from '@src/components/EditTableCell';
+import Radio from '@src/components/Radio';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+// import FileUpload from '@src/components/FileUpload';
+import { formatFormError, formatSeconds, formatTreeData, getMap } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { CrowdList, CourseStatus } from '../../../../Constant';
+import { Course } from '../../../stores/course';
+import { System } from '../../../stores/system';
+import { Exercise } from '../../../stores/exercise';
+
+const CourseStatusMap = getMap(CourseStatus, 'value', 'label');
+
+export default class extends Page {
+  init() {
+    this.exerciseMap = {};
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '上传视频',
+      render: (item) => {
+        return <Upload
+          showUploadList={false}
+          beforeUpload={(file) => System.uploadVideo(file).then((result) => {
+            return Course.addNo({ courseId: this.params.id, resource: result.url, time: result.time });
+          }).then(() => {
+            this.refreshNo();
+          })}
+        >
+          <Button>{item.name}</Button>
+        </Upload>;
+      },
+    }];
+
+    this.noColumns = [{
+      title: '课程序号',
+      dataIndex: 'no',
+    }, {
+      title: '名称',
+      dataIndex: 'title',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeNo('title', record.id, v);
+        }} />;
+      },
+    }, {
+      title: '时长',
+      dataIndex: 'time',
+      render: (text) => {
+        return formatSeconds(text);
+      },
+    }, {
+      title: '视频地址',
+      dataIndex: 'resource',
+      render: (text) => {
+        return <a href={text} target='_blank'>访问</a>;
+      },
+    }, {
+      title: '试用区间',
+      dataIndex: 'originContent',
+      render: (text, record) => {
+        return <EditTableCell value={text} onChange={(v) => {
+          this.changeNo('originContent', record.id, v);
+        }} />;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        const { total } = this.state;
+        return <div className="table-button">
+          {record.no > 1 && (
+            <a onClick={() => {
+              this.changeNo('no', record.id, record.no - 1);
+            }}>上移</a>
+          )}
+          {record.no <= total && (
+            <a onClick={() => {
+              this.changeNo('no', record.id, record.no + 1);
+            }}>下移</a>
+          )}
+          {(
+            <a onClick={() => {
+              this.delNo(record.id);
+            }}>删除</a>
+          )}
+        </div>;
+      },
+    }];
+
+    this.timeColumns = [{
+      title: '时间段',
+      dataIndex: 'time',
+      render: (text, record) => {
+        return <DatePicker.RangePicker value={[record.startTime, record.endTime]} onChange={(value) => {
+          this.changeTime(record.id, { startTime: value[0], endTime: value[1] });
+        }} />;
+      },
+    }, {
+      title: '学员数量',
+      dataIndex: 'studentNumber',
+      render: (text, record) => {
+        return <Link to={`/course/student/${this.params.id}?timeId=${record.id}`}>{text}</Link>;
+      },
+    }, {
+      title: '状态',
+      dataIndex: 'status',
+      render: (text) => {
+        return CourseStatusMap[text] || text;
+      },
+    }];
+
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id');
+
+      this.setState({ exercise: tree });
+    });
+  }
+
+  initData() {
+    const { id } = this.params;
+    const { module } = this.state.search;
+    let handler;
+    if (id) {
+      handler = Course.get({ id });
+    } else {
+      handler = Promise.resolve({ structId: 0, courseModule: module });
+    }
+
+    handler
+      .then(result => {
+        this.setState({ module: result.courseModule });
+        const { form } = this.props;
+        result.structId = `${result.structId}`;
+        // baseContent: null
+        // courseContent: null
+        // courseNoContent: null
+        // crowdContent: null
+        // messageContent: null
+        // pointContent: null
+        // processContent: null
+        // promoteContent: null
+        // serviceContent: null
+        // syllabusContent: null
+        // teacherContent: null
+        // form.getFieldDecorator('id');
+        // form.getFieldDecorator('structId');
+        // form.getFieldDecorator('parentStructId');
+        // form.getFieldDecorator('courseModule');
+        // form.getFieldDecorator('title');
+        // form.getFieldDecorator('price');
+        // form.getFieldDecorator('crowd');
+        // form.getFieldDecorator('teacher');
+        // form.getFieldDecorator('wechatAvatar');
+        // form.getFieldDecorator('minNumber');
+        // form.getFieldDecorator('maxNumber');
+        form.setFieldsValue(result);
+        if (id) {
+          switch (result.courseModule) {
+            case 'video':
+              this.refreshNo();
+              break;
+            case 'online':
+              this.refreshTime();
+              break;
+            case 'vs':
+              this.refreshTeacher();
+              break;
+            default:
+          }
+        }
+        this.setState({ data: result });
+      });
+  }
+
+  refreshNo() {
+    const { id } = this.params;
+    Course.allNo({ courseId: id }).then(result => {
+      this.setState({ list: result, total: result.length, no: true });
+    });
+  }
+
+  changeNo(field, id, value) {
+    Course.editNo({ id, [field]: value }).then(() => {
+      this.refreshNo();
+    });
+  }
+
+  delNo(id) {
+    Course.delNo({ id }).then(() => {
+      this.refreshNo();
+    });
+  }
+
+  refreshTime() {
+    const { id } = this.params;
+    Course.listTime({ courseId: id }).then(result => {
+      result.list = result.list.map(row => {
+        row.startTime = moment(row.startTime);
+        row.endTime = moment(row.endTime);
+        return row;
+      });
+      this.setState({ list: result.list, total: result.total, time: true });
+    });
+  }
+
+  changeTime(id, data) {
+    data.id = id;
+    Course.editTime(data).then(() => {
+      this.refreshTime();
+    });
+  }
+
+  refreshTeacher() {
+    const { id } = this.params;
+    Course.listTeacher({ courseId: id }).then(result => {
+      this.setState({ teachers: result.list, total: result.total, teacher: true });
+    });
+  }
+
+  changeTeacher(field, index, value) {
+    const { teachers } = this.state;
+    teachers[index] = teachers[index] || {};
+    teachers[index][field] = value;
+    this.setState({ teachers });
+  }
+
+  addLength(key, data) {
+    this.state[key] = this.state[key] || [];
+    this.state[key].push(data);
+    this.setState({ [key]: this.state[key] });
+  }
+
+  deleteLength(key, start) {
+    this.state[key] = this.state[key] || [];
+    this.state[key].splice(start, 1);
+    this.setState({ [key]: this.state[key] });
+  }
+
+  submit() {
+    const { form } = this.props;
+    const { module } = this.state;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        data.parentStructId = this.exerciseMap[data.structId] ? this.exerciseMap[data.structId].parentId : 0;
+        data.extend = this.exerciseMap[data.structId] ? this.exerciseMap[data.structId].extend : '';
+        let handler;
+        if (data.id) {
+          handler = Course.edit(data);
+        } else {
+          data.courseModule = module;
+          handler = Course.add(data);
+        }
+        handler.then((result) => {
+          asyncSMessage('保存成功');
+          if (data.id) {
+            linkTo(`/course/detail/${data.id}`);
+          } else {
+            linkTo(`/course/detail/${result.id}`);
+          }
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderVideo() {
+    const { exercise, data } = this.state;
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        {exercise && data.structId && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
+          {getFieldDecorator('structId', {
+            rules: [{
+              required: true, message: '请选择学科',
+            }],
+            initialValue: data.structId,
+          })(
+            <TreeSelect treeData={exercise} />,
+          )}
+        </Form.Item>}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='适合人群'>
+          {getFieldDecorator('crowd', {
+            rules: [
+              { required: true, message: '请选择' },
+            ],
+          })(
+            <Radio select={CrowdList} />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='定价'>
+          {getFieldDecorator('price', {
+            rules: [
+              { required: true, message: '请输入价格' },
+            ],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程名称'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入课程名称' },
+            ],
+          })(
+            <Input placeholder='请输入课程名称' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='教师'>
+          {getFieldDecorator('teacher', {
+            rules: [
+              { required: true, message: '请输入教师' },
+            ],
+          })(
+            <Input placeholder='请输入教师' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderNo() {
+    const { no } = this.state;
+    if (!no) return null;
+    return <Block>
+      <h1>上传正式视频</h1>
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        columns={this.noColumns}
+        list={this.state.list}
+        pagination={false}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+    </Block>;
+  }
+
+  renderInfoVideo() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <h1>课程介绍</h1>
+      <Form>
+        <Form.Item label='老师资历'>
+          {getFieldDecorator('teacherContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='基本参数'>
+          {getFieldDecorator('baseContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='授课内容'>
+          {getFieldDecorator('courseContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='授课重点'>
+          {getFieldDecorator('pointContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='适合人群'>
+          {getFieldDecorator('crowdContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderSyllabus() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='授课大纲'>
+          {getFieldDecorator('syllabusContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderPromote() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block flex>
+      <Form>
+        <Form.Item label='优惠信息'>
+          {getFieldDecorator('promoteContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderOnline() {
+    const { exercise, data } = this.state;
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        {exercise && data.structId && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
+          {getFieldDecorator('structId', {
+            rules: [{
+              required: true, message: '请选择学科',
+            }],
+            initialValue: data.structId,
+          })(
+            <TreeSelect treeData={exercise} />,
+          )}
+        </Form.Item>}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程名称'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入课程名称' },
+            ],
+          })(
+            <Input placeholder='请输入课程名称' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderTime() {
+    const { time, timerange } = this.state;
+    if (!time) return null;
+    return <Block>
+      <h1>课时管理</h1>
+      <TableLayout
+        columns={this.timeColumns}
+        list={this.state.list}
+        pagination={false}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      <Row>
+        <Col span={8}>
+          <Form.Item>
+            <DatePicker.RangePicker value={timerange} onChange={(value) => {
+              this.setState({ timerange: value });
+            }} />
+          </Form.Item>
+        </Col>
+        <Col span={1}>
+          <Form.Item>
+            <Button onClick={() => {
+              Course.addTime({ courseId: this.params.id, startTime: timerange[0], endTime: timerange[1] }).then(() => {
+                this.refreshTime();
+                this.setState({ timerange: null });
+              });
+            }}>添加</Button>
+          </Form.Item>
+        </Col>
+      </Row>
+    </Block>;
+  }
+
+  renderVs() {
+    const { exercise, data } = this.state;
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        {exercise && data.structId && <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
+          {getFieldDecorator('structId', {
+            rules: [{
+              required: true, message: '请选择学科',
+            }],
+            initialValue: data.structId,
+          })(
+            <TreeSelect treeData={exercise} />,
+          )}
+        </Form.Item>}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程名称'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入课程名称' },
+            ],
+          })(
+            <Input placeholder='请输入课程名称' />,
+          )}
+        </Form.Item>
+
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='定价'>
+          {getFieldDecorator('price', {
+            rules: [
+              { required: true, message: '请输入价格' },
+            ],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='最小购买数量'>
+          {getFieldDecorator('minNumber', {
+            rules: [
+              { required: true, message: '请输入最小购买数量' },
+            ],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='最大购买数量'>
+          {getFieldDecorator('maxNumber', {
+            rules: [
+              { required: true, message: '请输入最大购买数量' },
+            ],
+          })(
+            <InputNumber placeholder='请输入' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='有效期'>
+          {getFieldDecorator('expireDays', {
+            rules: [
+              { required: true, message: '请输入有效期' },
+            ],
+          })(
+            <InputNumber placeholder='天/10课时' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderInfoVs() {
+    const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
+    const image = getFieldValue('wechatAvatar') || null;
+    return <Block flex>
+      <h1>课程介绍</h1>
+      <Form>
+        <Form.Item label='服务介绍'>
+          {getFieldDecorator('serviceContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='适合人群'>
+          {getFieldDecorator('crowdContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='课时数'>
+          {getFieldDecorator('courseNoContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='授课流程'>
+          {getFieldDecorator('processContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item label='推广语'>
+          {getFieldDecorator('messageContent', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='微信头像'>
+          {getFieldDecorator('wechatAvatar', {
+            rules: [
+              { required: true, message: '上传图片' },
+            ],
+          })(
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                setFieldsValue({ wechatAvatar: 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>
+    </Block>;
+  }
+
+  renderTeacher() {
+    const { teachers, teacher } = this.state;
+    if (!teacher) return null;
+    return <Block>
+      <h1>授课老师</h1>
+      <Form>
+        <Row>
+          {teachers.map((row, index) => {
+            return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
+              <Button className="delete-button" size="small" onClick={() => {
+                if (row.id) {
+                  Course.delTeacher(row.id).then(() => {
+                    this.deleteLength('teachers', index);
+                  });
+                } else {
+                  this.deleteLength('teachers', index);
+                }
+              }}>
+                <Icon type="delete" />
+              </Button>
+              <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label='姓名'>
+                <Input placeholder='请输入姓名' value={row.realname} onChange={(e) => {
+                  this.changeTeacher('realname', index, e.target.value);
+                }} />
+              </Form.Item>
+              <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label='微信'>
+                <Input placeholder='请输入微信' value={row.wechat} onChange={(e) => {
+                  this.changeTeacher('wechat', index, e.target.value);
+                }} />
+              </Form.Item>
+              <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 15 }} label='二维码'>
+                <Upload
+                  listType="picture-card"
+                  showUploadList={false}
+                  beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                    this.changeTeacher('qr', index, result.url);
+                    return Promise.reject();
+                  })}
+                >
+                  {row.qr ? <img src={row.qr} alt="avatar" /> : <div>
+                    <Icon type={this.state.loading ? 'loading' : 'plus'} />
+                    <div className="ant-upload-text">Upload</div>
+                  </div>}
+                </Upload>
+              </Form.Item>
+              <Button onClick={() => {
+                let handler = null;
+                if (row.id) {
+                  handler = Course.editTeacher(row);
+                } else {
+                  handler = Course.addTeacher(Object.assign({ courseId: this.params.id }, row));
+                }
+                handler.then(() => {
+                  this.refreshTeacher();
+                });
+              }}>{row.id ? '修改' : '添加'}</Button>
+            </Card></Col>;
+          })}
+          <Col span={7} offset={teachers.length % 3 ? 1 : 0}>
+            <Card className="plus" onClick={() => {
+              this.addLength('teachers', { realname: '', wechat: '', qr: '' });
+            }}>
+              <Icon type={'plus'} />
+            </Card>
+          </Col>
+        </Row>
+      </Form>
+    </Block>;
+  }
+
+  renderContent() {
+    switch (this.state.module) {
+      case 'online':
+        return [this.renderOnline(), this.renderTime()];
+      case 'vs':
+        return [this.renderVs(), this.renderInfoVs(), this.renderTeacher()];
+      case 'video':
+        return [this.renderVideo(), this.renderNo(), this.renderInfoVideo(), this.renderSyllabus(), this.renderPromote()];
+      default:
+        return <div />;
+    }
+  }
+
+  renderView() {
+    return <div flex>
+      {this.renderContent()}
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

+ 15 - 0
front/project/admin/routes/course/experience/index.js

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/experience',
+  key: 'course-experience',
+  title: '心经',
+  needLogin: true,
+  module,
+  group,
+  index: true,
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/course/experience/index.less

@@ -0,0 +1,3 @@
+@charset "utf-8";
+
+#course-experience {}

+ 189 - 0
front/project/admin/routes/course/experience/page.js

@@ -0,0 +1,189 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button, Modal, Form, InputNumber, Row, Col } from 'antd';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { formatDate, bindSearch } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { ExperienceScore, ExperiencePercent } from '../../../../Constant';
+import { System } from '../../../stores/system';
+import { Course } from '../../../stores/course';
+import { User } from '../../../stores/user';
+
+
+export default class extends Page {
+  init() {
+    this.filterForm = [
+      {
+        key: 'keyword',
+        type: 'input',
+        allowClear: true,
+        name: '搜索',
+        placeholder: '标题或正文',
+      }, {
+        key: 'userId',
+        type: 'select',
+        name: '用户',
+        allowClear: true,
+        select: [],
+        number: true,
+        placeholder: '请输入',
+      },
+    ];
+    this.actionList = [{
+      key: 'info',
+      name: '数据管理',
+    }, {
+      key: 'add',
+      type: 'primary',
+      name: '创建',
+      render: (item) => {
+        return <Link to='/course/experience/detail'><Button>{item.name}</Button></Link>;
+      },
+    }];
+    this.columns = [{
+      title: '文章标题',
+      dataIndex: 'title',
+    }, {
+      title: '作者',
+      dataIndex: 'user',
+      render: (text) => {
+        return (text || {}).nickname;
+      },
+    }, {
+      title: '录入时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
+      },
+    }, {
+      title: '收藏数',
+      dataIndex: 'collectNumber',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/course/experience/detail/${record.id}`}>编辑</Link>}
+        </div>;
+      },
+    }];
+    System.getExperienceInfo().then(result => {
+      return this.refreshInfo(result);
+    }).then(() => {
+      this.initData();
+    });
+
+    bindSearch(this.filterForm, 'userId', this, (search) => {
+      return User.list(search);
+    }, (row) => {
+      return {
+        title: `${row.nickname}(${row.mobile})`,
+        value: row.id,
+      };
+    }, this.state.search.userId ? Number(this.state.search.userId) : [], null);
+  }
+
+  initData() {
+    Course.listExperience(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  refreshInfo(result) {
+    this.setState({ info: result });
+  }
+
+  infoAction() {
+    const { info = {} } = this.state;
+    this.open(info);
+  }
+
+  changeInfoList(field, index, value) {
+    const { detail } = this.state;
+    if (!detail[field]) detail[field] = [];
+    detail[field][index] = value;
+    this.setState({ detail });
+  }
+
+  changeInfo(field, value) {
+    const { detail } = this.state;
+    detail[field] = value;
+    this.setState({ detail });
+  }
+
+  submitInfo() {
+    const { detail } = this.state;
+    System.setExperienceInfo(detail).then(() => {
+      asyncSMessage('保存成功');
+      this.close(false, 'detail');
+      return this.refreshInfo(detail);
+    });
+  }
+
+  renderView() {
+    return <Block flex>
+      <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      {this.state.detail && <Modal visible closable title='数据管理' onCancel={() => {
+        this.close(false, 'detail');
+      }} onOk={() => {
+        this.submitInfo();
+      }}>
+        <Form>
+          <Form.Item label='考分分布' />
+          <Row>
+            {ExperienceScore.map((row, index) => {
+              return <Col span={8}><Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label={row.label}>
+                <InputNumber value={this.state.detail.score ? this.state.detail.score[index] || 0 : 0} onChange={(value) => {
+                  this.changeInfoList('score', index, value);
+                }} />
+              </Form.Item></Col>;
+            })}
+          </Row>
+          <Row>
+            <Col span={12}><Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 10 }} label={'出分周期'}>
+              <InputNumber value={this.state.detail.period || 0} placeholder={'单位天'} onChange={(value) => {
+                this.changeInfo('period', value);
+              }} />
+            </Form.Item></Col>
+          </Row>
+          <Form.Item label='提分比例' />
+          <Row>
+            {ExperiencePercent.map((row, index) => {
+              return <Col span={8}><Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label={row.label}>
+                <InputNumber value={this.state.detail.percent ? this.state.detail.percent[index] || 0 : 0} onChange={(value) => {
+                  this.changeInfoList('percent', index, value);
+                }} />
+              </Form.Item></Col>;
+            })}
+          </Row>
+        </Form>
+      </Modal>}
+    </Block>;
+  }
+}

+ 16 - 0
front/project/admin/routes/course/experienceDetail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/experience/detail',
+  matchPath: '/course/experience/detail/:id?',
+  key: 'course-experience-detail',
+  title: '心经',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'course-experience',
+  component() {
+    return import('./page');
+  },
+};

+ 3 - 0
front/project/admin/routes/course/experienceDetail/index.less

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

+ 105 - 0
front/project/admin/routes/course/experienceDetail/page.js

@@ -0,0 +1,105 @@
+import React from 'react';
+import { Form, Input, Button, Row, Col } from 'antd';
+import './index.less';
+import Editor from '@src/components/Editor';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import Select from '@src/components/Select';
+// import FileUpload from '@src/components/FileUpload';
+import { formatFormError, generateSearch } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { Course } from '../../../stores/course';
+import { User } from '../../../stores/user';
+
+export default class extends Page {
+  initData() {
+    const { id } = this.params;
+    const { form } = this.props;
+    let handler;
+    if (id) {
+      handler = Course.getExperience({ id });
+    } else {
+      handler = Promise.resolve({});
+    }
+
+    handler
+      .then(result => {
+        generateSearch('userId', {}, this, (search) => {
+          return User.list(search);
+        }, (row) => {
+          return {
+            title: `${row.nickname}(${row.mobile})`,
+            value: row.id,
+          };
+        }, result.userId, null);
+        form.setFieldsValue(result);
+      });
+  }
+
+  submit() {
+    const { form } = this.props;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        let handler;
+        if (data.id) {
+          handler = Course.editExperience(data);
+        } else {
+          handler = Course.addExperience(data);
+        }
+        handler.then(() => {
+          asyncSMessage('保存成功');
+          goBack();
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderBase() {
+    const { getFieldDecorator } = this.props.form;
+    return <Block>
+      <Form>
+        {getFieldDecorator('id')(<input hidden />)}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目'>
+          {getFieldDecorator('title', {
+            rules: [
+              { required: true, message: '请输入名称' },
+            ],
+          })(
+            <Input placeholder='请输入名称' />,
+          )}
+        </Form.Item>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='作者'>
+          {getFieldDecorator('userId', {
+            rules: [
+              { required: true, message: '请选择作者' },
+            ],
+          })(
+            <Select {...this.state.userId} placeholder='请选择作者' />,
+          )}
+        </Form.Item>
+        <Form.Item label='正文'>
+          {getFieldDecorator('content', {
+          })(
+            <Editor placeholder='输入内容' />,
+          )}
+        </Form.Item>
+      </Form>
+    </Block>;
+  }
+
+  renderView() {
+    return <div flex>
+      {this.renderBase()}
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

+ 7 - 1
front/project/admin/routes/course/index.js

@@ -2,6 +2,12 @@ import ask from './ask';
 import askDetail from './askDetail';
 import invoice from './invoice';
 import list from './list';
+import detail from './detail';
+import data from './data';
+import dataDetail from './dataDetail';
+import experience from './experience';
+import experienceDetail from './experienceDetail';
+import student from './student';
 import Package from './package';
 
-export default [ask, askDetail, invoice, list, Package];
+export default [ask, askDetail, invoice, list, detail, data, dataDetail, experience, experienceDetail, student, Package];

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

@@ -1,12 +1,224 @@
 import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button, Modal, Form, Icon, Upload } from 'antd';
 import './index.less';
 import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { formatTreeData, getMap } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { CourseModule } from '../../../../Constant';
+import { System } from '../../../stores/system';
+import { Course } from '../../../stores/course';
+import { Exercise } from '../../../stores/exercise';
+
+const CourseModuleMap = getMap(CourseModule, 'value', 'label');
 
 export default class extends Page {
   init() {
+    this.exerciseMap = {};
+    this.filterForm = [
+      {
+        key: 'structId',
+        type: 'tree',
+        allowClear: true,
+        tree: [],
+        name: '学科',
+        placeholder: '标题或正文',
+      }, {
+        key: 'type',
+        type: 'select',
+        name: '类型',
+        allowClear: true,
+        select: [],
+        placeholder: '请输入',
+      },
+    ];
+    this.actionList = [{
+      key: 'info',
+      name: '首页视频',
+    }, {
+      key: 'addVideo',
+      type: 'primary',
+      name: '创建视频课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=video'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }, {
+      key: 'addOnline',
+      type: 'primary',
+      name: '创建直播课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=online'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }, {
+      key: 'addVs',
+      type: 'primary',
+      name: '创建1vs1课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=vs'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }];
+    this.columns = [{
+      title: '课程种类',
+      dataIndex: 'courseModule',
+      render: (text) => {
+        return CourseModuleMap[text] || text;
+      },
+    }, {
+      title: '学科',
+      dataIndex: 'structId',
+      render: (text, record) => {
+        return `${record.parentStructId ? `${this.exerciseMap[record.parentStructId]}-` : ''}${this.exerciseMap[record.structId]}`;
+      },
+    }, {
+      title: '类型',
+      dataIndex: 'type',
+    }, {
+      title: '课程名称',
+      dataIndex: 'title',
+    }, {
+      title: '售价',
+      dataIndex: 'price',
+    }, {
+      title: '试听人数',
+      dataIndex: 'trailNumber',
+    }, {
+      title: '购买数量(含套餐)',
+      dataIndex: 'saleNumber',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/course/detail/${record.id}`}>编辑</Link>}
+          {<Link to={`/course/student/${record.id}`}>查看学员</Link>}
+        </div>;
+      },
+    }];
+    System.getCourseIndex().then(result => {
+      return this.refreshInfo(result);
+    }).then(() => {
+      this.initData();
+    });
+
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
+  }
+
+  initData() {
+    Course.list(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  refreshInfo(result) {
+    this.setState({ info: result });
+  }
+
+  infoAction() {
+    const { info = {} } = this.state;
+    this.open(info);
+  }
+
+  changeInfo(field, value) {
+    const { detail } = this.state;
+    detail[field] = value;
+    this.setState({ detail });
+  }
+
+  submitInfo() {
+    const { detail } = this.state;
+    System.setCourseIndex(detail).then(() => {
+      asyncSMessage('保存成功');
+      this.close(false, 'detail');
+      return this.refreshInfo(detail);
+    });
   }
 
   renderView() {
-    return <div />;
+    const { exercise } = this.state;
+    return <Block flex>
+      {exercise && <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />}
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      {this.state.detail && <Modal visible closable title='数据管理' onCancel={() => {
+        this.close(false, 'detail');
+      }} onOk={() => {
+        this.submitInfo();
+      }}>
+        <Form>
+          {this.state.uploadErr}
+          <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 10 }} label={'在线课程'} help={this.state.onlineErr}>
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadVideo(file).then((result) => {
+                this.changeInfo('onlineVideo', result.url);
+              }).catch(err => {
+                this.setState({ onlineErr: err.message });
+              })}
+            >
+              {this.state.detail.onlineVideo ? <div>
+                <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">已上传</div>
+              </div> : <div>
+                <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">Upload</div>
+              </div>}
+            </Upload>
+          </Form.Item>
+          <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 10 }} label={'1v1课程'} help={this.state.vsErr}>
+            <Upload
+              listType="picture-card"
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadVideo(file).then((result) => {
+                this.changeInfo('vsVideo', result.url);
+              }).catch(err => {
+                this.setState({ vsErr: err.message });
+              })}
+            >
+              {this.state.detail.vsVideo ? <div>
+                <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">已上传</div>
+              </div> : <div>
+                <Icon type={this.props.core.loading ? 'loading' : 'plus'} />
+                <div className="ant-upload-text">Upload</div>
+              </div>}
+            </Upload>
+          </Form.Item>
+        </Form>
+      </Modal>}
+    </Block>;
   }
 }

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

@@ -76,7 +76,7 @@ export default class extends Page {
       dataIndex: 'price',
     }, {
       title: '销售数量',
-      dataIndex: 'totalNumber',
+      dataIndex: 'saleNumber',
     }, {
       title: '首页推荐',
       dataIndex: 'isSpecial',
@@ -177,7 +177,6 @@ export default class extends Page {
         onAction={key => this.onAction(key)}
       />
       <TableLayout
-        select
         columns={this.columns}
         list={this.state.list}
         pagination={this.state.page}

+ 16 - 0
front/project/admin/routes/course/student/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/student',
+  matchPath: '/course/student/:id?',
+  key: 'course-student-detail',
+  title: '课程管理',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'course-student',
+  component() {
+    return import('./page');
+  },
+};

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

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

+ 199 - 0
front/project/admin/routes/course/student/page.js

@@ -0,0 +1,199 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Button, Modal, Form, InputNumber, Row, Col } from 'antd';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { formatDate, formatTreeData, getMap } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { ExperienceScore, ExperiencePercent } from '../../../../Constant';
+import { System } from '../../../stores/system';
+import { Course } from '../../../stores/course';
+import { Exercise } from '../../../stores/exercise';
+
+
+export default class extends Page {
+  init() {
+    this.filterForm = [
+      {
+        key: 'structId',
+        type: 'input',
+        allowClear: true,
+        name: '搜索',
+        placeholder: '标题或正文',
+      }, {
+        key: 'type',
+        type: 'select',
+        name: '类型',
+        allowClear: true,
+        select: [],
+        placeholder: '请输入',
+      },
+    ];
+    this.actionList = [{
+      key: 'info',
+      name: '首页视频',
+    }, {
+      key: 'addVideo',
+      type: 'primary',
+      name: '创建视频课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=video'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }, {
+      key: 'addOnline',
+      type: 'primary',
+      name: '创建直播课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=online'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }, {
+      key: 'addVs',
+      type: 'primary',
+      name: '创建1vs1课程',
+      render: (item) => {
+        return <Link to='/course/detail?module=vs'><Button type='primary'>{item.name}</Button></Link>;
+      },
+    }];
+    this.columns = [{
+      title: '文章标题',
+      dataIndex: 'title',
+    }, {
+      title: '作者',
+      dataIndex: 'user',
+      render: (text) => {
+        return (text || {}).nickname;
+      },
+    }, {
+      title: '录入时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
+      },
+    }, {
+      title: '收藏数',
+      dataIndex: 'collectNumber',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/course/experience/detail/${record.id}`}>编辑</Link>}
+        </div>;
+      },
+    }];
+    System.getCourseIndex().then(result => {
+      return this.refreshInfo(result);
+    }).then(() => {
+      this.initData();
+    });
+
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
+  }
+
+  initData() {
+    Course.list(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  refreshInfo(result) {
+    this.setState({ info: result });
+  }
+
+  infoAction() {
+    const { info = {} } = this.state;
+    this.open(info);
+  }
+
+  changeInfo(field, value) {
+    const { detail } = this.state;
+    detail[field] = value;
+    this.setState({ detail });
+  }
+
+  submitInfo() {
+    const { detail } = this.state;
+    System.setCourseIndex(detail).then(() => {
+      asyncSMessage('保存成功');
+      this.close(false, 'detail');
+      return this.refreshInfo(detail);
+    });
+  }
+
+  renderView() {
+    const { exercise } = this.state;
+    return <Block flex>
+      {exercise && <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />}
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+      {this.state.detail && <Modal visible closable title='数据管理' onCancel={() => {
+        this.close(false, 'detail');
+      }} onOk={() => {
+        this.submitInfo();
+      }}>
+        <Form>
+          <Form.Item label='考分分布' />
+          <Row>
+            {ExperienceScore.map((row, index) => {
+              return <Col span={8}><Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label={row.label}>
+                <InputNumber value={this.state.detail.score ? this.state.detail.score[index] || 0 : 0} onChange={(value) => {
+                  this.changeInfoList('score', index, value);
+                }} />
+              </Form.Item></Col>;
+            })}
+          </Row>
+          <Row>
+            <Col span={12}><Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 10 }} label={'出分周期'}>
+              <InputNumber value={this.state.detail.period || 0} placeholder={'单位天'} onChange={(value) => {
+                this.changeInfo('period', value);
+              }} />
+            </Form.Item></Col>
+          </Row>
+          <Form.Item label='提分比例' />
+          <Row>
+            {ExperiencePercent.map((row, index) => {
+              return <Col span={8}><Form.Item labelCol={{ span: 10 }} wrapperCol={{ span: 14 }} label={row.label}>
+                <InputNumber value={this.state.detail.percent ? this.state.detail.percent[index] || 0 : 0} onChange={(value) => {
+                  this.changeInfoList('percent', index, value);
+                }} />
+              </Form.Item></Col>;
+            })}
+          </Row>
+        </Form>
+      </Modal>}
+    </Block>;
+  }
+}

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

@@ -46,7 +46,7 @@ export default class extends Page {
       type: 'image',
       name: '学员头像',
       onUpload: ({ file }) => {
-        return System.uploadImage(file).then(url => { return { url }; });
+        return System.uploadImage(file).then(result => { return result; });
       },
     }, {
       key: 'content',

+ 5 - 20
front/project/admin/routes/setting/index/page.js

@@ -190,7 +190,7 @@ export default class extends Page {
                     listType="picture-card"
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`course.${index}.image`]: result });
+                      setFieldsValue({ [`course.${index}.image`]: result.url });
                       return Promise.reject();
                     })}
                   >
@@ -199,11 +199,6 @@ export default class extends Page {
                       <div className="ant-upload-text">Upload</div>
                     </div>}
                   </Upload>,
-                  // <FileUpload type='image'
-                  //   onChange={(file) => System.uploadImage(file).then((result) => {
-                  //     setFieldsValue({ [`class.${index}.image`]: result });
-                  //   })}
-                  // />,
                 )}
               </Form.Item>
             </Card></Col>;
@@ -256,7 +251,7 @@ export default class extends Page {
                     listType="picture-card"
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`claactivityss.${index}.image`]: result });
+                      setFieldsValue({ [`claactivityss.${index}.image`]: result.url });
                       return Promise.reject();
                     })}
                   >
@@ -265,11 +260,6 @@ export default class extends Page {
                       <div className="ant-upload-text">Upload</div>
                     </div>}
                   </Upload>,
-                  // <FileUpload type='image'
-                  //   onChange={(file) => System.uploadImage(file).then((result) => {
-                  //     setFieldsValue({ [`class.${index}.image`]: result });
-                  //   })}
-                  // />,
                 )}
               </Form.Item>
             </Card></Col>;
@@ -322,7 +312,7 @@ export default class extends Page {
                     listType="picture-card"
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`evaluation.${index}.avatar`]: result });
+                      setFieldsValue({ [`evaluation.${index}.avatar`]: result.url });
                       return Promise.reject();
                     })}
                   >
@@ -331,11 +321,6 @@ export default class extends Page {
                       <div className="ant-upload-text">Upload</div>
                     </div>}
                   </Upload>,
-                  // <FileUpload type='image'
-                  //   onChange={(file) => System.uploadImage(file).then((result) => {
-                  //     setFieldsValue({ [`class.${index}.image`]: result });
-                  //   })}
-                  // />,
                 )}
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='评价内容'>
@@ -404,7 +389,7 @@ export default class extends Page {
               showUploadList={false}
               beforeUpload={(file) => {
                 System.uploadImage(file).then((result) => {
-                  setFieldsValue({ 'contact.wechatImage': result });
+                  setFieldsValue({ 'contact.wechatImage': result.url });
                   return Promise.reject();
                 });
               }
@@ -423,7 +408,7 @@ export default class extends Page {
               listType="picture-card"
               showUploadList={false}
               beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                setFieldsValue({ 'contact.weiboImage': result });
+                setFieldsValue({ 'contact.weiboImage': result.url });
                 return Promise.reject();
               })}
             >

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

@@ -15,9 +15,9 @@ export default class extends Page {
         form.getFieldDecorator(`video_list[${index}].number`);
         form.getFieldDecorator(`video_list[${index}].percent`);
       });
-      (result['1v1_list'] || []).forEach((row, index) => {
-        form.getFieldDecorator(`1v1_list[${index}].number`);
-        form.getFieldDecorator(`1v1_list[${index}].percent`);
+      (result.vs_list || []).forEach((row, index) => {
+        form.getFieldDecorator(`vs_list[${index}].number`);
+        form.getFieldDecorator(`vs_list[${index}].percent`);
       });
       (result.gifts || []).forEach((row, index) => {
         form.getFieldDecorator(`gifts[${index}].money`);
@@ -67,7 +67,7 @@ export default class extends Page {
         data.video_list = (data.video_list || []).map(row => {
           return { number: Number(row.number), percent: Number(row.percent) };
         });
-        data['1v1_list'] = (data['1v1_list'] || []).map(row => {
+        data.vs_list = (data.vs_list || []).map(row => {
           return { number: Number(row.number), percent: Number(row.percent) };
         });
         data.gifts = (data.gifts || []).map(row => {
@@ -151,25 +151,25 @@ export default class extends Page {
     </Block>;
   }
 
-  render1vs1() {
+  renderVs() {
     const { getFieldDecorator } = this.props.form;
     const { data } = this.state;
-    const vs = data['1v1_list'] || [];
+    const vss = data.vs || [];
     return <Block>
       <h1>1v1课折扣</h1>
       <Form>
         <Form.Item label='按购买课程数量计算' />
-        {vs.map((row, index) => {
+        {vss.map((row, index) => {
           return <Row>
             <Col span={2}>
               <Form.Item>
-                {getFieldDecorator(`1v1_list[${index}].number`, {
+                {getFieldDecorator(`vs_list[${index}].number`, {
                   rules: [
                     { required: true, message: '输入数量' },
                   ],
                 })(
                   <Input placeholder={'输入数量'} onChange={(value) => {
-                    this.changeMapValue('1v1_list', index, 'number', value);
+                    this.changeMapValue('vs_list', index, 'number', value);
                   }} />,
                 )}
               </Form.Item>
@@ -179,13 +179,13 @@ export default class extends Page {
           </Col>
             <Col span={2}>
               <Form.Item>
-                {getFieldDecorator(`1v1_list[${index}].percent`, {
+                {getFieldDecorator(`vs_list[${index}].percent`, {
                   rules: [
                     { required: true, message: '输入百分比' },
                   ],
                 })(
                   <Input placeholder={'输入百分比'} onChange={(value) => {
-                    this.changeMapValue('1v1_list', index, 'percent', value);
+                    this.changeMapValue('vs_list', index, 'percent', value);
                   }} />,
                 )}
               </Form.Item>
@@ -194,23 +194,23 @@ export default class extends Page {
               %
           </Col>
             <Col span={1} onClick={() => {
-              this.deleteLength('1v1_list', index, 1);
+              this.deleteLength('vs_list', index, 1);
             }}>
               <Button><Icon type="minus" /></Button>
             </Col>
           </Row>;
         })}
         <Button onClick={() => {
-          this.addLength('1v1_list', { number: 0, precent: 0 });
+          this.addLength('vs_list', { number: 0, precent: 0 });
         }}><Icon type={'plus'} /></Button>
         <Form.Item labelCol={{ span: 3 }} wrapperCol={{ span: 16 }} label='促销文案'>
-          {getFieldDecorator('1v1.text', {
+          {getFieldDecorator('vs.text', {
             rules: [
               { required: true, message: '输入促销文案' },
             ],
           })(
             <Input placeholder='满30课时95折' onChange={(value) => {
-              this.changeValue('1v1', 'text', value);
+              this.changeValue('vs', 'text', value);
             }} />,
           )}
         </Form.Item>
@@ -272,7 +272,7 @@ export default class extends Page {
     const { tab } = this.state;
     return <div>
       {this.renderVideo()}
-      {this.render1vs1()}
+      {this.renderVs()}
       {this.renderGift()}
       <Row type="flex" justify="center">
         <Col>

+ 9 - 9
front/project/admin/routes/setting/service/page.js

@@ -98,7 +98,7 @@ export default class extends Page {
 
   renderQxCat() {
     const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
-    const image = getFieldValue('qx_cat.image') || null;
+    const image = getFieldValue('qx_cat_image') || null;
     return <Form>
       <Row>
         <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品价格'>
@@ -169,7 +169,7 @@ export default class extends Page {
         </Form.Item>
 
         <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品图片'>
-          {getFieldDecorator('qx_cat.image', {
+          {getFieldDecorator('qx_cat_image', {
             rules: [
               { required: true, message: '上传图片' },
             ],
@@ -178,7 +178,7 @@ export default class extends Page {
               listType="picture-card"
               showUploadList={false}
               beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                setFieldsValue({ 'qx_cat.image': result });
+                setFieldsValue({ qx_cat_image: result.url });
                 return Promise.reject();
               })}
             >
@@ -195,11 +195,11 @@ export default class extends Page {
 
   renderTextbook() {
     const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
-    const image = getFieldValue('textbook.image') || null;
+    const image = getFieldValue('textbook_image') || null;
     return <Form>
       <Row>
         <Form.Item labelCol={{ span: 4 }} wrapperCol={{ span: 16 }} label='商品图片'>
-          {getFieldDecorator('textbook.image', {
+          {getFieldDecorator('textbook_image', {
             rules: [
               { required: true, message: '上传图片' },
             ],
@@ -208,7 +208,7 @@ export default class extends Page {
               listType="picture-card"
               showUploadList={false}
               beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                setFieldsValue({ 'textbook.image': result });
+                setFieldsValue({ textbook_image: result.url });
                 return Promise.reject();
               })}
             >
@@ -291,10 +291,10 @@ export default class extends Page {
 
   renderVip() {
     const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
-    const image = getFieldValue('vip.image') || null;
+    const image = getFieldValue('vip_image') || null;
     return <Form>
       <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 16 }} label='商品图片'>
-        {getFieldDecorator('vip.image', {
+        {getFieldDecorator('vip_image', {
           rules: [
             { required: true, message: '上传图片' },
           ],
@@ -303,7 +303,7 @@ export default class extends Page {
             listType="picture-card"
             showUploadList={false}
             beforeUpload={(file) => System.uploadImage(file).then((result) => {
-              setFieldsValue({ 'vip.image': result });
+              setFieldsValue({ vip_image: result.url });
               return Promise.reject();
             })}
           >

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

@@ -1,5 +1,5 @@
 import React from 'react';
-import { Button, Upload } from 'antd';
+import { Button } from 'antd';
 import { Link } from 'react-router-dom';
 import './index.less';
 import Page from '@src/containers/Page';
@@ -12,7 +12,6 @@ import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
 import { PreviewStatus } from '../../../../Constant';
 import { Exercise } from '../../../stores/exercise';
 import { Preview } from '../../../stores/preview';
-import { System } from '../../../stores/system';
 
 const filterForm = [
   {
@@ -44,30 +43,6 @@ export default class extends Page {
           linkTo('/subject/preview/detail');
         }}>{item.name}</Button>;
       },
-    }, {
-      key: 'template',
-      name: '下载批量导入模版',
-      render: (item) => {
-        return <a href={`/${encodeURIComponent('预习作业导入模板')}.xlsx`}>{item.name}</a>;
-      },
-    }, {
-      key: 'import',
-      name: '批量导入',
-      render: (item) => {
-        return <Upload
-          showUploadList={false}
-          beforeUpload={(file) => System.uploadImage(file).then((result) => {
-            asyncSMessage(result);
-            return Promise.reject();
-          })}
-        >
-          <Button>{item.name}</Button>
-        </Upload>;
-      },
-    }, {
-      key: 'delete',
-      name: '批量删除',
-      needSelect: 1,
     }];
     this.categoryMap = {};
     this.columns = [{

+ 3 - 3
front/project/admin/routes/subject/textbookLibrary/page.js

@@ -161,7 +161,7 @@ export default class extends Page {
                 listType="text"
                 showUploadList={false}
                 beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                  setFieldsValue({ 'post.quant': result });
+                  setFieldsValue({ 'post.quant': result.url });
                   return Promise.reject();
                 })}
                 onChange={this.handleChange}
@@ -178,7 +178,7 @@ export default class extends Page {
                 listType="text"
                 showUploadList={false}
                 beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                  setFieldsValue({ 'post.rc': result });
+                  setFieldsValue({ 'post.rc': result.url });
                   return Promise.reject();
                 })}
                 onChange={this.handleChange}
@@ -195,7 +195,7 @@ export default class extends Page {
                 listType="text"
                 showUploadList={false}
                 beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                  setFieldsValue({ 'post.ir': result });
+                  setFieldsValue({ 'post.ir': result.url });
                   return Promise.reject();
                 })}
                 onChange={this.handleChange}

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

@@ -8,7 +8,7 @@ import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
 import { formatFormError, formatDate, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { AskTarget, QuestionType } from '../../../../Constant';
+import { UserUrl, AskTarget, QuestionType } from '../../../../Constant';
 // import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
 
@@ -131,7 +131,7 @@ export default class extends Page {
           this.orderQuestion(oldIndex, newIndex);
         }}
         renderItem={(item) => (
-          <List.Item actions={[<Icon type='bars' className='icon' />, <Typography.Text copyable={{ text: 'url' }} />]}>
+          <List.Item actions={[<Icon type='bars' className='icon' />, <Typography.Text copyable={{ text: `${UserUrl}/paper/question/${this.state.data.userQuestionId}?askId=${item.id}` }} />]}>
             <Row style={{ width: '100%' }}>
               <Col span={11}>问题:{item.content}</Col>
               <Col span={11} offset={1}>答复:{item.answer}</Col>

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

@@ -6,8 +6,9 @@ import preview from './preview';
 import exercise from './exercise';
 import examination from './examination';
 import student from './student';
-import pay from './pay';
+import order from './order';
+import orderDetail from './orderDetail';
 import feedback from './feedback';
 import service from './service';
 
-export default [list, detail, ask, askDetail, preview, exercise, examination, student, pay, feedback, service];
+export default [list, detail, ask, askDetail, preview, exercise, examination, student, order, orderDetail, feedback, service];

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

@@ -2,9 +2,9 @@ import module from '../../module';
 import group from '../group';
 
 export default {
-  path: '/user/pay',
-  key: 'user-pay',
-  title: '购买记录',
+  path: '/user/order',
+  key: 'user-order',
+  title: '订单记录',
   needLogin: true,
   module,
   group,

+ 1 - 1
front/project/admin/routes/user/pay/index.less

@@ -1,3 +1,3 @@
 @charset "utf-8";
 
-#user-payList {}
+#user-order {}

front/project/admin/routes/user/pay/page.js → front/project/admin/routes/user/order/page.js


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

@@ -0,0 +1,15 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/user/order/detail/:id',
+  key: 'user-order',
+  title: '订单记录',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'user-order',
+  component() {
+    return import('./page');
+  },
+};

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

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

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

@@ -0,0 +1,39 @@
+import React from 'react';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+
+export default class extends Page {
+  renderProduct() {
+    return <Block>
+      <h1>包含商品</h1>
+    </Block>;
+  }
+
+  renderMoney() {
+    return <Block>
+      <h1>订单金额</h1>
+    </Block>;
+  }
+
+  renderGift() {
+    return <Block>
+      <h1>赠送服务</h1>
+    </Block>;
+  }
+
+  renderTime() {
+    return <Block>
+      <h1>订单时间</h1>
+    </Block>;
+  }
+
+  renderView() {
+    return <div>
+      {this.renderProduct()}
+      {this.renderMoney()}
+      {this.renderGift()}
+      {this.renderTime()}
+    </div>;
+  }
+}

+ 149 - 1
front/project/admin/stores/course.js

@@ -5,6 +5,22 @@ export default class CourseStore extends BaseStore {
     return this.apiGet('/course/list', params);
   }
 
+  add(params) {
+    return this.apiPost('/course/add', params);
+  }
+
+  edit(params) {
+    return this.apiPut('/course/edit', params);
+  }
+
+  get(params) {
+    return this.apiGet('/course/detail', params);
+  }
+
+  del(params) {
+    return this.apiDel('/course/delete', params);
+  }
+
   listAsk(params) {
     return this.apiGet('/course/ask/list', params);
   }
@@ -30,7 +46,139 @@ export default class CourseStore extends BaseStore {
   }
 
   delPackage(params) {
-    return this.apiGet('/course/package/detail', params);
+    return this.apiDel('/course/package/delete', params);
+  }
+
+  listData(params) {
+    return this.apiGet('/course/data/list', params);
+  }
+
+  addData(params) {
+    return this.apiPost('/course/data/add', params);
+  }
+
+  editData(params) {
+    return this.apiPut('/course/data/edit', params);
+  }
+
+  getData(params) {
+    return this.apiGet('/course/data/detail', params);
+  }
+
+  delData(params) {
+    return this.apiDel('/course/data/delete', params);
+  }
+
+  listDataHistory(params) {
+    return this.apiGet('/course/data/history/list', params);
+  }
+
+  addDataHistory(params) {
+    return this.apiPost('/course/data/history/add', params);
+  }
+
+  editDataHistory(params) {
+    return this.apiPut('/course/data/history/edit', params);
+  }
+
+  listExperience(params) {
+    return this.apiGet('/course/experience/list', params);
+  }
+
+  addExperience(params) {
+    return this.apiPost('/course/experience/add', params);
+  }
+
+  editExperience(params) {
+    return this.apiPut('/course/experience/edit', params);
+  }
+
+  getExperience(params) {
+    return this.apiGet('/course/experience/detail', params);
+  }
+
+  delExperience(params) {
+    return this.apiDel('/course/experience/delete', params);
+  }
+
+  listTeacher(params) {
+    return this.apiGet('/course/teacher/list', params);
+  }
+
+  addTeacher(params) {
+    return this.apiPost('/course/teacher/add', params);
+  }
+
+  editTeacher(params) {
+    return this.apiPut('/course/teacher/edit', params);
+  }
+
+  getTeacher(params) {
+    return this.apiGet('/course/teacher/detail', params);
+  }
+
+  delTeacher(params) {
+    return this.apiDel('/course/teacher/delete', params);
+  }
+
+  allNo(params) {
+    return this.apiGet('/course/no/all', params);
+  }
+
+  addNo(params) {
+    return this.apiPost('/course/no/add', params);
+  }
+
+  editNo(params) {
+    return this.apiPut('/course/no/edit', params);
+  }
+
+  getNo(params) {
+    return this.apiGet('/course/no/detail', params);
+  }
+
+  delNo(params) {
+    return this.apiDel('/course/no/delete', params);
+  }
+
+  listTime(params) {
+    return this.apiGet('/course/time/list', params);
+  }
+
+  addTime(params) {
+    return this.apiPost('/course/time/add', params);
+  }
+
+  editTime(params) {
+    return this.apiPut('/course/time/edit', params);
+  }
+
+  getTime(params) {
+    return this.apiGet('/course/time/detail', params);
+  }
+
+  delTime(params) {
+    return this.apiDel('/course/time/delete', params);
+  }
+
+  listStudentOnline(params) {
+    return this.apiGet('/course/student/online/list', params);
+  }
+
+  addStudentOnline(params) {
+    return this.apiPost('/course/student/online/add', params);
+  }
+
+  editStudentOnline(params) {
+    return this.apiPut('/course/student/online/edit', params);
+  }
+
+  getStudentOnline(params) {
+    return this.apiGet('/course/student/online/detail', params);
+  }
+
+  delStudentOnline(params) {
+    return this.apiDel('/course/student/online/delete', params);
   }
 }
 

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

@@ -141,6 +141,14 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/course_promote', params);
   }
 
+  getExperienceInfo() {
+    return this.apiGet('/setting/experience_info');
+  }
+
+  setExperienceInfo(params) {
+    return this.apiPut('/setting/experience_info', params);
+  }
+
   getTips() {
     return this.apiGet('/setting/tips');
   }

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

@@ -115,7 +115,7 @@ export default class extends Page {
   submitAsk() {
     const { userQuestion = {}, ask = {} } = this.state;
     if (ask.originContent === '' || ask.content === '' || ask.target === '') return;
-    My.addQuestionAsk(ask.target, userQuestion.questionModule, ask.originContent, ask.content).then(() => {
+    My.addQuestionAsk(userQuestion.id, ask.target, userQuestion.questionModule, ask.originContent, ask.content).then(() => {
       this.setState({ askModal: false, askOkModal: true });
     }).catch(err => {
       this.setState({ askError: err.message });

+ 2 - 2
front/project/www/stores/my.js

@@ -228,8 +228,8 @@ export default class MyStore extends BaseStore {
    * @param {*} questionNoId
    * @param {*} content
    */
-  addQuestionAsk(target, questionModule, questionNoId, originContent, content) {
-    return this.apiPost('/my/ask/question', { target, questionModule, questionNoId, originContent, content });
+  addQuestionAsk(userQuestionId, target, questionModule, questionNoId, originContent, content) {
+    return this.apiPost('/my/ask/question', { userQuestionId, target, questionModule, questionNoId, originContent, content });
   }
 
   /**

+ 2 - 0
front/src/containers/Async.js

@@ -11,6 +11,8 @@ export default class extends Component {
     if (!this.state.C && this.props.component) {
       this.props.component().then(({ default: component }) => {
         this.setState({ C: this.props.isForm ? Form.create()(component) : component });
+      }).catch(err => {
+        console.log(err);
       });
     }
   }

+ 8 - 4
front/src/services/Api.js

@@ -5,8 +5,8 @@ import { GET, DELETE, FORM } from './Constant';
  */
 const Request = require('superagent');
 
-function OfflineError() {
-  const error = new Error('网络不给力,请重试');
+function OfflineError(message) {
+  const error = new Error(message || '网络不给力,请重试');
   error.Type = 'offline';
   return error;
 }
@@ -65,7 +65,11 @@ export default class {
       }
       request.timeout(30 * 1000).end((error, response) => {
         if (error) {
-          reject(new OfflineError());
+          if (response.body) {
+            reject(response.body);
+          } else {
+            reject(new OfflineError(error));
+          }
         } else {
           resolve(response);
         }
@@ -81,7 +85,7 @@ export default class {
       if (response.ok && response.body) {
         return response.body;
       }
-      throw new OfflineError();
+      throw new OfflineError(response.body ? JSON.parse(response.body) : null);
     });
   }
 }

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

@@ -27,6 +27,7 @@ public enum SettingKey {
     SERVICE_VIP("service_vip"), // vip服务信息
     COURSE_INDEX("course_index"), // 课程首页设置
     COURSE_PROMOTE("course_promote"), // 课程促销
+    EXPERIENCE_INFO("experience_info"), // 心经信息
 
     TIPS("tips"); // 页面提示信息
 

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

@@ -4,7 +4,7 @@ package com.qxgmat.data.constants.enums.module;
 public enum CourseModule {
     VIDEO("video"),
     ONLINE("online"),
-    IVSI("1vs1"),
+    VS("vs"),
     ;
     public String key;
     private CourseModule(String key){

+ 5 - 5
server/data/src/main/java/com/qxgmat/data/constants/enums/module/PayModule.java

@@ -1,17 +1,17 @@
 package com.qxgmat.data.constants.enums.module;
 
-public enum PayModule {
+public enum ProductType {
     SERVICE("service"),
-    CLASS("class"),
+    COURSE("course"),
     DATA("data"),
     ;
     public String key;
-    private PayModule(String key){
+    private ProductType(String key){
         this.key = key;
     }
 
-    public static PayModule ValueOf(String name){
+    public static ProductType ValueOf(String name){
         if (name == null) return null;
-        return PayModule.valueOf(name.toUpperCase());
+        return ProductType.valueOf(name.toUpperCase());
     }
 }

+ 17 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/user/DataType.java

@@ -0,0 +1,17 @@
+package com.qxgmat.data.constants.enums.user;
+
+public enum  DataType {
+    ELECTRON("electron"),
+    PAPER("paper"),
+
+    ;
+    public String key;
+    private DataType(String key){
+        this.key = key;
+    }
+
+    public static DataType ValueOf(String name){
+        if (name == null || name.isEmpty()) return null;
+        return DataType.valueOf(name.toUpperCase());
+    }
+}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 import javax.persistence.*;
 
@@ -24,10 +25,16 @@ public class Course implements Serializable {
     private Integer parentStructId;
 
     /**
-     * 题型:从struct上获取extend
+     * 课程类型
      */
-    @Column(name = "`question_type`")
-    private String questionType;
+    @Column(name = "`course_module`")
+    private String courseModule;
+
+    /**
+     * 从struct上继承extend
+     */
+    @Column(name = "`extend`")
+    private String extend;
 
     /**
      * 课程名称
@@ -35,9 +42,132 @@ public class Course implements Serializable {
     @Column(name = "`title`")
     private String title;
 
+    /**
+     * 适合人群
+     */
+    @Column(name = "`crowd`")
+    private String crowd;
+
+    /**
+     * 价格
+     */
+    @Column(name = "`price`")
+    private BigDecimal price;
+
+    /**
+     * 授课老师
+     */
+    @Column(name = "`teacher`")
+    private String teacher;
+
+    /**
+     * 最小购买数量
+     */
+    @Column(name = "`min_number`")
+    private Integer minNumber;
+
+    /**
+     * 最大购买数量
+     */
+    @Column(name = "`max_number`")
+    private Integer maxNumber;
+
+    /**
+     * 有效天数
+     */
+    @Column(name = "`expire_days`")
+    private Integer expireDays;
+
+    /**
+     * 微信头像
+     */
+    @Column(name = "`wechat_avatar`")
+    private String wechatAvatar;
+
+    /**
+     * 试听人数
+     */
+    @Column(name = "`trail_number`")
+    private Integer trailNumber;
+
+    /**
+     * 购买数量
+     */
+    @Column(name = "`sale_number`")
+    private Integer saleNumber;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 老师资质
+     */
+    @Column(name = "`teacher_content`")
+    private String teacherContent;
+
+    /**
+     * 基本参数
+     */
+    @Column(name = "`base_content`")
+    private String baseContent;
+
+    /**
+     * 授课内容
+     */
+    @Column(name = "`course_content`")
+    private String courseContent;
+
+    /**
+     * 授课重点
+     */
+    @Column(name = "`point_content`")
+    private String pointContent;
+
+    /**
+     * 适合人群内容
+     */
+    @Column(name = "`crowd_content`")
+    private String crowdContent;
+
+    /**
+     * 授课大纲
+     */
+    @Column(name = "`syllabus_content`")
+    private String syllabusContent;
+
+    /**
+     * 优惠信息
+     */
+    @Column(name = "`promote_content`")
+    private String promoteContent;
+
+    /**
+     * 服务介绍
+     */
+    @Column(name = "`service_content`")
+    private String serviceContent;
+
+    /**
+     * 推广语
+     */
+    @Column(name = "`message_content`")
+    private String messageContent;
+
+    /**
+     * 授课流程
+     */
+    @Column(name = "`process_content`")
+    private String processContent;
+
+    /**
+     * 课时数
+     */
+    @Column(name = "`course_no_content`")
+    private String courseNoContent;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -91,21 +221,39 @@ public class Course implements Serializable {
     }
 
     /**
-     * 获取题型:从struct上获取extend
+     * 获取课程类型
+     *
+     * @return course_module - 课程类型
+     */
+    public String getCourseModule() {
+        return courseModule;
+    }
+
+    /**
+     * 设置课程类型
      *
-     * @return question_type - 题型:从struct上获取extend
+     * @param courseModule 课程类型
      */
-    public String getQuestionType() {
-        return questionType;
+    public void setCourseModule(String courseModule) {
+        this.courseModule = courseModule;
     }
 
     /**
-     * 设置题型:从struct上获取extend
+     * 获取从struct上继承extend
      *
-     * @param questionType 题型:从struct上获取extend
+     * @return extend - 从struct上继承extend
      */
-    public void setQuestionType(String questionType) {
-        this.questionType = questionType;
+    public String getExtend() {
+        return extend;
+    }
+
+    /**
+     * 设置从struct上继承extend
+     *
+     * @param extend 从struct上继承extend
+     */
+    public void setExtend(String extend) {
+        this.extend = extend;
     }
 
     /**
@@ -127,6 +275,168 @@ public class Course implements Serializable {
     }
 
     /**
+     * 获取适合人群
+     *
+     * @return crowd - 适合人群
+     */
+    public String getCrowd() {
+        return crowd;
+    }
+
+    /**
+     * 设置适合人群
+     *
+     * @param crowd 适合人群
+     */
+    public void setCrowd(String crowd) {
+        this.crowd = crowd;
+    }
+
+    /**
+     * 获取价格
+     *
+     * @return price - 价格
+     */
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    /**
+     * 设置价格
+     *
+     * @param price 价格
+     */
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    /**
+     * 获取授课老师
+     *
+     * @return teacher - 授课老师
+     */
+    public String getTeacher() {
+        return teacher;
+    }
+
+    /**
+     * 设置授课老师
+     *
+     * @param teacher 授课老师
+     */
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    /**
+     * 获取最小购买数量
+     *
+     * @return min_number - 最小购买数量
+     */
+    public Integer getMinNumber() {
+        return minNumber;
+    }
+
+    /**
+     * 设置最小购买数量
+     *
+     * @param minNumber 最小购买数量
+     */
+    public void setMinNumber(Integer minNumber) {
+        this.minNumber = minNumber;
+    }
+
+    /**
+     * 获取最大购买数量
+     *
+     * @return max_number - 最大购买数量
+     */
+    public Integer getMaxNumber() {
+        return maxNumber;
+    }
+
+    /**
+     * 设置最大购买数量
+     *
+     * @param maxNumber 最大购买数量
+     */
+    public void setMaxNumber(Integer maxNumber) {
+        this.maxNumber = maxNumber;
+    }
+
+    /**
+     * 获取有效天数
+     *
+     * @return expire_days - 有效天数
+     */
+    public Integer getExpireDays() {
+        return expireDays;
+    }
+
+    /**
+     * 设置有效天数
+     *
+     * @param expireDays 有效天数
+     */
+    public void setExpireDays(Integer expireDays) {
+        this.expireDays = expireDays;
+    }
+
+    /**
+     * 获取微信头像
+     *
+     * @return wechat_avatar - 微信头像
+     */
+    public String getWechatAvatar() {
+        return wechatAvatar;
+    }
+
+    /**
+     * 设置微信头像
+     *
+     * @param wechatAvatar 微信头像
+     */
+    public void setWechatAvatar(String wechatAvatar) {
+        this.wechatAvatar = wechatAvatar;
+    }
+
+    /**
+     * 获取试听人数
+     *
+     * @return trail_number - 试听人数
+     */
+    public Integer getTrailNumber() {
+        return trailNumber;
+    }
+
+    /**
+     * 设置试听人数
+     *
+     * @param trailNumber 试听人数
+     */
+    public void setTrailNumber(Integer trailNumber) {
+        this.trailNumber = trailNumber;
+    }
+
+    /**
+     * 获取购买数量
+     *
+     * @return sale_number - 购买数量
+     */
+    public Integer getSaleNumber() {
+        return saleNumber;
+    }
+
+    /**
+     * 设置购买数量
+     *
+     * @param saleNumber 购买数量
+     */
+    public void setSaleNumber(Integer saleNumber) {
+        this.saleNumber = saleNumber;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -140,6 +450,218 @@ public class Course implements Serializable {
         this.createTime = createTime;
     }
 
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取老师资质
+     *
+     * @return teacher_content - 老师资质
+     */
+    public String getTeacherContent() {
+        return teacherContent;
+    }
+
+    /**
+     * 设置老师资质
+     *
+     * @param teacherContent 老师资质
+     */
+    public void setTeacherContent(String teacherContent) {
+        this.teacherContent = teacherContent;
+    }
+
+    /**
+     * 获取基本参数
+     *
+     * @return base_content - 基本参数
+     */
+    public String getBaseContent() {
+        return baseContent;
+    }
+
+    /**
+     * 设置基本参数
+     *
+     * @param baseContent 基本参数
+     */
+    public void setBaseContent(String baseContent) {
+        this.baseContent = baseContent;
+    }
+
+    /**
+     * 获取授课内容
+     *
+     * @return course_content - 授课内容
+     */
+    public String getCourseContent() {
+        return courseContent;
+    }
+
+    /**
+     * 设置授课内容
+     *
+     * @param courseContent 授课内容
+     */
+    public void setCourseContent(String courseContent) {
+        this.courseContent = courseContent;
+    }
+
+    /**
+     * 获取授课重点
+     *
+     * @return point_content - 授课重点
+     */
+    public String getPointContent() {
+        return pointContent;
+    }
+
+    /**
+     * 设置授课重点
+     *
+     * @param pointContent 授课重点
+     */
+    public void setPointContent(String pointContent) {
+        this.pointContent = pointContent;
+    }
+
+    /**
+     * 获取适合人群内容
+     *
+     * @return crowd_content - 适合人群内容
+     */
+    public String getCrowdContent() {
+        return crowdContent;
+    }
+
+    /**
+     * 设置适合人群内容
+     *
+     * @param crowdContent 适合人群内容
+     */
+    public void setCrowdContent(String crowdContent) {
+        this.crowdContent = crowdContent;
+    }
+
+    /**
+     * 获取授课大纲
+     *
+     * @return syllabus_content - 授课大纲
+     */
+    public String getSyllabusContent() {
+        return syllabusContent;
+    }
+
+    /**
+     * 设置授课大纲
+     *
+     * @param syllabusContent 授课大纲
+     */
+    public void setSyllabusContent(String syllabusContent) {
+        this.syllabusContent = syllabusContent;
+    }
+
+    /**
+     * 获取优惠信息
+     *
+     * @return promote_content - 优惠信息
+     */
+    public String getPromoteContent() {
+        return promoteContent;
+    }
+
+    /**
+     * 设置优惠信息
+     *
+     * @param promoteContent 优惠信息
+     */
+    public void setPromoteContent(String promoteContent) {
+        this.promoteContent = promoteContent;
+    }
+
+    /**
+     * 获取服务介绍
+     *
+     * @return service_content - 服务介绍
+     */
+    public String getServiceContent() {
+        return serviceContent;
+    }
+
+    /**
+     * 设置服务介绍
+     *
+     * @param serviceContent 服务介绍
+     */
+    public void setServiceContent(String serviceContent) {
+        this.serviceContent = serviceContent;
+    }
+
+    /**
+     * 获取推广语
+     *
+     * @return message_content - 推广语
+     */
+    public String getMessageContent() {
+        return messageContent;
+    }
+
+    /**
+     * 设置推广语
+     *
+     * @param messageContent 推广语
+     */
+    public void setMessageContent(String messageContent) {
+        this.messageContent = messageContent;
+    }
+
+    /**
+     * 获取授课流程
+     *
+     * @return process_content - 授课流程
+     */
+    public String getProcessContent() {
+        return processContent;
+    }
+
+    /**
+     * 设置授课流程
+     *
+     * @param processContent 授课流程
+     */
+    public void setProcessContent(String processContent) {
+        this.processContent = processContent;
+    }
+
+    /**
+     * 获取课时数
+     *
+     * @return course_no_content - 课时数
+     */
+    public String getCourseNoContent() {
+        return courseNoContent;
+    }
+
+    /**
+     * 设置课时数
+     *
+     * @param courseNoContent 课时数
+     */
+    public void setCourseNoContent(String courseNoContent) {
+        this.courseNoContent = courseNoContent;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -149,9 +671,31 @@ public class Course implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", structId=").append(structId);
         sb.append(", parentStructId=").append(parentStructId);
-        sb.append(", questionType=").append(questionType);
+        sb.append(", courseModule=").append(courseModule);
+        sb.append(", extend=").append(extend);
         sb.append(", title=").append(title);
+        sb.append(", crowd=").append(crowd);
+        sb.append(", price=").append(price);
+        sb.append(", teacher=").append(teacher);
+        sb.append(", minNumber=").append(minNumber);
+        sb.append(", maxNumber=").append(maxNumber);
+        sb.append(", expireDays=").append(expireDays);
+        sb.append(", wechatAvatar=").append(wechatAvatar);
+        sb.append(", trailNumber=").append(trailNumber);
+        sb.append(", saleNumber=").append(saleNumber);
         sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", teacherContent=").append(teacherContent);
+        sb.append(", baseContent=").append(baseContent);
+        sb.append(", courseContent=").append(courseContent);
+        sb.append(", pointContent=").append(pointContent);
+        sb.append(", crowdContent=").append(crowdContent);
+        sb.append(", syllabusContent=").append(syllabusContent);
+        sb.append(", promoteContent=").append(promoteContent);
+        sb.append(", serviceContent=").append(serviceContent);
+        sb.append(", messageContent=").append(messageContent);
+        sb.append(", processContent=").append(processContent);
+        sb.append(", courseNoContent=").append(courseNoContent);
         sb.append("]");
         return sb.toString();
     }
@@ -196,12 +740,22 @@ public class Course implements Serializable {
         }
 
         /**
-         * 设置题型:从struct上获取extend
+         * 设置课程类型
          *
-         * @param questionType 题型:从struct上获取extend
+         * @param courseModule 课程类型
          */
-        public Builder questionType(String questionType) {
-            obj.setQuestionType(questionType);
+        public Builder courseModule(String courseModule) {
+            obj.setCourseModule(courseModule);
+            return this;
+        }
+
+        /**
+         * 设置从struct上继承extend
+         *
+         * @param extend 从struct上继承extend
+         */
+        public Builder extend(String extend) {
+            obj.setExtend(extend);
             return this;
         }
 
@@ -216,6 +770,116 @@ public class Course implements Serializable {
         }
 
         /**
+         * 设置适合人群
+         *
+         * @param crowd 适合人群
+         */
+        public Builder crowd(String crowd) {
+            obj.setCrowd(crowd);
+            return this;
+        }
+
+        /**
+         * 设置适合人群内容
+         *
+         * @param crowdContent 适合人群内容
+         */
+        public Builder crowdContent(String crowdContent) {
+            obj.setCrowdContent(crowdContent);
+            return this;
+        }
+
+        /**
+         * 设置价格
+         *
+         * @param price 价格
+         */
+        public Builder price(BigDecimal price) {
+            obj.setPrice(price);
+            return this;
+        }
+
+        /**
+         * 设置授课老师
+         *
+         * @param teacher 授课老师
+         */
+        public Builder teacher(String teacher) {
+            obj.setTeacher(teacher);
+            return this;
+        }
+
+        /**
+         * 设置老师资质
+         *
+         * @param teacherContent 老师资质
+         */
+        public Builder teacherContent(String teacherContent) {
+            obj.setTeacherContent(teacherContent);
+            return this;
+        }
+
+        /**
+         * 设置最小购买数量
+         *
+         * @param minNumber 最小购买数量
+         */
+        public Builder minNumber(Integer minNumber) {
+            obj.setMinNumber(minNumber);
+            return this;
+        }
+
+        /**
+         * 设置最大购买数量
+         *
+         * @param maxNumber 最大购买数量
+         */
+        public Builder maxNumber(Integer maxNumber) {
+            obj.setMaxNumber(maxNumber);
+            return this;
+        }
+
+        /**
+         * 设置有效天数
+         *
+         * @param expireDays 有效天数
+         */
+        public Builder expireDays(Integer expireDays) {
+            obj.setExpireDays(expireDays);
+            return this;
+        }
+
+        /**
+         * 设置微信头像
+         *
+         * @param wechatAvatar 微信头像
+         */
+        public Builder wechatAvatar(String wechatAvatar) {
+            obj.setWechatAvatar(wechatAvatar);
+            return this;
+        }
+
+        /**
+         * 设置试听人数
+         *
+         * @param trailNumber 试听人数
+         */
+        public Builder trailNumber(Integer trailNumber) {
+            obj.setTrailNumber(trailNumber);
+            return this;
+        }
+
+        /**
+         * 设置购买数量
+         *
+         * @param saleNumber 购买数量
+         */
+        public Builder saleNumber(Integer saleNumber) {
+            obj.setSaleNumber(saleNumber);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {
@@ -223,6 +887,104 @@ public class Course implements Serializable {
             return this;
         }
 
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置基本参数
+         *
+         * @param baseContent 基本参数
+         */
+        public Builder baseContent(String baseContent) {
+            obj.setBaseContent(baseContent);
+            return this;
+        }
+
+        /**
+         * 设置授课内容
+         *
+         * @param courseContent 授课内容
+         */
+        public Builder courseContent(String courseContent) {
+            obj.setCourseContent(courseContent);
+            return this;
+        }
+
+        /**
+         * 设置授课重点
+         *
+         * @param pointContent 授课重点
+         */
+        public Builder pointContent(String pointContent) {
+            obj.setPointContent(pointContent);
+            return this;
+        }
+
+        /**
+         * 设置授课大纲
+         *
+         * @param syllabusContent 授课大纲
+         */
+        public Builder syllabusContent(String syllabusContent) {
+            obj.setSyllabusContent(syllabusContent);
+            return this;
+        }
+
+        /**
+         * 设置优惠信息
+         *
+         * @param promoteContent 优惠信息
+         */
+        public Builder promoteContent(String promoteContent) {
+            obj.setPromoteContent(promoteContent);
+            return this;
+        }
+
+        /**
+         * 设置服务介绍
+         *
+         * @param serviceContent 服务介绍
+         */
+        public Builder serviceContent(String serviceContent) {
+            obj.setServiceContent(serviceContent);
+            return this;
+        }
+
+        /**
+         * 设置推广语
+         *
+         * @param messageContent 推广语
+         */
+        public Builder messageContent(String messageContent) {
+            obj.setMessageContent(messageContent);
+            return this;
+        }
+
+        /**
+         * 设置授课流程
+         *
+         * @param processContent 授课流程
+         */
+        public Builder processContent(String processContent) {
+            obj.setProcessContent(processContent);
+            return this;
+        }
+
+        /**
+         * 设置课时数
+         *
+         * @param courseNoContent 课时数
+         */
+        public Builder courseNoContent(String courseNoContent) {
+            obj.setCourseNoContent(courseNoContent);
+            return this;
+        }
+
         public Course build() {
             return this.obj;
         }

+ 614 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseData.java

@@ -1,6 +1,8 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "course_data")
@@ -10,6 +12,108 @@ public class CourseData implements Serializable {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
+    /**
+     * 资料名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 学科:节点id
+     */
+    @Column(name = "`struct_id`")
+    private Integer structId;
+
+    /**
+     * 上级节点id,0为无上级
+     */
+    @Column(name = "`parent_struct_id`")
+    private Integer parentStructId;
+
+    /**
+     * 资料形式
+     */
+    @Column(name = "`data_type`")
+    private String dataType;
+
+    /**
+     * 适合新手:1适合
+     */
+    @Column(name = "`is_novice`")
+    private Integer isNovice;
+
+    /**
+     * 是否原创:1原创
+     */
+    @Column(name = "`is_original`")
+    private Integer isOriginal;
+
+    /**
+     * 价格
+     */
+    @Column(name = "`price`")
+    private BigDecimal price;
+
+    /**
+     * 页数
+     */
+    @Column(name = "`pages`")
+    private Integer pages;
+
+    /**
+     * 链接
+     */
+    @Column(name = "`link`")
+    private String link;
+
+    /**
+     * 封面图片
+     */
+    @Column(name = "`cover`")
+    private String cover;
+
+    /**
+     * 查看人数
+     */
+    @Column(name = "`view_number`")
+    private Integer viewNumber;
+
+    /**
+     * 销售数量
+     */
+    @Column(name = "`sale_number`")
+    private Integer saleNumber;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 摘要介绍
+     */
+    @Column(name = "`description`")
+    private String description;
+
+    /**
+     * 资料介绍
+     */
+    @Column(name = "`content`")
+    private String content;
+
+    /**
+     * 作者介绍
+     */
+    @Column(name = "`author_content`")
+    private String authorContent;
+
+    /**
+     * 获取介绍
+     */
+    @Column(name = "`method_content`")
+    private String methodContent;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -26,6 +130,322 @@ public class CourseData implements Serializable {
         this.id = id;
     }
 
+    /**
+     * 获取资料名称
+     *
+     * @return title - 资料名称
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置资料名称
+     *
+     * @param title 资料名称
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取学科:节点id
+     *
+     * @return struct_id - 学科:节点id
+     */
+    public Integer getStructId() {
+        return structId;
+    }
+
+    /**
+     * 设置学科:节点id
+     *
+     * @param structId 学科:节点id
+     */
+    public void setStructId(Integer structId) {
+        this.structId = structId;
+    }
+
+    /**
+     * 获取上级节点id,0为无上级
+     *
+     * @return parent_struct_id - 上级节点id,0为无上级
+     */
+    public Integer getParentStructId() {
+        return parentStructId;
+    }
+
+    /**
+     * 设置上级节点id,0为无上级
+     *
+     * @param parentStructId 上级节点id,0为无上级
+     */
+    public void setParentStructId(Integer parentStructId) {
+        this.parentStructId = parentStructId;
+    }
+
+    /**
+     * 获取资料形式
+     *
+     * @return data_type - 资料形式
+     */
+    public String getDataType() {
+        return dataType;
+    }
+
+    /**
+     * 设置资料形式
+     *
+     * @param dataType 资料形式
+     */
+    public void setDataType(String dataType) {
+        this.dataType = dataType;
+    }
+
+    /**
+     * 获取适合新手:1适合
+     *
+     * @return is_novice - 适合新手:1适合
+     */
+    public Integer getIsNovice() {
+        return isNovice;
+    }
+
+    /**
+     * 设置适合新手:1适合
+     *
+     * @param isNovice 适合新手:1适合
+     */
+    public void setIsNovice(Integer isNovice) {
+        this.isNovice = isNovice;
+    }
+
+    /**
+     * 获取是否原创:1原创
+     *
+     * @return is_original - 是否原创:1原创
+     */
+    public Integer getIsOriginal() {
+        return isOriginal;
+    }
+
+    /**
+     * 设置是否原创:1原创
+     *
+     * @param isOriginal 是否原创:1原创
+     */
+    public void setIsOriginal(Integer isOriginal) {
+        this.isOriginal = isOriginal;
+    }
+
+    /**
+     * 获取价格
+     *
+     * @return price - 价格
+     */
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    /**
+     * 设置价格
+     *
+     * @param price 价格
+     */
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    /**
+     * 获取页数
+     *
+     * @return pages - 页数
+     */
+    public Integer getPages() {
+        return pages;
+    }
+
+    /**
+     * 设置页数
+     *
+     * @param pages 页数
+     */
+    public void setPages(Integer pages) {
+        this.pages = pages;
+    }
+
+    /**
+     * 获取链接
+     *
+     * @return link - 链接
+     */
+    public String getLink() {
+        return link;
+    }
+
+    /**
+     * 设置链接
+     *
+     * @param link 链接
+     */
+    public void setLink(String link) {
+        this.link = link;
+    }
+
+    /**
+     * 获取封面图片
+     *
+     * @return cover - 封面图片
+     */
+    public String getCover() {
+        return cover;
+    }
+
+    /**
+     * 设置封面图片
+     *
+     * @param cover 封面图片
+     */
+    public void setCover(String cover) {
+        this.cover = cover;
+    }
+
+    /**
+     * 获取查看人数
+     *
+     * @return view_number - 查看人数
+     */
+    public Integer getViewNumber() {
+        return viewNumber;
+    }
+
+    /**
+     * 设置查看人数
+     *
+     * @param viewNumber 查看人数
+     */
+    public void setViewNumber(Integer viewNumber) {
+        this.viewNumber = viewNumber;
+    }
+
+    /**
+     * 获取销售数量
+     *
+     * @return sale_number - 销售数量
+     */
+    public Integer getSaleNumber() {
+        return saleNumber;
+    }
+
+    /**
+     * 设置销售数量
+     *
+     * @param saleNumber 销售数量
+     */
+    public void setSaleNumber(Integer saleNumber) {
+        this.saleNumber = saleNumber;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取摘要介绍
+     *
+     * @return description - 摘要介绍
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 设置摘要介绍
+     *
+     * @param description 摘要介绍
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    /**
+     * 获取资料介绍
+     *
+     * @return content - 资料介绍
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * 设置资料介绍
+     *
+     * @param content 资料介绍
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    /**
+     * 获取作者介绍
+     *
+     * @return author_content - 作者介绍
+     */
+    public String getAuthorContent() {
+        return authorContent;
+    }
+
+    /**
+     * 设置作者介绍
+     *
+     * @param authorContent 作者介绍
+     */
+    public void setAuthorContent(String authorContent) {
+        this.authorContent = authorContent;
+    }
+
+    /**
+     * 获取获取介绍
+     *
+     * @return method_content - 获取介绍
+     */
+    public String getMethodContent() {
+        return methodContent;
+    }
+
+    /**
+     * 设置获取介绍
+     *
+     * @param methodContent 获取介绍
+     */
+    public void setMethodContent(String methodContent) {
+        this.methodContent = methodContent;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -33,6 +453,24 @@ public class CourseData implements Serializable {
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
+        sb.append(", title=").append(title);
+        sb.append(", structId=").append(structId);
+        sb.append(", parentStructId=").append(parentStructId);
+        sb.append(", dataType=").append(dataType);
+        sb.append(", isNovice=").append(isNovice);
+        sb.append(", isOriginal=").append(isOriginal);
+        sb.append(", price=").append(price);
+        sb.append(", pages=").append(pages);
+        sb.append(", link=").append(link);
+        sb.append(", cover=").append(cover);
+        sb.append(", viewNumber=").append(viewNumber);
+        sb.append(", saleNumber=").append(saleNumber);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", description=").append(description);
+        sb.append(", content=").append(content);
+        sb.append(", authorContent=").append(authorContent);
+        sb.append(", methodContent=").append(methodContent);
         sb.append("]");
         return sb.toString();
     }
@@ -56,6 +494,182 @@ public class CourseData implements Serializable {
             return this;
         }
 
+        /**
+         * 设置资料名称
+         *
+         * @param title 资料名称
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置学科:节点id
+         *
+         * @param structId 学科:节点id
+         */
+        public Builder structId(Integer structId) {
+            obj.setStructId(structId);
+            return this;
+        }
+
+        /**
+         * 设置上级节点id,0为无上级
+         *
+         * @param parentStructId 上级节点id,0为无上级
+         */
+        public Builder parentStructId(Integer parentStructId) {
+            obj.setParentStructId(parentStructId);
+            return this;
+        }
+
+        /**
+         * 设置资料形式
+         *
+         * @param dataType 资料形式
+         */
+        public Builder dataType(String dataType) {
+            obj.setDataType(dataType);
+            return this;
+        }
+
+        /**
+         * 设置适合新手:1适合
+         *
+         * @param isNovice 适合新手:1适合
+         */
+        public Builder isNovice(Integer isNovice) {
+            obj.setIsNovice(isNovice);
+            return this;
+        }
+
+        /**
+         * 设置是否原创:1原创
+         *
+         * @param isOriginal 是否原创:1原创
+         */
+        public Builder isOriginal(Integer isOriginal) {
+            obj.setIsOriginal(isOriginal);
+            return this;
+        }
+
+        /**
+         * 设置价格
+         *
+         * @param price 价格
+         */
+        public Builder price(BigDecimal price) {
+            obj.setPrice(price);
+            return this;
+        }
+
+        /**
+         * 设置页数
+         *
+         * @param pages 页数
+         */
+        public Builder pages(Integer pages) {
+            obj.setPages(pages);
+            return this;
+        }
+
+        /**
+         * 设置链接
+         *
+         * @param link 链接
+         */
+        public Builder link(String link) {
+            obj.setLink(link);
+            return this;
+        }
+
+        /**
+         * 设置封面图片
+         *
+         * @param cover 封面图片
+         */
+        public Builder cover(String cover) {
+            obj.setCover(cover);
+            return this;
+        }
+
+        /**
+         * 设置查看人数
+         *
+         * @param viewNumber 查看人数
+         */
+        public Builder viewNumber(Integer viewNumber) {
+            obj.setViewNumber(viewNumber);
+            return this;
+        }
+
+        /**
+         * 设置销售数量
+         *
+         * @param saleNumber 销售数量
+         */
+        public Builder saleNumber(Integer saleNumber) {
+            obj.setSaleNumber(saleNumber);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置摘要介绍
+         *
+         * @param description 摘要介绍
+         */
+        public Builder description(String description) {
+            obj.setDescription(description);
+            return this;
+        }
+
+        /**
+         * 设置资料介绍
+         *
+         * @param content 资料介绍
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
+        /**
+         * 设置作者介绍
+         *
+         * @param authorContent 作者介绍
+         */
+        public Builder authorContent(String authorContent) {
+            obj.setAuthorContent(authorContent);
+            return this;
+        }
+
+        /**
+         * 设置获取介绍
+         *
+         * @param methodContent 获取介绍
+         */
+        public Builder methodContent(String methodContent) {
+            obj.setMethodContent(methodContent);
+            return this;
+        }
+
         public CourseData build() {
             return this.obj;
         }

+ 300 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseDataHistory.java

@@ -0,0 +1,300 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "course_data_history")
+public class CourseDataHistory implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 资料id
+     */
+    @Column(name = "`data_id`")
+    private Integer dataId;
+
+    /**
+     * 存储地址
+     */
+    @Column(name = "`resource`")
+    private String resource;
+
+    /**
+     * 版本名称
+     */
+    @Column(name = "`version`")
+    private String version;
+
+    /**
+     * 变更页数
+     */
+    @Column(name = "`change_page`")
+    private String changePage;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    /**
+     * 原文
+     */
+    @Column(name = "`origin_content`")
+    private String originContent;
+
+    /**
+     * 更正
+     */
+    @Column(name = "`content`")
+    private String content;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取资料id
+     *
+     * @return data_id - 资料id
+     */
+    public Integer getDataId() {
+        return dataId;
+    }
+
+    /**
+     * 设置资料id
+     *
+     * @param dataId 资料id
+     */
+    public void setDataId(Integer dataId) {
+        this.dataId = dataId;
+    }
+
+    /**
+     * 获取存储地址
+     *
+     * @return resource - 存储地址
+     */
+    public String getResource() {
+        return resource;
+    }
+
+    /**
+     * 设置存储地址
+     *
+     * @param resource 存储地址
+     */
+    public void setResource(String resource) {
+        this.resource = resource;
+    }
+
+    /**
+     * 获取版本名称
+     *
+     * @return version - 版本名称
+     */
+    public String getVersion() {
+        return version;
+    }
+
+    /**
+     * 设置版本名称
+     *
+     * @param version 版本名称
+     */
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    /**
+     * 获取变更页数
+     *
+     * @return change_page - 变更页数
+     */
+    public String getChangePage() {
+        return changePage;
+    }
+
+    /**
+     * 设置变更页数
+     *
+     * @param changePage 变更页数
+     */
+    public void setChangePage(String changePage) {
+        this.changePage = changePage;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 获取原文
+     *
+     * @return origin_content - 原文
+     */
+    public String getOriginContent() {
+        return originContent;
+    }
+
+    /**
+     * 设置原文
+     *
+     * @param originContent 原文
+     */
+    public void setOriginContent(String originContent) {
+        this.originContent = originContent;
+    }
+
+    /**
+     * 获取更正
+     *
+     * @return content - 更正
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * 设置更正
+     *
+     * @param content 更正
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", dataId=").append(dataId);
+        sb.append(", resource=").append(resource);
+        sb.append(", version=").append(version);
+        sb.append(", changePage=").append(changePage);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", originContent=").append(originContent);
+        sb.append(", content=").append(content);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static CourseDataHistory.Builder builder() {
+        return new CourseDataHistory.Builder();
+    }
+
+    public static class Builder {
+        private CourseDataHistory obj;
+
+        public Builder() {
+            this.obj = new CourseDataHistory();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置资料id
+         *
+         * @param dataId 资料id
+         */
+        public Builder dataId(Integer dataId) {
+            obj.setDataId(dataId);
+            return this;
+        }
+
+        /**
+         * 设置存储地址
+         *
+         * @param resource 存储地址
+         */
+        public Builder resource(String resource) {
+            obj.setResource(resource);
+            return this;
+        }
+
+        /**
+         * 设置版本名称
+         *
+         * @param version 版本名称
+         */
+        public Builder version(String version) {
+            obj.setVersion(version);
+            return this;
+        }
+
+        /**
+         * 设置变更页数
+         *
+         * @param changePage 变更页数
+         */
+        public Builder changePage(String changePage) {
+            obj.setChangePage(changePage);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * 设置原文
+         *
+         * @param originContent 原文
+         */
+        public Builder originContent(String originContent) {
+            obj.setOriginContent(originContent);
+            return this;
+        }
+
+        /**
+         * 设置更正
+         *
+         * @param content 更正
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
+        public CourseDataHistory build() {
+            return this.obj;
+        }
+    }
+}

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

@@ -0,0 +1,291 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "course_experience")
+public class CourseExperience implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
+     * 题目
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 阅读量
+     */
+    @Column(name = "`view_number`")
+    private Integer viewNumber;
+
+    /**
+     * 收藏量
+     */
+    @Column(name = "`collect_number`")
+    private Integer collectNumber;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 正文
+     */
+    @Column(name = "`content`")
+    private String content;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取用户id
+     *
+     * @return user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * 获取题目
+     *
+     * @return title - 题目
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置题目
+     *
+     * @param title 题目
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取阅读量
+     *
+     * @return view_number - 阅读量
+     */
+    public Integer getViewNumber() {
+        return viewNumber;
+    }
+
+    /**
+     * 设置阅读量
+     *
+     * @param viewNumber 阅读量
+     */
+    public void setViewNumber(Integer viewNumber) {
+        this.viewNumber = viewNumber;
+    }
+
+    /**
+     * 获取收藏量
+     *
+     * @return collect_number - 收藏量
+     */
+    public Integer getCollectNumber() {
+        return collectNumber;
+    }
+
+    /**
+     * 设置收藏量
+     *
+     * @param collectNumber 收藏量
+     */
+    public void setCollectNumber(Integer collectNumber) {
+        this.collectNumber = collectNumber;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取正文
+     *
+     * @return content - 正文
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * 设置正文
+     *
+     * @param content 正文
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", userId=").append(userId);
+        sb.append(", title=").append(title);
+        sb.append(", viewNumber=").append(viewNumber);
+        sb.append(", collectNumber=").append(collectNumber);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", content=").append(content);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static CourseExperience.Builder builder() {
+        return new CourseExperience.Builder();
+    }
+
+    public static class Builder {
+        private CourseExperience obj;
+
+        public Builder() {
+            this.obj = new CourseExperience();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * 设置题目
+         *
+         * @param title 题目
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置阅读量
+         *
+         * @param viewNumber 阅读量
+         */
+        public Builder viewNumber(Integer viewNumber) {
+            obj.setViewNumber(viewNumber);
+            return this;
+        }
+
+        /**
+         * 设置收藏量
+         *
+         * @param collectNumber 收藏量
+         */
+        public Builder collectNumber(Integer collectNumber) {
+            obj.setCollectNumber(collectNumber);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置正文
+         *
+         * @param content 正文
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
+        public CourseExperience build() {
+            return this.obj;
+        }
+    }
+}

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

@@ -24,6 +24,12 @@ public class CourseNo implements Serializable {
     private Integer no;
 
     /**
+     * 标题
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
      * 资源文件地址
      */
     @Column(name = "`resource`")
@@ -35,6 +41,18 @@ public class CourseNo implements Serializable {
     @Column(name = "`time`")
     private Integer time;
 
+    /**
+     * 试用区间:开始
+     */
+    @Column(name = "`start_trail`")
+    private Integer startTrail;
+
+    /**
+     * 试用区间:结束
+     */
+    @Column(name = "`end_trail`")
+    private Integer endTrail;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -97,6 +115,24 @@ public class CourseNo implements Serializable {
     }
 
     /**
+     * 获取标题
+     *
+     * @return title - 标题
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置标题
+     *
+     * @param title 标题
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
      * 获取资源文件地址
      *
      * @return resource - 资源文件地址
@@ -133,6 +169,42 @@ public class CourseNo implements Serializable {
     }
 
     /**
+     * 获取试用区间:开始
+     *
+     * @return start_trail - 试用区间:开始
+     */
+    public Integer getStartTrail() {
+        return startTrail;
+    }
+
+    /**
+     * 设置试用区间:开始
+     *
+     * @param startTrail 试用区间:开始
+     */
+    public void setStartTrail(Integer startTrail) {
+        this.startTrail = startTrail;
+    }
+
+    /**
+     * 获取试用区间:结束
+     *
+     * @return end_trail - 试用区间:结束
+     */
+    public Integer getEndTrail() {
+        return endTrail;
+    }
+
+    /**
+     * 设置试用区间:结束
+     *
+     * @param endTrail 试用区间:结束
+     */
+    public void setEndTrail(Integer endTrail) {
+        this.endTrail = endTrail;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -173,8 +245,11 @@ public class CourseNo implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", courseId=").append(courseId);
         sb.append(", no=").append(no);
+        sb.append(", title=").append(title);
         sb.append(", resource=").append(resource);
         sb.append(", time=").append(time);
+        sb.append(", startTrail=").append(startTrail);
+        sb.append(", endTrail=").append(endTrail);
         sb.append(", createTime=").append(createTime);
         sb.append(", content=").append(content);
         sb.append("]");
@@ -221,6 +296,16 @@ public class CourseNo implements Serializable {
         }
 
         /**
+         * 设置标题
+         *
+         * @param title 标题
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
          * 设置资源文件地址
          *
          * @param resource 资源文件地址
@@ -241,6 +326,26 @@ public class CourseNo implements Serializable {
         }
 
         /**
+         * 设置试用区间:开始
+         *
+         * @param startTrail 试用区间:开始
+         */
+        public Builder startTrail(Integer startTrail) {
+            obj.setStartTrail(startTrail);
+            return this;
+        }
+
+        /**
+         * 设置试用区间:结束
+         *
+         * @param endTrail 试用区间:结束
+         */
+        public Builder endTrail(Integer endTrail) {
+            obj.setEndTrail(endTrail);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

+ 12 - 12
server/data/src/main/java/com/qxgmat/data/dao/entity/CoursePackage.java

@@ -52,8 +52,8 @@ public class CoursePackage implements Serializable {
     /**
      * 销售数量
      */
-    @Column(name = "`total_number`")
-    private Integer totalNumber;
+    @Column(name = "`sale_number`")
+    private Integer saleNumber;
 
     @Column(name = "`create_time`")
     private Date createTime;
@@ -194,19 +194,19 @@ public class CoursePackage implements Serializable {
     /**
      * 获取销售数量
      *
-     * @return total_number - 销售数量
+     * @return sale_number - 销售数量
      */
-    public Integer getTotalNumber() {
-        return totalNumber;
+    public Integer getSaleNumber() {
+        return saleNumber;
     }
 
     /**
      * 设置销售数量
      *
-     * @param totalNumber 销售数量
+     * @param saleNumber 销售数量
      */
-    public void setTotalNumber(Integer totalNumber) {
-        this.totalNumber = totalNumber;
+    public void setSaleNumber(Integer saleNumber) {
+        this.saleNumber = saleNumber;
     }
 
     /**
@@ -268,7 +268,7 @@ public class CoursePackage implements Serializable {
         sb.append(", courseIds=").append(courseIds);
         sb.append(", isSpecial=").append(isSpecial);
         sb.append(", gift=").append(gift);
-        sb.append(", totalNumber=").append(totalNumber);
+        sb.append(", saleNumber=").append(saleNumber);
         sb.append(", createTime=").append(createTime);
         sb.append(", updateTime=").append(updateTime);
         sb.append(", description=").append(description);
@@ -358,10 +358,10 @@ public class CoursePackage implements Serializable {
         /**
          * 设置销售数量
          *
-         * @param totalNumber 销售数量
+         * @param saleNumber 销售数量
          */
-        public Builder totalNumber(Integer totalNumber) {
-            obj.setTotalNumber(totalNumber);
+        public Builder saleNumber(Integer saleNumber) {
+            obj.setSaleNumber(saleNumber);
             return this;
         }
 

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

@@ -0,0 +1,195 @@
+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;
+        }
+    }
+}

+ 317 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentVs.java

@@ -0,0 +1,317 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "course_student_vs")
+public class CourseStudentVs implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    /**
+     * 教师id
+     */
+    @Column(name = "`teacher_id`")
+    private Integer teacherId;
+
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    @Column(name = "`start_time`")
+    private Date startTime;
+
+    @Column(name = "`end_time`")
+    private Date endTime;
+
+    /**
+     * 添加方式
+     */
+    @Column(name = "`add_method`")
+    private String addMethod;
+
+    /**
+     * 状态:0未开通
+     */
+    @Column(name = "`is_used`")
+    private Integer isUsed;
+
+    @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;
+    }
+
+    /**
+     * 获取教师id
+     *
+     * @return teacher_id - 教师id
+     */
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    /**
+     * 设置教师id
+     *
+     * @param teacherId 教师id
+     */
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    /**
+     * 获取用户id
+     *
+     * @return user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * @return start_time
+     */
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * @param startTime
+     */
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    /**
+     * @return end_time
+     */
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    /**
+     * @param endTime
+     */
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    /**
+     * 获取添加方式
+     *
+     * @return add_method - 添加方式
+     */
+    public String getAddMethod() {
+        return addMethod;
+    }
+
+    /**
+     * 设置添加方式
+     *
+     * @param addMethod 添加方式
+     */
+    public void setAddMethod(String addMethod) {
+        this.addMethod = addMethod;
+    }
+
+    /**
+     * 获取状态:0未开通
+     *
+     * @return is_used - 状态:0未开通
+     */
+    public Integer getIsUsed() {
+        return isUsed;
+    }
+
+    /**
+     * 设置状态:0未开通
+     *
+     * @param isUsed 状态:0未开通
+     */
+    public void setIsUsed(Integer isUsed) {
+        this.isUsed = isUsed;
+    }
+
+    /**
+     * @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(", teacherId=").append(teacherId);
+        sb.append(", userId=").append(userId);
+        sb.append(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", addMethod=").append(addMethod);
+        sb.append(", isUsed=").append(isUsed);
+        sb.append(", createTime=").append(createTime);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static CourseStudentVs.Builder builder() {
+        return new CourseStudentVs.Builder();
+    }
+
+    public static class Builder {
+        private CourseStudentVs obj;
+
+        public Builder() {
+            this.obj = new CourseStudentVs();
+        }
+
+        /**
+         * @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;
+        }
+
+        /**
+         * 设置教师id
+         *
+         * @param teacherId 教师id
+         */
+        public Builder teacherId(Integer teacherId) {
+            obj.setTeacherId(teacherId);
+            return this;
+        }
+
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * @param startTime
+         */
+        public Builder startTime(Date startTime) {
+            obj.setStartTime(startTime);
+            return this;
+        }
+
+        /**
+         * @param endTime
+         */
+        public Builder endTime(Date endTime) {
+            obj.setEndTime(endTime);
+            return this;
+        }
+
+        /**
+         * 设置添加方式
+         *
+         * @param addMethod 添加方式
+         */
+        public Builder addMethod(String addMethod) {
+            obj.setAddMethod(addMethod);
+            return this;
+        }
+
+        /**
+         * 设置状态:0未开通
+         *
+         * @param isUsed 状态:0未开通
+         */
+        public Builder isUsed(Integer isUsed) {
+            obj.setIsUsed(isUsed);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        public CourseStudentVs build() {
+            return this.obj;
+        }
+    }
+}

+ 230 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseTeacher.java

@@ -0,0 +1,230 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "course_teacher")
+public class CourseTeacher implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    /**
+     * 姓名
+     */
+    @Column(name = "`realname`")
+    private String realname;
+
+    /**
+     * 微信号
+     */
+    @Column(name = "`wechat`")
+    private String wechat;
+
+    /**
+     * 微信二维码
+     */
+    @Column(name = "`qr`")
+    private String qr;
+
+    @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 realname - 姓名
+     */
+    public String getRealname() {
+        return realname;
+    }
+
+    /**
+     * 设置姓名
+     *
+     * @param realname 姓名
+     */
+    public void setRealname(String realname) {
+        this.realname = realname;
+    }
+
+    /**
+     * 获取微信号
+     *
+     * @return wechat - 微信号
+     */
+    public String getWechat() {
+        return wechat;
+    }
+
+    /**
+     * 设置微信号
+     *
+     * @param wechat 微信号
+     */
+    public void setWechat(String wechat) {
+        this.wechat = wechat;
+    }
+
+    /**
+     * 获取微信二维码
+     *
+     * @return qr - 微信二维码
+     */
+    public String getQr() {
+        return qr;
+    }
+
+    /**
+     * 设置微信二维码
+     *
+     * @param qr 微信二维码
+     */
+    public void setQr(String qr) {
+        this.qr = qr;
+    }
+
+    /**
+     * @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(", realname=").append(realname);
+        sb.append(", wechat=").append(wechat);
+        sb.append(", qr=").append(qr);
+        sb.append(", createTime=").append(createTime);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static CourseTeacher.Builder builder() {
+        return new CourseTeacher.Builder();
+    }
+
+    public static class Builder {
+        private CourseTeacher obj;
+
+        public Builder() {
+            this.obj = new CourseTeacher();
+        }
+
+        /**
+         * @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 realname 姓名
+         */
+        public Builder realname(String realname) {
+            obj.setRealname(realname);
+            return this;
+        }
+
+        /**
+         * 设置微信号
+         *
+         * @param wechat 微信号
+         */
+        public Builder wechat(String wechat) {
+            obj.setWechat(wechat);
+            return this;
+        }
+
+        /**
+         * 设置微信二维码
+         *
+         * @param qr 微信二维码
+         */
+        public Builder qr(String qr) {
+            obj.setQr(qr);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        public CourseTeacher build() {
+            return this.obj;
+        }
+    }
+}

+ 230 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/CourseTime.java

@@ -0,0 +1,230 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "course_time")
+public class CourseTime implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    /**
+     * 开始时间
+     */
+    @Column(name = "`start_time`")
+    private Date startTime;
+
+    /**
+     * 结束时间
+     */
+    @Column(name = "`end_time`")
+    private Date endTime;
+
+    /**
+     * 状态:0未开始,1进行,2结束
+     */
+    @Column(name = "`status`")
+    private Integer status;
+
+    @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 start_time - 开始时间
+     */
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * 设置开始时间
+     *
+     * @param startTime 开始时间
+     */
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    /**
+     * 获取结束时间
+     *
+     * @return end_time - 结束时间
+     */
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    /**
+     * 设置结束时间
+     *
+     * @param endTime 结束时间
+     */
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    /**
+     * 获取状态:0未开始,1进行,2结束
+     *
+     * @return status - 状态:0未开始,1进行,2结束
+     */
+    public Integer getStatus() {
+        return status;
+    }
+
+    /**
+     * 设置状态:0未开始,1进行,2结束
+     *
+     * @param status 状态:0未开始,1进行,2结束
+     */
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    /**
+     * @return 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(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", status=").append(status);
+        sb.append(", createTime=").append(createTime);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static CourseTime.Builder builder() {
+        return new CourseTime.Builder();
+    }
+
+    public static class Builder {
+        private CourseTime obj;
+
+        public Builder() {
+            this.obj = new CourseTime();
+        }
+
+        /**
+         * @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 startTime 开始时间
+         */
+        public Builder startTime(Date startTime) {
+            obj.setStartTime(startTime);
+            return this;
+        }
+
+        /**
+         * 设置结束时间
+         *
+         * @param endTime 结束时间
+         */
+        public Builder endTime(Date endTime) {
+            obj.setEndTime(endTime);
+            return this;
+        }
+
+        /**
+         * 设置状态:0未开始,1进行,2结束
+         *
+         * @param status 状态:0未开始,1进行,2结束
+         */
+        public Builder status(Integer status) {
+            obj.setStatus(status);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        public CourseTime build() {
+            return this.obj;
+        }
+    }
+}

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

@@ -36,12 +36,6 @@ public class PreviewPaper implements Serializable {
     private Integer[] questionNoIds;
 
     /**
-     * 作业模式:0基础作业,1系统作业(自动发送给课程用户)
-     */
-    @Column(name = "`mode`")
-    private Integer mode;
-
-    /**
      * 题目类型
      */
     @Column(name = "`paper_module`")
@@ -54,12 +48,6 @@ public class PreviewPaper implements Serializable {
     private Integer[] userIds;
 
     /**
-     * 做题时间
-     */
-    @Column(name = "`time`")
-    private Integer time;
-
-    /**
      * 作业开始时间
      */
     @Column(name = "`start_time`")
@@ -172,24 +160,6 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
-     * 获取作业模式:0基础作业,1系统作业(自动发送给课程用户)
-     *
-     * @return mode - 作业模式:0基础作业,1系统作业(自动发送给课程用户)
-     */
-    public Integer getMode() {
-        return mode;
-    }
-
-    /**
-     * 设置作业模式:0基础作业,1系统作业(自动发送给课程用户)
-     *
-     * @param mode 作业模式:0基础作业,1系统作业(自动发送给课程用户)
-     */
-    public void setMode(Integer mode) {
-        this.mode = mode;
-    }
-
-    /**
      * 获取题目类型
      *
      * @return paper_module - 题目类型
@@ -226,24 +196,6 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
-     * 获取做题时间
-     *
-     * @return time - 做题时间
-     */
-    public Integer getTime() {
-        return time;
-    }
-
-    /**
-     * 设置做题时间
-     *
-     * @param time 做题时间
-     */
-    public void setTime(Integer time) {
-        this.time = time;
-    }
-
-    /**
      * 获取作业开始时间
      *
      * @return start_time - 作业开始时间
@@ -336,10 +288,8 @@ public class PreviewPaper implements Serializable {
         sb.append(", courseId=").append(courseId);
         sb.append(", courseNo=").append(courseNo);
         sb.append(", questionNoIds=").append(questionNoIds);
-        sb.append(", mode=").append(mode);
         sb.append(", paperModule=").append(paperModule);
         sb.append(", userIds=").append(userIds);
-        sb.append(", time=").append(time);
         sb.append(", startTime=").append(startTime);
         sb.append(", endTime=").append(endTime);
         sb.append(", finish=").append(finish);
@@ -409,16 +359,6 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
-         * 设置作业模式:0基础作业,1系统作业(自动发送给课程用户)
-         *
-         * @param mode 作业模式:0基础作业,1系统作业(自动发送给课程用户)
-         */
-        public Builder mode(Integer mode) {
-            obj.setMode(mode);
-            return this;
-        }
-
-        /**
          * 设置题目类型
          *
          * @param paperModule 题目类型
@@ -439,16 +379,6 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
-         * 设置做题时间
-         *
-         * @param time 做题时间
-         */
-        public Builder time(Integer time) {
-            obj.setTime(time);
-            return this;
-        }
-
-        /**
          * 设置作业开始时间
          *
          * @param startTime 作业开始时间

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

@@ -177,6 +177,12 @@ public class User implements Serializable {
     @Column(name = "`invite_number`")
     private Integer inviteNumber;
 
+    /**
+     * 是否订阅最新机经
+     */
+    @Column(name = "`is_subscribe_textbook`")
+    private Integer isSubscribeTextbook;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -697,6 +703,24 @@ public class User implements Serializable {
     }
 
     /**
+     * 获取是否订阅最新机经
+     *
+     * @return is_subscribe_textbook - 是否订阅最新机经
+     */
+    public Integer getIsSubscribeTextbook() {
+        return isSubscribeTextbook;
+    }
+
+    /**
+     * 设置是否订阅最新机经
+     *
+     * @param isSubscribeTextbook 是否订阅最新机经
+     */
+    public void setIsSubscribeTextbook(Integer isSubscribeTextbook) {
+        this.isSubscribeTextbook = isSubscribeTextbook;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -745,6 +769,7 @@ public class User implements Serializable {
         sb.append(", inviteCode=").append(inviteCode);
         sb.append(", totalMoney=").append(totalMoney);
         sb.append(", inviteNumber=").append(inviteNumber);
+        sb.append(", isSubscribeTextbook=").append(isSubscribeTextbook);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
@@ -1048,6 +1073,16 @@ public class User implements Serializable {
         }
 
         /**
+         * 设置是否订阅最新机经
+         *
+         * @param isSubscribeTextbook 是否订阅最新机经
+         */
+        public Builder isSubscribeTextbook(Integer isSubscribeTextbook) {
+            obj.setIsSubscribeTextbook(isSubscribeTextbook);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

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

@@ -18,6 +18,12 @@ public class UserAskQuestion implements Serializable {
     private Integer userId;
 
     /**
+     * 用户做题id
+     */
+    @Column(name = "`user_question_id`")
+    private Integer userQuestionId;
+
+    /**
      * 题目模块
      */
     @Column(name = "`question_module`")
@@ -36,7 +42,7 @@ public class UserAskQuestion implements Serializable {
     private Integer questionNoId;
 
     /**
-     * 问题对象:question,offical,qx,association
+     * 问题对象:question,official,qx,association
      */
     @Column(name = "`target`")
     private String target;
@@ -130,6 +136,24 @@ public class UserAskQuestion implements Serializable {
     }
 
     /**
+     * 获取用户做题id
+     *
+     * @return user_question_id - 用户做题id
+     */
+    public Integer getUserQuestionId() {
+        return userQuestionId;
+    }
+
+    /**
+     * 设置用户做题id
+     *
+     * @param userQuestionId 用户做题id
+     */
+    public void setUserQuestionId(Integer userQuestionId) {
+        this.userQuestionId = userQuestionId;
+    }
+
+    /**
      * 获取题目模块
      *
      * @return question_module - 题目模块
@@ -184,18 +208,18 @@ public class UserAskQuestion implements Serializable {
     }
 
     /**
-     * 获取问题对象:question,offical,qx,association
+     * 获取问题对象:question,official,qx,association
      *
-     * @return target - 问题对象:question,offical,qx,association
+     * @return target - 问题对象:question,official,qx,association
      */
     public String getTarget() {
         return target;
     }
 
     /**
-     * 设置问题对象:question,offical,qx,association
+     * 设置问题对象:question,official,qx,association
      *
-     * @param target 问题对象:question,offical,qx,association
+     * @param target 问题对象:question,official,qx,association
      */
     public void setTarget(String target) {
         this.target = target;
@@ -381,6 +405,7 @@ public class UserAskQuestion implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
+        sb.append(", userQuestionId=").append(userQuestionId);
         sb.append(", questionModule=").append(questionModule);
         sb.append(", questionId=").append(questionId);
         sb.append(", questionNoId=").append(questionNoId);
@@ -429,6 +454,16 @@ public class UserAskQuestion implements Serializable {
         }
 
         /**
+         * 设置用户做题id
+         *
+         * @param userQuestionId 用户做题id
+         */
+        public Builder userQuestionId(Integer userQuestionId) {
+            obj.setUserQuestionId(userQuestionId);
+            return this;
+        }
+
+        /**
          * 设置题目模块
          *
          * @param questionModule 题目模块
@@ -459,9 +494,9 @@ public class UserAskQuestion implements Serializable {
         }
 
         /**
-         * 设置问题对象:question,offical,qx,association
+         * 设置问题对象:question,official,qx,association
          *
-         * @param target 问题对象:question,offical,qx,association
+         * @param target 问题对象:question,official,qx,association
          */
         public Builder target(String target) {
             obj.setTarget(target);

+ 160 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserCollectExperience.java

@@ -0,0 +1,160 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "user_collect_experience")
+public class UserCollectExperience implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
+     * 经验id
+     */
+    @Column(name = "`expericence_id`")
+    private Integer expericenceId;
+
+    @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 user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * 获取经验id
+     *
+     * @return expericence_id - 经验id
+     */
+    public Integer getExpericenceId() {
+        return expericenceId;
+    }
+
+    /**
+     * 设置经验id
+     *
+     * @param expericenceId 经验id
+     */
+    public void setExpericenceId(Integer expericenceId) {
+        this.expericenceId = expericenceId;
+    }
+
+    /**
+     * @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(", userId=").append(userId);
+        sb.append(", expericenceId=").append(expericenceId);
+        sb.append(", createTime=").append(createTime);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static UserCollectExperience.Builder builder() {
+        return new UserCollectExperience.Builder();
+    }
+
+    public static class Builder {
+        private UserCollectExperience obj;
+
+        public Builder() {
+            this.obj = new UserCollectExperience();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * 设置经验id
+         *
+         * @param expericenceId 经验id
+         */
+        public Builder expericenceId(Integer expericenceId) {
+            obj.setExpericenceId(expericenceId);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        public UserCollectExperience build() {
+            return this.obj;
+        }
+    }
+}

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

@@ -35,6 +35,12 @@ public class UserCourse implements Serializable {
     @Column(name = "`expire_time`")
     private Date expireTime;
 
+    /**
+     * 课程扩展信息:json
+     */
+    @Column(name = "`extend`")
+    private String extend;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -123,6 +129,24 @@ public class UserCourse implements Serializable {
         this.expireTime = expireTime;
     }
 
+    /**
+     * 获取课程扩展信息:json
+     *
+     * @return extend - 课程扩展信息:json
+     */
+    public String getExtend() {
+        return extend;
+    }
+
+    /**
+     * 设置课程扩展信息:json
+     *
+     * @param extend 课程扩展信息:json
+     */
+    public void setExtend(String extend) {
+        this.extend = extend;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -134,6 +158,7 @@ public class UserCourse implements Serializable {
         sb.append(", courseId=").append(courseId);
         sb.append(", startTime=").append(startTime);
         sb.append(", expireTime=").append(expireTime);
+        sb.append(", extend=").append(extend);
         sb.append("]");
         return sb.toString();
     }
@@ -197,6 +222,16 @@ public class UserCourse implements Serializable {
             return this;
         }
 
+        /**
+         * 设置课程扩展信息:json
+         *
+         * @param extend 课程扩展信息:json
+         */
+        public Builder extend(String extend) {
+            obj.setExtend(extend);
+            return this;
+        }
+
         public UserCourse build() {
             return this.obj;
         }

+ 335 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourseAppointment.java

@@ -0,0 +1,335 @@
+package com.qxgmat.data.dao.entity;
+
+import java.io.Serializable;
+import java.util.Date;
+import javax.persistence.*;
+
+@Table(name = "user_course_appointment")
+public class UserCourseAppointment implements Serializable {
+    @Id
+    @Column(name = "`id`")
+    @GeneratedValue(strategy = GenerationType.IDENTITY)
+    private Integer id;
+
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
+     * 课程id
+     */
+    @Column(name = "`course_id`")
+    private Integer courseId;
+
+    /**
+     * 频道号
+     */
+    @Column(name = "`channel`")
+    private String channel;
+
+    /**
+     * 预约时间
+     */
+    @Column(name = "`appointment_time`")
+    private Date appointmentTime;
+
+    /**
+     * 是否完成
+     */
+    @Column(name = "`is_finish`")
+    private Integer isFinish;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    /**
+     * 课后补充:json格式
+     */
+    @Column(name = "`supply_list`")
+    private String supplyList;
+
+    /**
+     * 笔记批阅:json格式
+     */
+    @Column(name = "`note_list`")
+    private String noteList;
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * @return id
+     */
+    public Integer getId() {
+        return id;
+    }
+
+    /**
+     * @param id
+     */
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    /**
+     * 获取用户id
+     *
+     * @return user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * 获取课程id
+     *
+     * @return course_id - 课程id
+     */
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    /**
+     * 设置课程id
+     *
+     * @param courseId 课程id
+     */
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    /**
+     * 获取频道号
+     *
+     * @return channel - 频道号
+     */
+    public String getChannel() {
+        return channel;
+    }
+
+    /**
+     * 设置频道号
+     *
+     * @param channel 频道号
+     */
+    public void setChannel(String channel) {
+        this.channel = channel;
+    }
+
+    /**
+     * 获取预约时间
+     *
+     * @return appointment_time - 预约时间
+     */
+    public Date getAppointmentTime() {
+        return appointmentTime;
+    }
+
+    /**
+     * 设置预约时间
+     *
+     * @param appointmentTime 预约时间
+     */
+    public void setAppointmentTime(Date appointmentTime) {
+        this.appointmentTime = appointmentTime;
+    }
+
+    /**
+     * 获取是否完成
+     *
+     * @return is_finish - 是否完成
+     */
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    /**
+     * 设置是否完成
+     *
+     * @param isFinish 是否完成
+     */
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 获取课后补充:json格式
+     *
+     * @return supply_list - 课后补充:json格式
+     */
+    public String getSupplyList() {
+        return supplyList;
+    }
+
+    /**
+     * 设置课后补充:json格式
+     *
+     * @param supplyList 课后补充:json格式
+     */
+    public void setSupplyList(String supplyList) {
+        this.supplyList = supplyList;
+    }
+
+    /**
+     * 获取笔记批阅:json格式
+     *
+     * @return note_list - 笔记批阅:json格式
+     */
+    public String getNoteList() {
+        return noteList;
+    }
+
+    /**
+     * 设置笔记批阅:json格式
+     *
+     * @param noteList 笔记批阅:json格式
+     */
+    public void setNoteList(String noteList) {
+        this.noteList = noteList;
+    }
+
+    @Override
+    public String toString() {
+        StringBuilder sb = new StringBuilder();
+        sb.append(getClass().getSimpleName());
+        sb.append(" [");
+        sb.append("Hash = ").append(hashCode());
+        sb.append(", id=").append(id);
+        sb.append(", userId=").append(userId);
+        sb.append(", courseId=").append(courseId);
+        sb.append(", channel=").append(channel);
+        sb.append(", appointmentTime=").append(appointmentTime);
+        sb.append(", isFinish=").append(isFinish);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", supplyList=").append(supplyList);
+        sb.append(", noteList=").append(noteList);
+        sb.append("]");
+        return sb.toString();
+    }
+
+    public static UserCourseAppointment.Builder builder() {
+        return new UserCourseAppointment.Builder();
+    }
+
+    public static class Builder {
+        private UserCourseAppointment obj;
+
+        public Builder() {
+            this.obj = new UserCourseAppointment();
+        }
+
+        /**
+         * @param id
+         */
+        public Builder id(Integer id) {
+            obj.setId(id);
+            return this;
+        }
+
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * 设置课程id
+         *
+         * @param courseId 课程id
+         */
+        public Builder courseId(Integer courseId) {
+            obj.setCourseId(courseId);
+            return this;
+        }
+
+        /**
+         * 设置频道号
+         *
+         * @param channel 频道号
+         */
+        public Builder channel(String channel) {
+            obj.setChannel(channel);
+            return this;
+        }
+
+        /**
+         * 设置预约时间
+         *
+         * @param appointmentTime 预约时间
+         */
+        public Builder appointmentTime(Date appointmentTime) {
+            obj.setAppointmentTime(appointmentTime);
+            return this;
+        }
+
+        /**
+         * 设置是否完成
+         *
+         * @param isFinish 是否完成
+         */
+        public Builder isFinish(Integer isFinish) {
+            obj.setIsFinish(isFinish);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * 设置课后补充:json格式
+         *
+         * @param supplyList 课后补充:json格式
+         */
+        public Builder supplyList(String supplyList) {
+            obj.setSupplyList(supplyList);
+            return this;
+        }
+
+        /**
+         * 设置笔记批阅:json格式
+         *
+         * @param noteList 笔记批阅:json格式
+         */
+        public Builder noteList(String noteList) {
+            obj.setNoteList(noteList);
+            return this;
+        }
+
+        public UserCourseAppointment build() {
+            return this.obj;
+        }
+    }
+}

+ 307 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrder.java

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "user_order")
@@ -10,6 +11,57 @@ public class UserOrder implements Serializable {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
+    /**
+     * 用户id
+     */
+    @Column(name = "`user_id`")
+    private Integer userId;
+
+    /**
+     * 模块
+     */
+    @Column(name = "`module`")
+    private String module;
+
+    /**
+     * 使用状态:0未使用,1已使用
+     */
+    @Column(name = "`is_use`")
+    private Integer isUse;
+
+    /**
+     * 最晚使用时间
+     */
+    @Column(name = "`end_time`")
+    private Date endTime;
+
+    /**
+     * 使用时间
+     */
+    @Column(name = "`use_time`")
+    private Date useTime;
+
+    /**
+     * 有效期:开始
+     */
+    @Column(name = "`start_time`")
+    private Date startTime;
+
+    /**
+     * 有效期:结束
+     */
+    @Column(name = "`expire_time`")
+    private Date expireTime;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    /**
+     * 模块扩展信息: json
+     */
+    @Column(name = "`module_extend`")
+    private String moduleExtend;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -26,6 +78,164 @@ public class UserOrder implements Serializable {
         this.id = id;
     }
 
+    /**
+     * 获取用户id
+     *
+     * @return user_id - 用户id
+     */
+    public Integer getUserId() {
+        return userId;
+    }
+
+    /**
+     * 设置用户id
+     *
+     * @param userId 用户id
+     */
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    /**
+     * 获取模块
+     *
+     * @return module - 模块
+     */
+    public String getModule() {
+        return module;
+    }
+
+    /**
+     * 设置模块
+     *
+     * @param module 模块
+     */
+    public void setModule(String module) {
+        this.module = module;
+    }
+
+    /**
+     * 获取使用状态:0未使用,1已使用
+     *
+     * @return is_use - 使用状态:0未使用,1已使用
+     */
+    public Integer getIsUse() {
+        return isUse;
+    }
+
+    /**
+     * 设置使用状态:0未使用,1已使用
+     *
+     * @param isUse 使用状态:0未使用,1已使用
+     */
+    public void setIsUse(Integer isUse) {
+        this.isUse = isUse;
+    }
+
+    /**
+     * 获取最晚使用时间
+     *
+     * @return end_time - 最晚使用时间
+     */
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    /**
+     * 设置最晚使用时间
+     *
+     * @param endTime 最晚使用时间
+     */
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    /**
+     * 获取使用时间
+     *
+     * @return use_time - 使用时间
+     */
+    public Date getUseTime() {
+        return useTime;
+    }
+
+    /**
+     * 设置使用时间
+     *
+     * @param useTime 使用时间
+     */
+    public void setUseTime(Date useTime) {
+        this.useTime = useTime;
+    }
+
+    /**
+     * 获取有效期:开始
+     *
+     * @return start_time - 有效期:开始
+     */
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    /**
+     * 设置有效期:开始
+     *
+     * @param startTime 有效期:开始
+     */
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    /**
+     * 获取有效期:结束
+     *
+     * @return expire_time - 有效期:结束
+     */
+    public Date getExpireTime() {
+        return expireTime;
+    }
+
+    /**
+     * 设置有效期:结束
+     *
+     * @param expireTime 有效期:结束
+     */
+    public void setExpireTime(Date expireTime) {
+        this.expireTime = expireTime;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * 获取模块扩展信息: json
+     *
+     * @return module_extend - 模块扩展信息: json
+     */
+    public String getModuleExtend() {
+        return moduleExtend;
+    }
+
+    /**
+     * 设置模块扩展信息: json
+     *
+     * @param moduleExtend 模块扩展信息: json
+     */
+    public void setModuleExtend(String moduleExtend) {
+        this.moduleExtend = moduleExtend;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -33,6 +243,15 @@ public class UserOrder implements Serializable {
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
+        sb.append(", userId=").append(userId);
+        sb.append(", module=").append(module);
+        sb.append(", isUse=").append(isUse);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", useTime=").append(useTime);
+        sb.append(", startTime=").append(startTime);
+        sb.append(", expireTime=").append(expireTime);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", moduleExtend=").append(moduleExtend);
         sb.append("]");
         return sb.toString();
     }
@@ -56,6 +275,94 @@ public class UserOrder implements Serializable {
             return this;
         }
 
+        /**
+         * 设置用户id
+         *
+         * @param userId 用户id
+         */
+        public Builder userId(Integer userId) {
+            obj.setUserId(userId);
+            return this;
+        }
+
+        /**
+         * 设置模块
+         *
+         * @param module 模块
+         */
+        public Builder module(String module) {
+            obj.setModule(module);
+            return this;
+        }
+
+        /**
+         * 设置模块扩展信息: json
+         *
+         * @param moduleExtend 模块扩展信息: json
+         */
+        public Builder moduleExtend(String moduleExtend) {
+            obj.setModuleExtend(moduleExtend);
+            return this;
+        }
+
+        /**
+         * 设置使用状态:0未使用,1已使用
+         *
+         * @param isUse 使用状态:0未使用,1已使用
+         */
+        public Builder isUse(Integer isUse) {
+            obj.setIsUse(isUse);
+            return this;
+        }
+
+        /**
+         * 设置最晚使用时间
+         *
+         * @param endTime 最晚使用时间
+         */
+        public Builder endTime(Date endTime) {
+            obj.setEndTime(endTime);
+            return this;
+        }
+
+        /**
+         * 设置使用时间
+         *
+         * @param useTime 使用时间
+         */
+        public Builder useTime(Date useTime) {
+            obj.setUseTime(useTime);
+            return this;
+        }
+
+        /**
+         * 设置有效期:开始
+         *
+         * @param startTime 有效期:开始
+         */
+        public Builder startTime(Date startTime) {
+            obj.setStartTime(startTime);
+            return this;
+        }
+
+        /**
+         * 设置有效期:结束
+         *
+         * @param expireTime 有效期:结束
+         */
+        public Builder expireTime(Date expireTime) {
+            obj.setExpireTime(expireTime);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
         public UserOrder build() {
             return this.obj;
         }

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

@@ -4,8 +4,8 @@ import java.io.Serializable;
 import java.util.Date;
 import javax.persistence.*;
 
-@Table(name = "user_service_record")
-public class UserServiceRecord implements Serializable {
+@Table(name = "user_order_record")
+public class UserOrderRecord implements Serializable {
     @Id
     @Column(name = "`id`")
     @GeneratedValue(strategy = GenerationType.IDENTITY)
@@ -18,6 +18,24 @@ public class UserServiceRecord implements Serializable {
     private Integer userId;
 
     /**
+     * 订单id
+     */
+    @Column(name = "`order_id`")
+    private Integer orderId;
+
+    /**
+     * 产品类型
+     */
+    @Column(name = "`product_type`")
+    private String productType;
+
+    /**
+     * 产品id
+     */
+    @Column(name = "`product_id`")
+    private Integer productId;
+
+    /**
      * 服务
      */
     @Column(name = "`service`")
@@ -48,6 +66,18 @@ public class UserServiceRecord implements Serializable {
     private Date endTime;
 
     /**
+     * 使用开始时间
+     */
+    @Column(name = "`use_start_time`")
+    private Date useStartTime;
+
+    /**
+     * 使用结束时间
+     */
+    @Column(name = "`use_end_time`")
+    private Date useEndTime;
+
+    /**
      * 是否使用
      */
     @Column(name = "`is_used`")
@@ -91,6 +121,60 @@ public class UserServiceRecord implements Serializable {
     }
 
     /**
+     * 获取订单id
+     *
+     * @return order_id - 订单id
+     */
+    public Integer getOrderId() {
+        return orderId;
+    }
+
+    /**
+     * 设置订单id
+     *
+     * @param orderId 订单id
+     */
+    public void setOrderId(Integer orderId) {
+        this.orderId = orderId;
+    }
+
+    /**
+     * 获取产品类型
+     *
+     * @return product_type - 产品类型
+     */
+    public String getProductType() {
+        return productType;
+    }
+
+    /**
+     * 设置产品类型
+     *
+     * @param productType 产品类型
+     */
+    public void setProductType(String productType) {
+        this.productType = productType;
+    }
+
+    /**
+     * 获取产品id
+     *
+     * @return product_id - 产品id
+     */
+    public Integer getProductId() {
+        return productId;
+    }
+
+    /**
+     * 设置产品id
+     *
+     * @param productId 产品id
+     */
+    public void setProductId(Integer productId) {
+        this.productId = productId;
+    }
+
+    /**
      * 获取服务
      *
      * @return service - 服务
@@ -181,6 +265,42 @@ public class UserServiceRecord implements Serializable {
     }
 
     /**
+     * 获取使用开始时间
+     *
+     * @return use_start_time - 使用开始时间
+     */
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    /**
+     * 设置使用开始时间
+     *
+     * @param useStartTime 使用开始时间
+     */
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    /**
+     * 获取使用结束时间
+     *
+     * @return use_end_time - 使用结束时间
+     */
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    /**
+     * 设置使用结束时间
+     *
+     * @param useEndTime 使用结束时间
+     */
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    /**
      * 获取是否使用
      *
      * @return is_used - 是否使用
@@ -220,26 +340,31 @@ public class UserServiceRecord implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
+        sb.append(", orderId=").append(orderId);
+        sb.append(", productType=").append(productType);
+        sb.append(", productId=").append(productId);
         sb.append(", service=").append(service);
         sb.append(", param=").append(param);
         sb.append(", source=").append(source);
         sb.append(", startTime=").append(startTime);
         sb.append(", endTime=").append(endTime);
+        sb.append(", useStartTime=").append(useStartTime);
+        sb.append(", useEndTime=").append(useEndTime);
         sb.append(", isUsed=").append(isUsed);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
     }
 
-    public static UserServiceRecord.Builder builder() {
-        return new UserServiceRecord.Builder();
+    public static UserOrderRecord.Builder builder() {
+        return new UserOrderRecord.Builder();
     }
 
     public static class Builder {
-        private UserServiceRecord obj;
+        private UserOrderRecord obj;
 
         public Builder() {
-            this.obj = new UserServiceRecord();
+            this.obj = new UserOrderRecord();
         }
 
         /**
@@ -261,6 +386,36 @@ public class UserServiceRecord implements Serializable {
         }
 
         /**
+         * 设置订单id
+         *
+         * @param orderId 订单id
+         */
+        public Builder orderId(Integer orderId) {
+            obj.setOrderId(orderId);
+            return this;
+        }
+
+        /**
+         * 设置产品类型
+         *
+         * @param productType 产品类型
+         */
+        public Builder productType(String productType) {
+            obj.setProductType(productType);
+            return this;
+        }
+
+        /**
+         * 设置产品id
+         *
+         * @param productId 产品id
+         */
+        public Builder productId(Integer productId) {
+            obj.setProductId(productId);
+            return this;
+        }
+
+        /**
          * 设置服务
          *
          * @param service 服务
@@ -311,6 +466,26 @@ public class UserServiceRecord implements Serializable {
         }
 
         /**
+         * 设置使用开始时间
+         *
+         * @param useStartTime 使用开始时间
+         */
+        public Builder useStartTime(Date useStartTime) {
+            obj.setUseStartTime(useStartTime);
+            return this;
+        }
+
+        /**
+         * 设置使用结束时间
+         *
+         * @param useEndTime 使用结束时间
+         */
+        public Builder useEndTime(Date useEndTime) {
+            obj.setUseEndTime(useEndTime);
+            return this;
+        }
+
+        /**
          * 设置是否使用
          *
          * @param isUsed 是否使用
@@ -328,7 +503,7 @@ public class UserServiceRecord implements Serializable {
             return this;
         }
 
-        public UserServiceRecord build() {
+        public UserOrderRecord build() {
             return this.obj;
         }
     }

+ 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 = "`expire_time`")
     private Date expireTime;
 
+    /**
+     * 服务当前扩展信息:json
+     */
+    @Column(name = "`extend`")
+    private String extend;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -109,6 +115,24 @@ public class UserService implements Serializable {
         this.expireTime = expireTime;
     }
 
+    /**
+     * 获取服务当前扩展信息:json
+     *
+     * @return extend - 服务当前扩展信息:json
+     */
+    public String getExtend() {
+        return extend;
+    }
+
+    /**
+     * 设置服务当前扩展信息:json
+     *
+     * @param extend 服务当前扩展信息:json
+     */
+    public void setExtend(String extend) {
+        this.extend = extend;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -120,6 +144,7 @@ public class UserService implements Serializable {
         sb.append(", service=").append(service);
         sb.append(", startTime=").append(startTime);
         sb.append(", expireTime=").append(expireTime);
+        sb.append(", extend=").append(extend);
         sb.append("]");
         return sb.toString();
     }
@@ -179,6 +204,16 @@ public class UserService implements Serializable {
             return this;
         }
 
+        /**
+         * 设置服务当前扩展信息:json
+         *
+         * @param extend 服务当前扩展信息:json
+         */
+        public Builder extend(String extend) {
+            obj.setExtend(extend);
+            return this;
+        }
+
         public UserService build() {
             return this.obj;
         }

+ 34 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseDataHistoryMapper.xml

@@ -0,0 +1,34 @@
+<?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.CourseDataHistoryMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.CourseDataHistory">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="data_id" jdbcType="INTEGER" property="dataId" />
+    <result column="resource" jdbcType="VARCHAR" property="resource" />
+    <result column="version" jdbcType="VARCHAR" property="version" />
+    <result column="change_page" jdbcType="VARCHAR" property="changePage" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.CourseDataHistory">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="origin_content" jdbcType="LONGVARCHAR" property="originContent" />
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `data_id`, `resource`, `version`, `change_page`, `create_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `origin_content`, `content`
+  </sql>
+</mapper>

+ 36 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseDataMapper.xml

@@ -6,5 +6,41 @@
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="struct_id" jdbcType="INTEGER" property="structId" />
+    <result column="parent_struct_id" jdbcType="INTEGER" property="parentStructId" />
+    <result column="data_type" jdbcType="VARCHAR" property="dataType" />
+    <result column="is_novice" jdbcType="INTEGER" property="isNovice" />
+    <result column="is_original" jdbcType="INTEGER" property="isOriginal" />
+    <result column="price" jdbcType="DECIMAL" property="price" />
+    <result column="pages" jdbcType="INTEGER" property="pages" />
+    <result column="link" jdbcType="VARCHAR" property="link" />
+    <result column="cover" jdbcType="VARCHAR" property="cover" />
+    <result column="view_number" jdbcType="INTEGER" property="viewNumber" />
+    <result column="sale_number" jdbcType="INTEGER" property="saleNumber" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.CourseData">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="description" jdbcType="LONGVARCHAR" property="description" />
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+    <result column="author_content" jdbcType="LONGVARCHAR" property="authorContent" />
+    <result column="method_content" jdbcType="LONGVARCHAR" property="methodContent" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `title`, `struct_id`, `parent_struct_id`, `data_type`, `is_novice`, `is_original`, 
+    `price`, `pages`, `link`, `cover`, `view_number`, `sale_number`, `create_time`, `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `description`, `content`, `author_content`, `method_content`
+  </sql>
 </mapper>

+ 34 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseExperienceMapper.xml

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

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

@@ -8,14 +8,51 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="struct_id" jdbcType="INTEGER" property="structId" />
     <result column="parent_struct_id" jdbcType="INTEGER" property="parentStructId" />
-    <result column="question_type" jdbcType="VARCHAR" property="questionType" />
+    <result column="course_module" jdbcType="VARCHAR" property="courseModule" />
+    <result column="extend" jdbcType="VARCHAR" property="extend" />
     <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="crowd" jdbcType="VARCHAR" property="crowd" />
+    <result column="price" jdbcType="DECIMAL" property="price" />
+    <result column="teacher" jdbcType="VARCHAR" property="teacher" />
+    <result column="min_number" jdbcType="INTEGER" property="minNumber" />
+    <result column="max_number" jdbcType="INTEGER" property="maxNumber" />
+    <result column="expire_days" jdbcType="INTEGER" property="expireDays" />
+    <result column="wechat_avatar" jdbcType="VARCHAR" property="wechatAvatar" />
+    <result column="trail_number" jdbcType="INTEGER" property="trailNumber" />
+    <result column="sale_number" jdbcType="INTEGER" property="saleNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.Course">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="teacher_content" jdbcType="LONGVARCHAR" property="teacherContent" />
+    <result column="base_content" jdbcType="LONGVARCHAR" property="baseContent" />
+    <result column="course_content" jdbcType="LONGVARCHAR" property="courseContent" />
+    <result column="point_content" jdbcType="LONGVARCHAR" property="pointContent" />
+    <result column="crowd_content" jdbcType="LONGVARCHAR" property="crowdContent" />
+    <result column="syllabus_content" jdbcType="LONGVARCHAR" property="syllabusContent" />
+    <result column="promote_content" jdbcType="LONGVARCHAR" property="promoteContent" />
+    <result column="service_content" jdbcType="LONGVARCHAR" property="serviceContent" />
+    <result column="message_content" jdbcType="LONGVARCHAR" property="messageContent" />
+    <result column="process_content" jdbcType="LONGVARCHAR" property="processContent" />
+    <result column="course_no_content" jdbcType="LONGVARCHAR" property="courseNoContent" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `struct_id`, `parent_struct_id`, `question_type`, `title`, `create_time`
+    `id`, `struct_id`, `parent_struct_id`, `course_module`, `extend`, `title`, `crowd`, 
+    `price`, `teacher`, `min_number`, `max_number`, `expire_days`, `wechat_avatar`, `trail_number`, 
+    `sale_number`, `create_time`, `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `teacher_content`, `base_content`, `course_content`, `point_content`, `crowd_content`, 
+    `syllabus_content`, `promote_content`, `service_content`, `message_content`, `process_content`, 
+    `course_no_content`
   </sql>
 </mapper>

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

@@ -8,8 +8,11 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
     <result column="no" jdbcType="INTEGER" property="no" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="resource" jdbcType="VARCHAR" property="resource" />
     <result column="time" jdbcType="INTEGER" property="time" />
+    <result column="start_trail" jdbcType="INTEGER" property="startTrail" />
+    <result column="end_trail" jdbcType="INTEGER" property="endTrail" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.CourseNo">
@@ -22,7 +25,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `course_id`, `no`, `resource`, `time`, `create_time`
+    `id`, `course_id`, `no`, `title`, `resource`, `time`, `start_trail`, `end_trail`, 
+    `create_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -12,7 +12,7 @@
     <result column="course_ids" jdbcType="VARCHAR" property="courseIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="is_special" jdbcType="INTEGER" property="isSpecial" />
     <result column="gift" jdbcType="VARCHAR" property="gift" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
-    <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
+    <result column="sale_number" jdbcType="INTEGER" property="saleNumber" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
@@ -26,7 +26,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `struct_id`, `title`, `price`, `course_ids`, `is_special`, `gift`, `total_number`, 
+    `id`, `struct_id`, `title`, `price`, `course_ids`, `is_special`, `gift`, `sale_number`, 
     `create_time`, `update_time`
   </sql>
   <sql id="Blob_Column_List">

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

@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.dao.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>

+ 7 - 7
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceRecordMapper.xml

@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.qxgmat.data.dao.UserServiceRecordMapper">
-  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.UserServiceRecord">
+<mapper namespace="com.qxgmat.data.dao.CourseStudentVsMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.CourseStudentVs">
     <!--
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="teacher_id" jdbcType="INTEGER" property="teacherId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
-    <result column="service" jdbcType="VARCHAR" property="service" />
-    <result column="param" jdbcType="VARCHAR" property="param" />
-    <result column="source" jdbcType="VARCHAR" property="source" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
+    <result column="add_method" jdbcType="VARCHAR" property="addMethod" />
     <result column="is_used" jdbcType="INTEGER" property="isUsed" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
@@ -19,7 +19,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `service`, `param`, `source`, `start_time`, `end_time`, `is_used`, 
-    `create_time`
+    `id`, `course_id`, `teacher_id`, `user_id`, `start_time`, `end_time`, `add_method`, 
+    `is_used`, `create_time`
   </sql>
 </mapper>

+ 21 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseTeacherMapper.xml

@@ -0,0 +1,21 @@
+<?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.CourseTeacherMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.CourseTeacher">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="realname" jdbcType="VARCHAR" property="realname" />
+    <result column="wechat" jdbcType="VARCHAR" property="wechat" />
+    <result column="qr" jdbcType="VARCHAR" property="qr" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `course_id`, `realname`, `wechat`, `qr`, `create_time`
+  </sql>
+</mapper>

+ 21 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseTimeMapper.xml

@@ -0,0 +1,21 @@
+<?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.CourseTimeMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.CourseTime">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
+    <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
+    <result column="status" jdbcType="INTEGER" property="status" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `course_id`, `start_time`, `end_time`, `status`, `create_time`
+  </sql>
+</mapper>

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

@@ -10,10 +10,8 @@
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
     <result column="course_no" jdbcType="INTEGER" property="courseNo" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
-    <result column="mode" jdbcType="INTEGER" property="mode" />
     <result column="paper_module" jdbcType="VARCHAR" property="paperModule" />
     <result column="user_ids" jdbcType="VARCHAR" property="userIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
-    <result column="time" jdbcType="INTEGER" property="time" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
     <result column="finish" jdbcType="INTEGER" property="finish" />
@@ -24,7 +22,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `course_id`, `course_no`, `question_no_ids`, `mode`, `paper_module`, 
-    `user_ids`, `time`, `start_time`, `end_time`, `finish`, `create_time`, `update_time`
+    `id`, `title`, `course_id`, `course_no`, `question_no_ids`, `paper_module`, `user_ids`, 
+    `start_time`, `end_time`, `finish`, `create_time`, `update_time`
   </sql>
 </mapper>

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

@@ -7,6 +7,7 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="user_question_id" jdbcType="INTEGER" property="userQuestionId" />
     <result column="question_module" jdbcType="VARCHAR" property="questionModule" />
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
     <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
@@ -31,8 +32,9 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `question_module`, `question_id`, `question_no_id`, `target`, `answer_status`, 
-    `manager_id`, `show_status`, `answer_time`, `order`, `create_time`, `update_time`
+    `id`, `user_id`, `user_question_id`, `question_module`, `question_id`, `question_no_id`, 
+    `target`, `answer_status`, `manager_id`, `show_status`, `answer_time`, `order`, `create_time`, 
+    `update_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

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

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

@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.dao.UserCourseAppointmentMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.UserCourseAppointment">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="channel" jdbcType="VARCHAR" property="channel" />
+    <result column="appointment_time" jdbcType="TIMESTAMP" property="appointmentTime" />
+    <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+  </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserCourseAppointment">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="supply_list" jdbcType="LONGVARCHAR" property="supplyList" />
+    <result column="note_list" jdbcType="LONGVARCHAR" property="noteList" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `user_id`, `course_id`, `channel`, `appointment_time`, `is_finish`, `create_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `supply_list`, `note_list`
+  </sql>
+</mapper>

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

@@ -11,10 +11,22 @@
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserCourse">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="extend" jdbcType="LONGVARCHAR" property="extend" />
+  </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `course_id`, `start_time`, `expire_time`
   </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `extend`
+  </sql>
 </mapper>

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

@@ -34,6 +34,7 @@
     <result column="invite_code" jdbcType="VARCHAR" property="inviteCode" />
     <result column="total_money" jdbcType="DECIMAL" property="totalMoney" />
     <result column="invite_number" jdbcType="INTEGER" property="inviteNumber" />
+    <result column="is_subscribe_textbook" jdbcType="INTEGER" property="isSubscribeTextbook" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
@@ -45,6 +46,6 @@
     `wechat_expire_time`, `real_name`, `real_address`, `real_identity`, `real_photo_front`, 
     `real_photo_back`, `real_status`, `prepare_status`, `prepare_goal`, `prepare_examination_time`, 
     `prepare_score_time`, `latest_exercise`, `latest_error`, `origin_id`, `invite_code`, 
-    `total_money`, `invite_number`, `create_time`
+    `total_money`, `invite_number`, `is_subscribe_textbook`, `create_time`
   </sql>
 </mapper>

+ 27 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderMapper.xml

@@ -6,5 +6,32 @@
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="module" jdbcType="VARCHAR" property="module" />
+    <result column="is_use" jdbcType="INTEGER" property="isUse" />
+    <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
+    <result column="use_time" jdbcType="TIMESTAMP" property="useTime" />
+    <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
+    <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserOrder">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="module_extend" jdbcType="LONGVARCHAR" property="moduleExtend" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `user_id`, `module`, `is_use`, `end_time`, `use_time`, `start_time`, `expire_time`, 
+    `create_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `module_extend`
+  </sql>
 </mapper>

+ 30 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml

@@ -0,0 +1,30 @@
+<?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.UserOrderRecordMapper">
+  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.UserOrderRecord">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="order_id" jdbcType="INTEGER" property="orderId" />
+    <result column="product_type" jdbcType="VARCHAR" property="productType" />
+    <result column="product_id" jdbcType="INTEGER" property="productId" />
+    <result column="service" jdbcType="VARCHAR" property="service" />
+    <result column="param" jdbcType="VARCHAR" property="param" />
+    <result column="source" jdbcType="VARCHAR" property="source" />
+    <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
+    <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
+    <result column="use_start_time" jdbcType="TIMESTAMP" property="useStartTime" />
+    <result column="use_end_time" jdbcType="TIMESTAMP" property="useEndTime" />
+    <result column="is_used" jdbcType="INTEGER" property="isUsed" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `user_id`, `order_id`, `product_type`, `product_id`, `service`, `param`, `source`, 
+    `start_time`, `end_time`, `use_start_time`, `use_end_time`, `is_used`, `create_time`
+  </sql>
+</mapper>

+ 12 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceMapper.xml

@@ -11,10 +11,22 @@
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserService">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="extend" jdbcType="LONGVARCHAR" property="extend" />
+  </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `service`, `start_time`, `expire_time`
   </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `extend`
+  </sql>
 </mapper>

+ 17 - 0
server/data/src/main/java/com/qxgmat/data/relation/CourseStudentOnlineRelationMapper.java

@@ -0,0 +1,17 @@
+package com.qxgmat.data.relation;
+
+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 CourseStudentOnlineRelationMapper {
+
+    List<CourseStudentNumberRelation> groupByTime(
+            @Param("ids") Collection ids
+    );
+}

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


Некоторые файлы не были показаны из-за большого количества измененных файлов