Browse Source

feat(server): 学习记录

Go 5 years ago
parent
commit
02e1955634
100 changed files with 3449 additions and 1801 deletions
  1. 5 3
      front/project/Constant.js
  2. 93 67
      front/project/admin/routes/course/ask/page.js
  3. 15 8
      front/project/admin/routes/course/askDetail/page.js
  4. 45 47
      front/project/admin/routes/course/data/page.js
  5. 2 2
      front/project/admin/routes/course/dataDetail/page.js
  6. 4 254
      front/project/admin/routes/course/detail/page.js
  7. 7 0
      front/project/admin/routes/course/experience/page.js
  8. 5 2
      front/project/admin/routes/course/index.js
  9. 7 7
      front/project/admin/routes/course/list/page.js
  10. 2 2
      front/project/admin/routes/course/package/page.js
  11. 1 1
      front/project/admin/routes/course/student/index.js
  12. 298 129
      front/project/admin/routes/course/student/page.js
  13. 15 0
      front/project/admin/routes/course/study/index.js
  14. 3 0
      front/project/admin/routes/course/study/index.less
  15. 185 0
      front/project/admin/routes/course/study/page.js
  16. 16 0
      front/project/admin/routes/course/studyDetail/index.js
  17. 3 0
      front/project/admin/routes/course/studyDetail/index.less
  18. 332 0
      front/project/admin/routes/course/studyDetail/page.js
  19. 16 0
      front/project/admin/routes/course/vsDetail/index.js
  20. 19 0
      front/project/admin/routes/course/vsDetail/index.less
  21. 304 0
      front/project/admin/routes/course/vsDetail/page.js
  22. 1 0
      front/project/admin/routes/setting/rank/page.js
  23. 52 54
      front/project/admin/routes/user/ask/page.js
  24. 1 1
      front/project/admin/routes/user/askDetail/page.js
  25. 1 11
      front/project/admin/routes/user/detail/page.js
  26. 8 4
      front/project/admin/routes/user/preview/page.js
  27. 10 3
      front/project/admin/routes/user/service/page.js
  28. 24 0
      front/project/admin/stores/course.js
  29. 30 2
      front/project/admin/stores/user.js
  30. 2 0
      front/src/layouts/FormLayout/index.js
  31. 8 8
      front/src/services/Tools.js
  32. 19 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/VsCourseType.java
  33. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/CourseStudentVsMapper.java
  34. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/UserPayMapper.java
  35. 42 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/Course.java
  36. 0 317
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentVs.java
  37. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/PreviewPaper.java
  38. 229 53
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourseAppointment.java
  39. 210 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserInvoice.java
  40. 0 175
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrder.java
  41. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrderRecord.java
  42. 0 371
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPay.java
  43. 4 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseMapper.xml
  44. 0 25
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseStudentVsMapper.xml
  45. 6 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/PreviewPaperMapper.xml
  46. 10 15
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseAppointmentMapper.xml
  47. 8 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserInvoiceMapper.xml
  48. 1 7
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderMapper.xml
  49. 5 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml
  50. 0 26
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPayMapper.xml
  51. 3 0
      server/data/src/main/java/com/qxgmat/data/relation/UserAskCourseRelationMapper.java
  52. 10 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskCourseRelationMapper.xml
  53. 5 0
      server/data/src/main/resources/mybatis-generator.xml
  54. 144 10
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  55. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java
  56. 87 16
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  57. 4 4
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  58. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  59. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseExtendDto.java
  60. 29 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseTeacherExtendDto.java
  61. 49 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseTimeExtendDto.java
  62. 9 18
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserCourseExtendDto.java
  63. 49 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserPaperExtendDto.java
  64. 120 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/UserCourseAppointmentDto.java
  65. 79 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/UserCourseRecordDto.java
  66. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CourseListDto.java
  67. 11 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CourseStudentOnlineListDto.java
  68. 162 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseAppointmentInfoDto.java
  69. 111 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseStudentRecordInfoDto.java
  70. 152 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseStudyRecordInfoDto.java
  71. 0 10
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserDetailDto.java
  72. 0 10
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserListDto.java
  73. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/ManagerService.java
  74. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectExperienceService.java
  75. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserCollectQuestionService.java
  76. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteCourseService.java
  77. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  78. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  79. 3 3
      server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java
  80. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserServiceService.java
  81. 3 4
      server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java
  82. 6 12
      server/gateway-api/src/main/java/com/qxgmat/service/extend/TradeService.java
  83. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/AdService.java
  84. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CommentService.java
  85. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseDataHistoryService.java
  86. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseDataService.java
  87. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseExperienceService.java
  88. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseNoService.java
  89. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CoursePackageService.java
  90. 17 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseService.java
  91. 23 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseStudentOnlineService.java
  92. 0 87
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseStudentVsService.java
  93. 5 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseTeacherService.java
  94. 12 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseTimeService.java
  95. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExaminationStructService.java
  96. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExerciseQuestionService.java
  97. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExerciseStructService.java
  98. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/FaqService.java
  99. 4 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/MessageService.java
  100. 0 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PayService.java

+ 5 - 3
front/project/Constant.js

@@ -26,6 +26,8 @@ export const ServiceParamMap = {
 
 export const ServiceSource = [{ label: '线下支付', value: 'offline' }, { label: '线上支付', value: 'online' }, { label: '实名认证', value: 'real' }, { label: '邀请好友', value: 'invite' }, { label: 'gift' }];
 
+export const CourseSource = [{ label: '线下报名', value: 'offline' }, { label: '线上报名', value: 'online' }];
+
 export const SwitchSelect = [{ value: 0, label: '否' }, { value: 1, label: '是' }];
 
 export const AskStatus = [{ value: 0, label: '新增' }, { value: 1, label: '已回答' }, { value: 2, label: '忽略' }];
@@ -56,13 +58,13 @@ export const ExperienceScore = [{ label: '650+', value: '_650' }, { label: '700+
 
 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 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 CourseVsType = [{ label: '新手辅导', value: 'novice' }, { label: '诊断辅导', value: 'coach' }, { 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 }];
+export const CourseStatus = [{ label: '未开通', value: 0 }, { label: '学习中', value: 1 }, { label: '已到期', value: 2 }];
 
 // const content = {
 //   steps: [{

+ 93 - 67
front/project/admin/routes/course/ask/page.js

@@ -6,9 +6,9 @@ import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
 // import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, formatDate, formatTreeData, formatSeconds } from '@src/services/Tools';
+import { getMap, formatDate, formatTreeData, formatSeconds, bindSearch } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { AskStatus, SwitchSelect } from '../../../../Constant';
+import { AskStatus, SwitchSelect, MoneyRange } from '../../../../Constant';
 import { User } from '../../../stores/user';
 import { Exercise } from '../../../stores/exercise';
 import { Course } from '../../../stores/course';
@@ -54,84 +54,111 @@ export default class extends Page {
       allowClear: true,
       name: '展示状态',
       select: SwitchSelect,
+    }, {
+      key: 'userId',
+      type: 'select',
+      name: '用户',
+      allowClear: true,
+      select: [],
+      number: true,
+      placeholder: '请输入',
+    }, {
+      key: 'money',
+      type: 'select',
+      allowClear: true,
+      name: '消费金额',
+      select: MoneyRange,
+      number: true,
     }];
-    this.columns = [
-      {
-        title: '学科',
-        dataIndex: 'course.structId',
-        render: (text, record) => {
-          return `${record.course.parentStructId ? `${this.exerciseMap[record.course.parentStructId]}-` : ''}${this.exerciseMap[record.course.structId]}`;
-        },
+    this.columns = [{
+      title: '学科',
+      dataIndex: 'course.structId',
+      render: (text, record) => {
+        return `${record.course.parentStructId ? `${this.exerciseMap[record.course.parentStructId]}-` : ''}${this.exerciseMap[record.course.structId]}`;
       },
-      {
-        title: '课程',
-        dataIndex: 'course.title',
+    },
+    {
+      title: '课程',
+      dataIndex: 'course.title',
+    },
+    {
+      title: '位置',
+      dataIndex: 'position',
+      render: (text, record) => {
+        return `P${record.courseNo.no}:${text}`;
       },
-      {
-        title: '位置',
-        dataIndex: 'position',
-        render: (text, record) => {
-          return `P${record.courseNo.no}:${text}`;
-        },
+    },
+    {
+      title: '提问摘要',
+      dataIndex: 'content',
+    }, {
+      title: '提问者',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '承诺时间',
+      dataIndex: 'user.askTime',
+      render: (text, record) => {
+        const cost = (new Date().getTime() - new Date(record.createTime).getTime()) / 1000;
+        return user.askTime ? formatSeconds(user.askTime - cost) : '-';
       },
-      {
-        title: '提问摘要',
-        dataIndex: 'content',
-      }, {
-        title: '提问者',
-        dataIndex: 'user.nickname',
-      }, {
-        title: '承诺时间',
-        dataIndex: 'user.askTime',
-        render: (text, record) => {
-          const cost = (new Date().getTime() - new Date(record.createTime).getTime()) / 1000;
-          return user.askTime ? formatSeconds(user.askTime - cost) : '-';
-        },
-      }, {
-        title: '回答状态',
-        dataIndex: 'answerStatus',
-        render: (text) => {
-          return AskStatusMap[text] || text;
-        },
-      }, {
-        title: '回答者',
-        dataIndex: 'manager.username',
-      }, {
-        title: '回答时间',
-        dataIndex: 'answerTime',
-        render: (text) => {
-          return text ? formatDate(text) : '';
-        },
-      }, {
-        title: '展示状态',
-        dataIndex: 'showStatus',
-        render: (text) => {
-          return SwitchSelectMap[text] || text;
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {(
-              <Link to={`/course/ask/detail/${record.id}`}>编辑</Link>
-            )}
-          </div>;
-        },
+    }, {
+      title: '回答状态',
+      dataIndex: 'answerStatus',
+      render: (text) => {
+        return AskStatusMap[text] || text;
       },
-    ];
+    }, {
+      title: '回答者',
+      dataIndex: 'manager.username',
+    }, {
+      title: '回答时间',
+      dataIndex: 'answerTime',
+      render: (text) => {
+        return text ? formatDate(text) : '';
+      },
+    }, {
+      title: '展示状态',
+      dataIndex: 'showStatus',
+      render: (text) => {
+        return SwitchSelectMap[text] || text;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <Link to={`/course/ask/detail/${record.id}`}>编辑</Link>
+          )}
+        </div>;
+      },
+    }];
+    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);
     Exercise.courseStruct().then((result) => {
-      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const list = result.map(row => { row.title = `${row.titleZh}`; row.value = row.id; return row; });
       this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
-      console.log(this.filterForm[0].tree);
       this.exerciseMap = getMap(result.map(row => {
-        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       }), 'id', 'title');
 
       this.setState({ exercise: result });
     });
+
+    Course.list().then((result) => {
+      this.filterForm[1].select = result.list.map(row => {
+        row.value = row.id;
+        return row;
+      });
+    });
   }
 
   initData() {
@@ -166,7 +193,6 @@ export default class extends Page {
         onAction={key => this.onAction(key)}
       /> */}
       <TableLayout
-        select
         columns={this.columns}
         list={this.state.list}
         pagination={this.state.page}

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

@@ -6,18 +6,25 @@ import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
-import { formatFormError, formatDate } from '@src/services/Tools';
+import { formatFormError, formatDate, formatTreeData, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
 import { UserUrl } from '../../../../Constant';
-// import { User } from '../../../stores/user';
+import { Exercise } from '../../../stores/exercise';
 import { Course } from '../../../stores/course';
 
 export default class extends Page {
   init() {
-    // Exercise.allStruct().then(result => {
-    //   result = result.filter(row => row.level === 2).map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
-    //   this.setState({ exercise: result });
-    // });
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}`; 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.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
   }
 
   initData() {
@@ -26,7 +33,7 @@ export default class extends Page {
     if (id) {
       handler = Course.getAsk({ id });
     } else {
-      handler = Promise.resolve({ others: [{ content: 123123123, answer: 123123 }, {}] });
+      handler = Promise.resolve({ others: [] });
     }
     handler
       .then(result => {
@@ -84,7 +91,7 @@ export default class extends Page {
       <h1>提问信息</h1>
       <Form>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
-          {/* {QuestionTypeMap[question.type]} */}
+          {this.exerciseMap[course.structId]}
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程'>
           <a href='' target='_blank'>{course.title}</a>

+ 45 - 47
front/project/admin/routes/course/data/page.js

@@ -45,60 +45,58 @@ export default class extends Page {
       select: DataType,
       placeholder: '请选择',
     }];
-    this.columns = [
-      {
-        title: '学科',
-        dataIndex: 'structId',
-        render: (text, record) => {
-          return `${record.parentStructId ? `${this.exerciseMap[record.parentStructId]}-` : ''}${this.exerciseMap[record.structId]}`;
-        },
+    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: 'dataType',
+      render: (text) => {
+        return DataTypeMap[text] || text;
       },
-      {
-        title: '适合新手',
-        dataIndex: 'isNovice',
-        render: (text) => {
-          return SwitchSelectMap[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>;
-        },
+    },
+    {
+      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; });
+      const list = result.map(row => { row.title = `${row.titleZh}`; 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.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       }), 'id', 'title');

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

@@ -87,10 +87,10 @@ export default class extends Page {
       },
     }];
     Exercise.courseStruct().then((result) => {
-      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const list = result.map(row => { row.title = `${row.titleZh}`; 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.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       }), 'id');

+ 4 - 254
front/project/admin/routes/course/detail/page.js

@@ -1,7 +1,7 @@
 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 { Form, Input, Button, Row, Col, InputNumber, Upload, DatePicker } from 'antd';
 import './index.less';
 import Editor from '@src/components/Editor';
 import Page from '@src/containers/Page';
@@ -110,7 +110,7 @@ export default class extends Page {
       title: '学员数量',
       dataIndex: 'studentNumber',
       render: (text, record) => {
-        return <Link to={`/course/student/${this.params.id}?timeId=${record.id}`}>{text}</Link>;
+        return <Link to={`/course/student/${this.params.id}?timeId=${record.id}`}>{text || 0}</Link>;
       },
     }, {
       title: '状态',
@@ -121,10 +121,10 @@ export default class extends Page {
     }];
 
     Exercise.courseStruct().then((result) => {
-      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const list = result.map(row => { row.title = `${row.titleZh}`; 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.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       }), 'id');
@@ -148,28 +148,6 @@ export default class extends Page {
         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) {
@@ -179,9 +157,6 @@ export default class extends Page {
             case 'online':
               this.refreshTime();
               break;
-            case 'vs':
-              this.refreshTeacher();
-              break;
             default:
           }
         }
@@ -227,32 +202,6 @@ export default class extends Page {
     });
   }
 
-  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;
@@ -492,209 +441,10 @@ export default class extends Page {
     </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:

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

@@ -155,6 +155,13 @@ export default class extends Page {
         this.submitInfo();
       }}>
         <Form>
+          <Row>
+            <Col span={12}><Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 10 }} label={'学员人数'}>
+              <InputNumber value={this.state.detail.number || 0} placeholder={'人数'} onChange={(value) => {
+                this.changeInfo('number', value);
+              }} />
+            </Form.Item></Col>
+          </Row>
           <Form.Item label='考分分布' />
           <Row>
             {ExperienceScore.map((row, index) => {

+ 5 - 2
front/project/admin/routes/course/index.js

@@ -1,13 +1,16 @@
+import list from './list';
 import ask from './ask';
 import askDetail from './askDetail';
 import invoice from './invoice';
-import list from './list';
 import detail from './detail';
+import vsDetail from './vsDetail';
 import data from './data';
 import dataDetail from './dataDetail';
+import study from './study';
+import studyDetail from './studyDetail';
 import experience from './experience';
 import experienceDetail from './experienceDetail';
 import student from './student';
 import Package from './package';
 
-export default [ask, askDetail, invoice, list, detail, data, dataDetail, experience, experienceDetail, student, Package];
+export default [list, ask, askDetail, invoice, detail, vsDetail, data, dataDetail, study, studyDetail, experience, experienceDetail, student, Package];

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

@@ -49,16 +49,16 @@ export default class extends Page {
     }, {
       key: 'addOnline',
       type: 'primary',
-      name: '创建直播课程',
+      name: '创建小班课程',
       render: (item) => {
         return <Link to='/course/detail?module=online'><Button type='primary'>{item.name}</Button></Link>;
       },
     }, {
       key: 'addVs',
       type: 'primary',
-      name: '创建1vs1课程',
+      name: '编辑1vs1课程',
       render: (item) => {
-        return <Link to='/course/detail?module=vs'><Button type='primary'>{item.name}</Button></Link>;
+        return <Link to='/course/vs'><Button type='primary'>{item.name}</Button></Link>;
       },
     }];
     this.columns = [{
@@ -94,7 +94,7 @@ export default class extends Page {
       render: (text, record) => {
         return <div className="table-button">
           {<Link to={`/course/detail/${record.id}`}>编辑</Link>}
-          {<Link to={`/course/student/${record.id}`}>查看学员</Link>}
+          {(record.courseModule === 'online') && <Link to={`/course/student/${record.id}`}>查看学员</Link>}
         </div>;
       },
     }];
@@ -105,10 +105,10 @@ export default class extends Page {
     });
 
     Exercise.courseStruct().then((result) => {
-      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      const list = result.map(row => { row.title = `${row.titleZh}`; 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.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       }), 'id', 'title');
@@ -118,7 +118,7 @@ export default class extends Page {
   }
 
   initData() {
-    Course.list(this.state.search).then(result => {
+    Course.list(Object.assign({ excludeVs: true }, this.state.search)).then(result => {
       this.setTableData(result.list, result.total);
     });
   }

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

@@ -111,7 +111,7 @@ export default class extends Page {
   init() {
     Exercise.courseStruct().then((result) => {
       const list = result.filter(row => row.level === 1).map(row => {
-        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.title = `${row.titleZh}`;
         row.value = row.id;
         return row;
       });
@@ -120,7 +120,7 @@ export default class extends Page {
       this.setState({ exercise: formatTreeData(list, 'id', 'title', 'parentId') });
     });
     Course.list().then((result) => {
-      this.itemList[4].select = result.list.map(row => {
+      this.itemList[5].select = result.list.map(row => {
         row.value = row.id;
         return row;
       });

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

@@ -5,7 +5,7 @@ export default {
   path: '/course/student',
   matchPath: '/course/student/:id?',
   key: 'course-student-detail',
-  title: '课程管理',
+  title: '学员管理',
   needLogin: true,
   module,
   group,

+ 298 - 129
front/project/admin/routes/course/student/page.js

@@ -1,157 +1,328 @@
 import React from 'react';
-import { Link } from 'react-router-dom';
-import { Button, Modal, Form, InputNumber, Row, Col } from 'antd';
+import moment from 'moment';
 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 { formatDate, bindSearch, getMap } from '@src/services/Tools';
+import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
+import { CourseSource, CourseStatus } from '../../../../Constant';
 import { Course } from '../../../stores/course';
-import { Exercise } from '../../../stores/exercise';
+import { User } from '../../../stores/user';
 
+const CourseSourceMap = getMap(CourseSource, 'value', 'label');
+const CourseStatusMap = getMap(CourseStatus, 'value', 'label');
 
 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>;
-      },
+    this.onlineAction = [{
+      key: 'addOnlineStudent',
+      name: '添加学员',
+    }];
+    this.onlineFilter = [{
+      key: 'id',
+      type: 'hidden',
+    }, {
+      key: 'timeId',
+      type: 'select',
+      allowClear: true,
+      select: [],
+      number: true,
+      name: '时间段',
     }, {
-      key: 'addOnline',
-      type: 'primary',
-      name: '创建直播课程',
-      render: (item) => {
-        return <Link to='/course/detail?module=online'><Button type='primary'>{item.name}</Button></Link>;
+      key: 'userId',
+      type: 'select',
+      name: '学员',
+      allowClear: true,
+      select: [],
+      number: true,
+      placeholder: '请输入',
+    }];
+    this.onlineList = [{
+      key: 'timeId',
+      type: 'select',
+      select: [],
+      name: '时间段',
+    }, {
+      key: 'userIds',
+      type: 'multiple',
+      name: '学员',
+      allowClear: true,
+      select: [],
+      number: true,
+      placeholder: '请输入',
+    }];
+    this.onlineColumns = [{
+      title: '时间段',
+      dataIndex: 'time',
+      render: (text) => {
+        return `${formatDate(text.startTime, 'YYYY-MM-DD')}~${formatDate(text.endTime, 'YYYY-MM-DD')}`;
       },
     }, {
-      key: 'addVs',
-      type: 'primary',
-      name: '创建1vs1课程',
-      render: (item) => {
-        return <Link to='/course/detail?module=vs'><Button type='primary'>{item.name}</Button></Link>;
+      title: '学员id',
+      dataIndex: 'userId',
+    }, {
+      title: '学员名称',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '手机号',
+      dataIndex: 'user.mobile',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<a onClick={() => {
+            this.deleteOnlineStudent(record);
+          }}>删除</a>}
+        </div>;
       },
     }];
-    this.columns = [{
-      title: '文章标题',
-      dataIndex: 'title',
+
+    this.vsAction = [{
+      key: 'addVsStudent',
+      name: '添加学员',
+    }];
+    this.vsList = [{
+      key: 'id',
+      type: 'hidden',
     }, {
-      title: '作者',
-      dataIndex: 'user',
-      render: (text) => {
-        return (text || {}).nickname;
+      key: 'userId',
+      type: 'select',
+      name: '学员',
+      select: [],
+      number: true,
+      placeholder: '请输入',
+    }, {
+      key: 'time',
+      type: 'daterange',
+      name: '有效期',
+    }, {
+      key: 'teacherId',
+      type: 'select',
+      select: [],
+      name: '老师',
+    }, {
+      key: 'vsNumber',
+      type: 'number',
+      name: '课时数',
+    }];
+    this.vsColumns = [{
+      title: '学员名称',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '有效期',
+      dataIndex: 'time',
+      render: (text, record) => {
+        return record.isUsed ? `${formatDate(record.useStartTime, 'YYYY-MM-DD')}~${formatDate(record.useEndTime, 'YYYY-MM-DD')}` : '';
       },
     }, {
-      title: '录入时间',
-      dataIndex: 'createTime',
+      title: '添加方式',
+      dataIndex: 'source',
       render: (text) => {
-        return formatDate(text);
+        return CourseSourceMap[text] || text;
       },
     }, {
-      title: '收藏数',
-      dataIndex: 'collectNumber',
+      title: '授课老师',
+      dataIndex: 'teacher.realname',
+    }, {
+      title: '状态',
+      dataIndex: 'status',
+      render: (text, record) => {
+        let status = 0;
+        if (record.isUsed) {
+          const end = new Date(record.useEndTime);
+          status = 1;
+          if (new Date().getTime() > end.getTime()) {
+            status = 2;
+          }
+        }
+        return CourseStatusMap[status] || status;
+      },
     }, {
       title: '操作',
       dataIndex: 'handler',
       render: (text, record) => {
         return <div className="table-button">
-          {<Link to={`/course/experience/detail/${record.id}`}>编辑</Link>}
+          {<a onClick={() => {
+            this.changeVs(record);
+          }}>修改</a>}
         </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');
+  initData() {
+    const { id } = this.params;
+    let handler;
+    if (id) {
+      handler = Course.get({ id });
+    }
+
+    handler
+      .then(result => {
+        this.setState({ module: result.courseModule });
+        this.setState({ data: result });
+        this.refresh();
+      });
+  }
+
+  refresh() {
+    const { id } = this.params;
+    const { module } = this.state;
+    switch (module) {
+      case 'video':
+        break;
+      case 'online':
+        bindSearch(this.onlineFilter, 'timeId', this, (search) => {
+          return Course.listTime(Object.assign({ courseId: id }, search));
+        }, (row) => {
+          return {
+            title: `${formatDate(row.startTime, 'YYYY-MM-DD')}~${formatDate(row.endTime, 'YYYY-MM-DD')}`,
+            value: row.id,
+          };
+        }, this.state.search.timeId ? Number(this.state.search.timeId) : null, null);
+        bindSearch(this.onlineFilter, 'userId', this, (search) => {
+          return User.list(search);
+        }, (row) => {
+          return {
+            title: `${row.nickname}(${row.mobile})`,
+            value: row.id,
+          };
+        }, null, null);
 
-      this.setState({ exercise: result });
+        bindSearch(this.onlineList, 'timeId', this, (search) => {
+          return Course.listTime(Object.assign({ courseId: id }, search));
+        }, (row) => {
+          return {
+            title: `${formatDate(row.startTime, 'YYYY-MM-DD')}~${formatDate(row.endTime, 'YYYY-MM-DD')}`,
+            value: row.id,
+          };
+        }, null, null);
+        bindSearch(this.onlineList, 'userIds', this, (search) => {
+          return User.list(search);
+        }, (row) => {
+          return {
+            title: `${row.nickname}(${row.mobile})`,
+            value: row.id,
+          };
+        }, [], null);
+        this.refreshOnline();
+        break;
+      case 'vs':
+        this.refreshVs();
+        break;
+      default:
+    }
+  }
+
+  refreshOnline() {
+    const { id } = this.params;
+    Course.listStudentOnline(Object.assign({ courseId: id }, this.state.search)).then(result => {
+      this.setTableData(result.list, result.total);
     });
   }
 
-  initData() {
-    Course.list(this.state.search).then(result => {
+  refreshVs() {
+    const { id } = this.params;
+    Course.listStudentVs(Object.assign({ courseId: id }, this.state.search)).then(result => {
       this.setTableData(result.list, result.total);
     });
   }
 
-  refreshInfo(result) {
-    this.setState({ info: result });
+  addOnlineStudentAction() {
+    const { id } = this.params;
+    asyncForm('添加', this.onlineList, {}, data => {
+      return Promise.all(data.userIds.map(userId => Course.addStudentOnline({ courseId: id, timeId: data.timeId, userId }))).then(() => {
+        asyncSMessage('添加成功!');
+        this.refresh();
+      });
+    }).catch(err => {
+      console.log(err);
+    });
   }
 
-  infoAction() {
-    const { info = {} } = this.state;
-    this.open(info);
+  deleteOnlineStudent(row) {
+    Course.delStudentOnline({ id: row.id }).then(() => {
+      asyncSMessage('删除成功!');
+      this.refresh();
+    });
   }
 
-  changeInfo(field, value) {
-    const { detail } = this.state;
-    detail[field] = value;
-    this.setState({ detail });
+  changeVs(record) {
+    const { id } = this.params;
+    record.time = [moment(record.useStartTime), moment(record.useEndTime)];
+    asyncForm('修改', this.vsList, record, data => {
+      return Course.editStudentVs(Object.assign({ courseId: id }, data)).then(() => {
+        asyncSMessage('添加成功!');
+        this.refresh();
+      });
+    }).then(component => {
+      bindSearch(this.vsList, 'userId', component, (search) => {
+        return User.list(search);
+      }, (row) => {
+        return {
+          title: `${row.nickname}(${row.mobile})`,
+          value: row.id,
+        };
+      }, record.userId, null);
+      bindSearch(this.vsList, 'teacherId', component, (search) => {
+        return Course.listTeacher(Object.assign({ courseId: id }, search));
+      }, (row) => {
+        return {
+          title: row.realname,
+          value: row.id,
+        };
+      }, record.teacherId, null);
+    });
   }
 
-  submitInfo() {
-    const { detail } = this.state;
-    System.setCourseIndex(detail).then(() => {
-      asyncSMessage('保存成功');
-      this.close(false, 'detail');
-      return this.refreshInfo(detail);
+  addVsStudentAction() {
+    const { id } = this.params;
+    asyncForm('添加', this.vsList, {}, data => {
+      ([data.useStartTime, data.useEndTime] = data.time);
+      return Course.addStudentVs(Object.assign({ courseId: id }, data)).then(() => {
+        asyncSMessage('添加成功!');
+        this.refresh();
+      });
+    }).then(component => {
+      bindSearch(this.vsList, 'userId', component, (search) => {
+        return User.list(search);
+      }, (row) => {
+        return {
+          title: `${row.nickname}(${row.mobile})`,
+          value: row.id,
+        };
+      }, null, null);
+      bindSearch(this.vsList, 'teacherId', component, (search) => {
+        return Course.listTeacher(Object.assign({ courseId: id }, search));
+      }, (row) => {
+        return {
+          title: row.realname,
+          value: row.id,
+        };
+      }, null, null);
     });
   }
 
-  renderView() {
-    const { exercise } = this.state;
+  renderOnline() {
     return <Block flex>
-      {exercise && <FilterLayout
+      {<FilterLayout
         show
-        itemList={this.filterForm}
+        itemList={this.onlineFilter}
         data={this.state.search}
         onChange={data => {
           this.search(data);
         }} />}
       <ActionLayout
-        itemList={this.actionList}
+        itemList={this.onlineAction}
         selectedKeys={this.state.selectedKeys}
         onAction={key => this.onAction(key)}
       />
       <TableLayout
-        select
-        columns={this.columns}
+        columns={this.onlineColumns}
         list={this.state.list}
         pagination={this.state.page}
         loading={this.props.core.loading}
@@ -159,41 +330,39 @@ export default class extends Page {
         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>;
   }
+
+  renderVs() {
+    const { data } = this.state;
+    return <Block flex>
+      {data.vsType === 'novice' && <ActionLayout
+        itemList={this.vsAction}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />}
+      <TableLayout
+        columns={this.vsColumns}
+        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>;
+  }
+
+  renderView() {
+    switch (this.state.module) {
+      case 'online':
+        return [this.renderOnline()];
+      case 'vs':
+        return [this.renderVs()];
+      case 'video':
+        return [];
+      default:
+        return <div />;
+    }
+  }
 }

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

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

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

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

+ 185 - 0
front/project/admin/routes/course/study/page.js

@@ -0,0 +1,185 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import './index.less';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+import FilterLayout from '@src/layouts/FilterLayout';
+// import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, formatTreeData, formatDate, bindSearch } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { CourseModule, CourseStatus } from '../../../../Constant';
+import { Course } from '../../../stores/course';
+import { Exercise } from '../../../stores/exercise';
+import { User } from '../../../stores/user';
+
+const CourseModuleMap = getMap(CourseModule, 'value', 'label');
+const CourseStatusMap = getMap(CourseStatus, 'value', 'label');
+
+export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.exerciseMap = {};
+
+    this.filterForm = [{
+      key: 'courseModule',
+      type: 'select',
+      name: '类型',
+      allowClear: true,
+      select: CourseModule,
+    }, {
+      key: 'structId',
+      type: 'tree',
+      allowClear: true,
+      name: '学科',
+      select: [],
+      placeholder: '请选择',
+      number: true,
+    }, {
+      key: 'courseId',
+      type: 'select',
+      name: '课程名称',
+      allowClear: true,
+      select: [],
+      number: true,
+    }, {
+      key: 'userId',
+      type: 'select',
+      name: '学生',
+      allowClear: true,
+      select: [],
+      number: true,
+    }, {
+      key: 'teacher',
+      type: 'input',
+      name: '老师',
+    }];
+
+    this.columns = [{
+      title: '学生id',
+      dataIndex: 'userId',
+      render: (text, record) => {
+        return `${text}/${record.user ? record.user.nickname : ''}`;
+      },
+    }, {
+      title: '课程类型',
+      dataIndex: 'course.courseModule',
+      render: (text) => {
+        return CourseModuleMap[text] || text;
+      },
+    }, {
+      title: '课程名称',
+      dataIndex: 'course.title',
+    }, {
+      title: '授课老师',
+      dataIndex: 'teacher',
+      render: (text, record) => {
+        return text || record.course.teacher;
+      },
+    }, {
+      title: '有效期',
+      dataIndex: 'time',
+      render: (text, record) => {
+        return record.isUsed ? `${formatDate(record.useStartTime, 'YYYY-MM-DD')}~${formatDate(record.useEndTime, 'YYYY-MM-DD')}` : '';
+      },
+    }, {
+      title: '上次学习时间',
+      dataIndex: 'lastTime',
+      render: (text) => {
+        return text ? `${formatDate(text)}` : '';
+      },
+    }, {
+      title: '状态',
+      dataIndex: 'status',
+      render: (text, record) => {
+        let status = 0;
+        if (record.isUsed) {
+          const end = new Date(record.useEndTime);
+          status = 1;
+          if (new Date().getTime() > end.getTime()) {
+            status = 2;
+          }
+        }
+        return CourseStatusMap[status] || status;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<Link to={`/course/study/detail/${record.id}`}>查看</Link>}
+          {record.isUsed > 0 && !record.isStop && (
+            <a onClick={() => {
+              this.stopAction(record.id);
+            }}>停用</a>
+          )}
+        </div>;
+      },
+    }];
+
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}`; row.value = row.id; return row; });
+      this.filterForm[1].tree = formatTreeData(list, 'id', 'title', 'parentId');
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}`;
+        row.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
+
+    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, null);
+  }
+
+  init() {
+    Course.list().then((result) => {
+      this.filterForm[2].select = result.list.map(row => {
+        row.value = row.id;
+        return row;
+      });
+    });
+  }
+
+  initData() {
+    Course.listStudy(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  stopAction(id) {
+    return Course.editStudy({ id, isStop: 1 }).then(() => {
+      asyncSMessage('停用成功!');
+      this.refresh();
+    });
+  }
+
+  renderView() {
+    const { exercise } = this.state;
+    return <Block flex>
+      {exercise && <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} />}
+      <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/studyDetail/index.js

@@ -0,0 +1,16 @@
+import module from '../../module';
+import group from '../group';
+
+export default {
+  path: '/course/study/detail',
+  matchPath: '/course/study/detail/:id?',
+  key: 'course-study-detail',
+  title: '学习记录详情',
+  needLogin: true,
+  module,
+  group,
+  showKey: 'course-study',
+  component() {
+    return import('./page');
+  },
+};

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

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

+ 332 - 0
front/project/admin/routes/course/studyDetail/page.js

@@ -0,0 +1,332 @@
+import React from 'react';
+import moment from 'moment';
+import { DatePicker, Checkbox, Modal, Form, Input, Row, Col, Button, 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 { formatDate } from '@src/services/Tools';
+import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
+import { UserUrl } from '../../../../Constant';
+import { Course } from '../../../stores/course';
+import { User } from '../../../stores/user';
+import { System } from '../../../stores/system';
+
+
+export default class extends Page {
+  init() {
+    this.videoColumns = [{
+      title: '时间段',
+      dataIndex: 'time',
+      render: (text) => {
+        return `${formatDate(text.startTime, 'YYYY-MM-DD')}~${formatDate(text.endTime, 'YYYY-MM-DD')}`;
+      },
+    }, {
+      title: '学员id',
+      dataIndex: 'userId',
+    }, {
+      title: '学员名称',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '手机号',
+      dataIndex: 'user.mobile',
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {<a onClick={() => {
+            this.deleteOnlineStudent(record);
+          }}>删除</a>}
+        </div>;
+      },
+    }];
+
+    this.vsAction = [{
+      key: 'addAppointment',
+      name: '添加预约',
+    }];
+    this.vsList = [{
+      key: 'id',
+      type: 'hidden',
+    }, {
+      key: 'title',
+      type: 'input',
+      name: '课程名称',
+    }, {
+      key: 'timerange',
+      type: 'daterange',
+      name: '上课时间',
+    }, {
+      key: 'channel',
+      type: 'input',
+      name: '频道号',
+    }];
+    this.vsColumns = [{
+      title: '课时序号',
+      dataIndex: 'no',
+      render: (text) => {
+        const { data } = this.state;
+        return `${text}/${data.vsNumber}`;
+      },
+    }, {
+      title: '上课时间',
+      dataIndex: 'time',
+      render: (text, record) => {
+        return <DatePicker.RangePicker value={[record.startTime, record.endTime]} onChange={(value) => {
+          this.changeAppointment(record.id, { startTime: value[0], endTime: value[1] });
+        }} />;
+      },
+    }, {
+      title: '课程名称',
+      dataIndex: 'title',
+    }, {
+      title: '频道号',
+      dataIndex: 'channel',
+    }, {
+      title: '学习进度',
+      dataIndex: 'isFinish',
+      render: (text, record) => {
+        return <Checkbox checked={text > 0} onChange={(e) => {
+          this.changeAppointment(record.id, { isFinish: e.target.value ? 1 : 0 });
+        }} />;
+      },
+    }, {
+      title: '预习作业',
+      dataIndex: 'userPaper',
+      render: (text, record) => {
+        return text ? <a onClick={() => {
+          User.locationUser(record.userId, `${UserUrl}/paper/report/${record.reportId}`);
+        }}>查看{text.times > 0 ? '(已完成)' : ''}</a> : '';
+      },
+    }, {
+      title: '笔记批阅',
+      dataIndex: 'noteList',
+      render: (text, record) => {
+        return <a onClick={() => {
+          this.noteAction(record);
+        }}>查看</a>;
+      },
+    }, {
+      title: '课后补充',
+      dataIndex: 'supplyList',
+      render: (text, record) => {
+        return <a onClick={() => {
+          this.supplyAction(record);
+        }}>查看</a>;
+      },
+    }];
+  }
+
+  initData() {
+    const { id } = this.params;
+    let handler;
+    if (id) {
+      handler = Course.listStudy({ ids: [id] });
+    }
+
+    handler
+      .then(result => {
+        const [row] = result.list;
+        if (!row) {
+          asyncSMessage('记录不存在');
+          return;
+        }
+        const { course } = row;
+        this.setState({ module: course.courseModule });
+        this.setState({ data: row });
+        this.refresh();
+      });
+  }
+
+  refresh() {
+    // const { id } = this.params;
+    const { module } = this.state;
+    switch (module) {
+      case 'video':
+        this.refreshVideo();
+        break;
+      case 'online':
+        break;
+      case 'vs':
+        this.refreshVs();
+        break;
+      default:
+    }
+  }
+
+  refreshVideo() {
+    // const { id } = this.params;
+    // Course.listStudentOnline(Object.assign({ courseId: id }, this.state.search)).then(result => {
+    //   this.setTableData(result.list, result.total);
+    // });
+  }
+
+  refreshVs() {
+    const { id } = this.params;
+    User.listCourseAppointment(Object.assign({ courseId: id }, this.state.search)).then(result => {
+      result.list = result.list.map(row => {
+        row.startTime = moment(row.startTime);
+        row.endTime = moment(row.endTime);
+        return row;
+      });
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  changeAppointment(id, data) {
+    data.id = id;
+    return User.editCourseAppointment(data).then(() => {
+      this.refreshVs();
+      this.cleanInfo();
+    });
+  }
+
+  addAppointmentAction() {
+    const { id } = this.params;
+    asyncForm('添加', this.vsList, {}, info => {
+      const { data } = this.state;
+      ([info.startTime, info.endTime] = info.timerange);
+      return User.addCourseAppointment(Object.assign({ recordId: id, userId: data.userId, courseId: data.courseId, noteList: [], supplyList: [] }, info)).then(() => {
+        asyncSMessage('添加成功!');
+        this.refreshVs();
+      });
+    }).catch(err => {
+      console.log(err);
+    });
+  }
+
+  noteAction(record) {
+    this.open(record, 'note');
+  }
+
+  supplyAction(record) {
+    this.open(record, 'supply');
+  }
+
+  deleteAppointment(row) {
+    User.delCourseAppointment({ id: row.id }).then(() => {
+      asyncSMessage('删除成功!');
+      this.refresh();
+    });
+  }
+
+  changeInfo(key, data) {
+    const info = this.state[key] || {};
+    this.setState({ [key]: Object.assign(info, data) });
+  }
+
+  cleanInfo() {
+    this.setState({ supplyInfo: null, noteInfo: null });
+  }
+
+  renderVs() {
+    const { data, page } = this.state;
+    return <Block flex>
+      {data.vsNumber > page.total && <ActionLayout
+        itemList={this.vsAction}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />}
+      <TableLayout
+        columns={this.vsColumns}
+        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.note && <Modal visible closable title='课后笔记' footer={null} onCancel={() => {
+        this.cleanInfo();
+        this.close(false, 'note');
+      }}>
+        {(this.state.note.noteList || []).map(row => {
+          return <p>{formatDate(row.time)}: {<a href={row.url} target='_blank'>{row.name}</a>}</p>;
+        })}
+        <Form>
+          <Row>
+            <Col span={1}><Upload
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                this.changeInfo('noteInfo', { url: result.url, name: file.name, time: new Date() });
+                return Promise.reject();
+              })}
+            >
+              <Button>上传文档{(this.state.noteInfo || {}).url ? '(已上传)' : ''}</Button>
+            </Upload></Col>
+            <Col span={1} offset={20}><Button type='primary' onClick={() => {
+              if (!this.state.noteInfo || !this.state.noteInfo.url) return;
+              let { noteList = [] } = this.state.note;
+              noteList = noteList || [];
+              noteList.push(this.state.noteInfo);
+              this.changeAppointment(this.state.note.id, { noteList });
+            }}>发布</Button></Col>
+          </Row>
+        </Form>
+      </Modal>}
+      {this.state.supply && <Modal visible closable title='课后补充' footer={null} onCancel={() => {
+        this.cleanInfo();
+        this.close(false, 'supply');
+      }}>
+        {(this.state.supply.supplyList || []).map(row => {
+          return [<p>{formatDate(row.time)}:{<a href={row.url} target='_blank'>{row.name}</a>}</p>, <p>留言 - {row.content}</p>];
+        })}
+        <Form>
+          <Row>
+            <Col span={12}>
+              <Input value={(this.state.supplyInfo || {}).content || ''} onChange={value => {
+                this.changeInfo('supplyInfo', { content: value });
+              }} />
+            </Col>
+            <Col span={1}><Upload
+              showUploadList={false}
+              beforeUpload={(file) => System.uploadImage(file).then((result) => {
+                this.changeInfo('supplyInfo', { url: result.url, name: file.name, time: new Date() });
+                return Promise.reject();
+              })}
+            >
+              <Button>上传文档{(this.state.supplyInfo || {}).url ? '(已上传)' : ''}</Button>
+            </Upload></Col>
+            <Col span={1} offset={10}><Button type='primary' onClick={() => {
+              if (!this.state.supplyInfo || !this.state.supplyInfo.url) return;
+              let { supplyList = [] } = this.state.supply;
+              supplyList = supplyList || [];
+              supplyList.push(this.state.supplyInfo);
+              this.changeAppointment(this.state.supply.id, { supplyList });
+            }}>发布</Button></Col>
+          </Row>
+        </Form>
+      </Modal>}
+    </Block>;
+  }
+
+  renderVideo() {
+    return <Block flex>
+      <TableLayout
+        columns={this.videoColumns}
+        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>;
+  }
+
+  renderView() {
+    switch (this.state.module) {
+      case 'online':
+        return [];
+      case 'vs':
+        return [this.renderVs()];
+      case 'video':
+        return [this.renderVideo()];
+      default:
+        return <div />;
+    }
+  }
+}

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

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

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

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

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

@@ -0,0 +1,304 @@
+import React from 'react';
+import { Link } from 'react-router-dom';
+import { Form, Input, Button, Row, Col, InputNumber, Upload, Card, Icon, Tabs, Spin } from 'antd';
+import './index.less';
+import Editor from '@src/components/Editor';
+import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+// import FileUpload from '@src/components/FileUpload';
+import { formatFormError } from '@src/services/Tools';
+import { asyncSMessage } from '@src/services/AsyncTools';
+import { CourseVsType } from '../../../../Constant';
+import { Course } from '../../../stores/course';
+import { System } from '../../../stores/system';
+
+export default class extends Page {
+  init() {
+    this.state.tab = CourseVsType[0].value;
+  }
+
+  initData() {
+    this.changeCourse(this.state.tab);
+  }
+
+  changeCourse(key) {
+    this.setState({ tab: key, loading: true });
+    Course.list({ courseModule: 'vs' })
+      .then(result => {
+        const { form } = this.props;
+        const list = result.list.filter(row => row.vsType === key);
+        let row = {};
+        if (list.length > 0) {
+          ([row] = list);
+          Course.get({ id: row.id }).then(r => {
+            form.setFieldsValue(r);
+            this.setState({ data: r, loading: false });
+            this.refreshTeacher(row.id);
+          });
+        } else {
+          form.resetFields();
+          this.setState({ data: {}, loading: false, teacher: false });
+        }
+      });
+  }
+
+  refreshTeacher(id) {
+    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;
+    form.validateFields((err) => {
+      if (!err) {
+        const data = form.getFieldsValue();
+        data.vsType = this.state.tab;
+        data.parentStructId = 0;
+        data.structId = 0;
+        data.extend = '';
+        data.courseModule = 'vs';
+        let handler;
+        if (data.id) {
+          handler = Course.edit(data);
+        } else {
+          handler = Course.add(data);
+        }
+        handler.then(() => {
+          asyncSMessage('保存成功');
+          if (!data.id) {
+            this.setState({ teacher: true, teachers: [] });
+          }
+        }).catch((e) => {
+          if (e.result) form.setFields(formatFormError(data, e.result));
+        });
+      }
+    });
+  }
+
+  renderVs() {
+    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('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')(
+            <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, data } = 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: data.id }, row));
+                }
+                handler.then(() => {
+                  this.refreshTeacher(data.id);
+                });
+              }}>{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() {
+    return [this.renderVs(), this.renderInfoVs(), this.renderTeacher()];
+  }
+
+  renderView() {
+    const { tab, data } = this.state;
+    return <div flex>
+      <Tabs activeKey={tab} tabBarExtraContent={data.id > 0 && <Link to={`/course/student/${data.id}`}>查看学员</Link>} onChange={(value) => {
+        this.changeCourse(value);
+      }}>
+        {CourseVsType.map((row) => {
+          return <Tabs.TabPane tab={row.label} key={row.value} />;
+        })}
+      </Tabs>
+      <Spin spinning={this.state.loading}>{this.renderContent()}</Spin>
+      <Row type="flex" justify="center">
+        <Col>
+          <Button type="primary" onClick={() => {
+            this.submit();
+          }}>保存</Button>
+        </Col>
+      </Row>
+    </div>;
+  }
+}

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

@@ -76,6 +76,7 @@ export default class extends Page {
           showUploadList={false}
           beforeUpload={(file) => System.importRank(file).then((result) => {
             asyncSMessage(result);
+            return Promise.reject();
           })}
         >
           <Button>{item.name}</Button>

+ 52 - 54
front/project/admin/routes/user/ask/page.js

@@ -74,64 +74,62 @@ export default class extends Page {
       number: true,
       placeholder: '请输入',
     }];
-    this.columns = [
-      {
-        title: '题型',
-        dataIndex: 'type',
-        render: (text, record) => {
-          return QuestionTypeMap[record.question.type];
-        },
+    this.columns = [{
+      title: '题型',
+      dataIndex: 'type',
+      render: (text, record) => {
+        return QuestionTypeMap[record.question.type];
       },
-      {
-        title: '题目id',
-        dataIndex: 'questionNo.no',
+    },
+    {
+      title: '题目id',
+      dataIndex: 'questionNo.no',
+    },
+    {
+      title: '提问时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
       },
-      {
-        title: '提问时间',
-        dataIndex: 'createTime',
-        render: (text) => {
-          return formatDate(text);
-        },
+    },
+    {
+      title: '提问摘要',
+      dataIndex: 'content',
+    }, {
+      title: '提问者',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '回答状态',
+      dataIndex: 'answerStatus',
+      render: (text) => {
+        return AskStatusMap[text] || text;
       },
-      {
-        title: '提问摘要',
-        dataIndex: 'content',
-      }, {
-        title: '提问者',
-        dataIndex: 'user.nickname',
-      }, {
-        title: '回答状态',
-        dataIndex: 'answerStatus',
-        render: (text) => {
-          return AskStatusMap[text] || text;
-        },
-      }, {
-        title: '回答者',
-        dataIndex: 'manager.username',
-      }, {
-        title: '回答时间',
-        dataIndex: 'answerTime',
-        render: (text) => {
-          return text ? formatDate(text) : '';
-        },
-      }, {
-        title: '展示状态',
-        dataIndex: 'showStatus',
-        render: (text) => {
-          return SwitchSelectMap[text] || text;
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {(
-              <Link to={`/user/ask/detail/${record.id}`}>编辑</Link>
-            )}
-          </div>;
-        },
+    }, {
+      title: '回答者',
+      dataIndex: 'manager.username',
+    }, {
+      title: '回答时间',
+      dataIndex: 'answerTime',
+      render: (text) => {
+        return text ? formatDate(text) : '';
       },
-    ];
+    }, {
+      title: '展示状态',
+      dataIndex: 'showStatus',
+      render: (text) => {
+        return SwitchSelectMap[text] || text;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <Link to={`/user/ask/detail/${record.id}`}>编辑</Link>
+          )}
+        </div>;
+      },
+    }];
     bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);
     }, (row) => {

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

@@ -28,7 +28,7 @@ export default class extends Page {
     if (id) {
       handler = Question.getAsk({ id });
     } else {
-      handler = Promise.resolve({ others: [{ content: 123123123, answer: 123123 }, {}] });
+      handler = Promise.resolve({ others: [] });
     }
     handler
       .then(result => {

+ 1 - 11
front/project/admin/routes/user/detail/page.js

@@ -198,12 +198,6 @@ export default class extends Page {
         })}
       </div>
       <div className="group">
-        <h2>已开通课程</h2>
-        {(data.classes || []).map(cls => {
-          return <p>{this.categoryMap[cls.category]}: {formatDate(cls.startTime)} - {formatDate(cls.expireTime)}</p>;
-        })}
-      </div>
-      <div className="group">
         <h2>消费记录</h2>
         <TableLayout
           columns={this.columns}
@@ -226,11 +220,7 @@ export default class extends Page {
       <div className="group">
         <h2>学习数据</h2>
         <Button onClick={() => {
-          User.token({ id: this.params.id || 1 })
-            .then(token => {
-              const w = window.open('about:blank');
-              w.location.href = `${UserUrl}/my/data?token=${token}`;
-            });
+          User.locationUser(this.params.id, `${UserUrl}/my/data`);
         }}>查看</Button>
       </div>
     </Block>;

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

@@ -6,6 +6,7 @@ import FilterLayout from '@src/layouts/FilterLayout';
 // import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { UserUrl } from '../../../../Constant';
 import { Exercise } from '../../../stores/exercise';
 import { Preview } from '../../../stores/preview';
 import { User } from '../../../stores/user';
@@ -21,7 +22,7 @@ export default class extends Page {
   init() {
     this.filterForm = [
       {
-        key: 'category',
+        key: 'structId',
         type: 'select',
         allowClear: true,
         name: '课程',
@@ -29,11 +30,11 @@ export default class extends Page {
         number: true,
         onChange: (value) => {
           this.refreshPreview(value);
-          this.filterF.setFieldsValue({ preview_id: '' });
+          this.filterF.setFieldsValue({ previewId: '' });
         },
       },
       {
-        key: 'preview_id',
+        key: 'previewId',
         type: 'select',
         name: '练习册',
         allowClear: true,
@@ -110,7 +111,10 @@ export default class extends Page {
       render: (text, record) => {
         return <div className="table-button">
           {(
-            <a href={`/subject/preview/detail/${record.id}`} target='_blank'>查看</a>
+            <a onClick={() => {
+              const url = `${UserUrl}paper/report/${record.id}`;
+              User.locationUser(record.userId, url);
+            }}>查看</a>
           )}
         </div>;
       },

+ 10 - 3
front/project/admin/routes/user/service/page.js

@@ -139,10 +139,10 @@ export default class extends Page {
       dataIndex: 'handler',
       render: (text, record) => {
         return <div className="table-button">
-          {!record.isUsed && (
+          {record.isUsed > 0 && !record.isStop && (
             <a onClick={() => {
-              this.editAction(record);
-            }}>编辑</a>
+              this.stopAction(record.id);
+            }}>停用</a>
           )}
         </div>;
       },
@@ -188,6 +188,13 @@ export default class extends Page {
     });
   }
 
+  stopAction(id) {
+    return User.editService({ id, isStop: 1 }).then(() => {
+      asyncSMessage('停用成功!');
+      this.refresh();
+    });
+  }
+
   renderView() {
     return <Block flex>
       <FilterLayout

+ 24 - 0
front/project/admin/stores/course.js

@@ -180,6 +180,30 @@ export default class CourseStore extends BaseStore {
   delStudentOnline(params) {
     return this.apiDel('/course/student/online/delete', params);
   }
+
+  listStudentVs(params) {
+    return this.apiGet('/course/student/vs/list', params);
+  }
+
+  addStudentVs(params) {
+    return this.apiPost('/course/student/vs/add', params);
+  }
+
+  editStudentVs(params) {
+    return this.apiPut('/course/student/vs/edit', params);
+  }
+
+  getStudentVs(params) {
+    return this.apiGet('/course/student/vs/detail', params);
+  }
+
+  delStudentVs(params) {
+    return this.apiDel('/course/student/vs/delete', params);
+  }
+
+  listStudy(params) {
+    return this.apiGet('/course/study/list', params);
+  }
 }
 
 export const Course = new CourseStore({ key: 'course' });

+ 30 - 2
front/project/admin/stores/user.js

@@ -1,6 +1,14 @@
 import BaseStore from '@src/stores/base';
 
 export default class UserStore extends BaseStore {
+  locationUser(id, url) {
+    this.token({ id })
+      .then(token => {
+        const w = window.open('about:blank');
+        w.location.href = `${url}?token=${token}`;
+      });
+  }
+
   list(params) {
     return this.apiGet('/user/list', params);
   }
@@ -65,8 +73,28 @@ export default class UserStore extends BaseStore {
     return this.apiGet('/user/preview/list', params);
   }
 
-  listPay(params) {
-    return this.apiGet('/user/pay/list', params);
+  listCourseAppointment(params) {
+    return this.apiGet('/user/course/appointment/list', params);
+  }
+
+  addCourseAppointment(params) {
+    return this.apiPost('/user/course/appointment/add', params);
+  }
+
+  editCourseAppointment(params) {
+    return this.apiPut('/user/course/appointment/edit', params);
+  }
+
+  getCourseAppointment(params) {
+    return this.apiGet('/user/course/appointment/detail', params);
+  }
+
+  delCourseAppointment(params) {
+    return this.apiDel('/user/course/appointment/delete', params);
+  }
+
+  listOrder(params) {
+    return this.apiGet('/user/order/list', params);
   }
 }
 

+ 2 - 0
front/src/layouts/FormLayout/index.js

@@ -111,6 +111,8 @@ class FormLayout extends Component {
         return <Switch {...item} className={item.class} disabled={!!item.disabled} />;
       case 'date':
         return <DatePicker {...item} className={item.class} placeholder={item.placeholder} disabled={!!item.disabled} />;
+      case 'daterange':
+        return <DatePicker.RangePicker {...item} className={item.class} />;
       case 'hidden':
         return <Input type="hidden" />;
       case 'image':

+ 8 - 8
front/src/services/Tools.js

@@ -84,14 +84,14 @@ export function loadScript(url, callback) {
   script.async = true;
   script.defer = true;
   if (script.readyState) {
-    script.onreadystatechange = function() {
+    script.onreadystatechange = function () {
       if (script.readyState === 'loaded' || script.readyState === 'complete') {
         script.onreadystatechange = null;
         if (callback) callback();
       }
     };
   } else {
-    script.onload = function() {
+    script.onload = function () {
       if (callback) callback();
     };
   }
@@ -303,7 +303,7 @@ export function flattenObject(ob, prefix = '') {
 function _formatMoney(s, n) {
   if (!s) s = 0;
   n = n > 0 && n <= 20 ? n : 2;
-  s = `${parseFloat(`${s}`.replace(/[^\d.-]/g, '')).toFixed(n)} `;
+  s = `${parseFloat(`${s}`.replace(/[^\d.-]/g, '')).toFixed(n)}`;
   const l = s
     .split('.')[0]
     .split('')
@@ -316,14 +316,14 @@ function _formatMoney(s, n) {
   return `${t
     .split('')
     .reverse()
-    .join('')}.${r} `;
+    .join('')}.${r}`;
 }
 
 export function formatMoney(price) {
   if (typeof price === 'object') {
-    return `${price.symbol} ${_formatMoney(price.value, 2)} `;
+    return `${price.symbol} ${_formatMoney(price.value, 2)}`;
   }
-  return `${_formatMoney(price, 2)} `;
+  return `${_formatMoney(price, 2)}`;
 }
 
 export function bindTags(targetList, field, render, def, notFound) {
@@ -342,7 +342,7 @@ export function bindSearch(targetList, field, Component, listFunc, render, def,
   targetList.forEach((row, i) => {
     if (row.key === field) index = i;
   });
-  const key = `lastFetchId${field} ${index} `;
+  const key = `lastFetchId${field}${index}${generateUUID(4)}`;
   if (!Component[key]) Component[key] = 0;
   const searchFunc = data => {
     Component[key] += 1;
@@ -383,7 +383,7 @@ export function bindSearch(targetList, field, Component, listFunc, render, def,
 }
 
 export function generateSearch(field, props, Component, listFunc, render, def, notFound = null) {
-  const key = `lastFetchId${field} `;
+  const key = `lastFetchId${field}${generateUUID(4)}`;
   if (!Component[key]) Component[key] = 0;
   let item = {
     showSearch: true,

+ 19 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/module/VsCourseType.java

@@ -0,0 +1,19 @@
+package com.qxgmat.data.constants.enums.module;
+
+public enum VsCourseType {
+    NOVICE("novice"),
+    COACH("coach"),
+    SYSTEM("system"),
+    ANSWER("answer"),
+
+    ;
+    public String key;
+    private VsCourseType(String key){
+        this.key = key;
+    }
+
+    public static VsCourseType ValueOf(String name){
+        if (name == null) return null;
+        return VsCourseType.valueOf(name.toUpperCase());
+    }
+}

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

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

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

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

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

@@ -25,12 +25,18 @@ public class Course implements Serializable {
     private Integer parentStructId;
 
     /**
-     * 课程类型
+     * 课程模块
      */
     @Column(name = "`course_module`")
     private String courseModule;
 
     /**
+     * 1vs1课程类型
+     */
+    @Column(name = "`vs_type`")
+    private String vsType;
+
+    /**
      * 从struct上继承extend
      */
     @Column(name = "`extend`")
@@ -221,24 +227,42 @@ public class Course implements Serializable {
     }
 
     /**
-     * 获取课程类型
+     * 获取课程模块
      *
-     * @return course_module - 课程类型
+     * @return course_module - 课程模块
      */
     public String getCourseModule() {
         return courseModule;
     }
 
     /**
-     * 设置课程类型
+     * 设置课程模块
      *
-     * @param courseModule 课程类型
+     * @param courseModule 课程模块
      */
     public void setCourseModule(String courseModule) {
         this.courseModule = courseModule;
     }
 
     /**
+     * 获取1vs1课程类型
+     *
+     * @return vs_type - 1vs1课程类型
+     */
+    public String getVsType() {
+        return vsType;
+    }
+
+    /**
+     * 设置1vs1课程类型
+     *
+     * @param vsType 1vs1课程类型
+     */
+    public void setVsType(String vsType) {
+        this.vsType = vsType;
+    }
+
+    /**
      * 获取从struct上继承extend
      *
      * @return extend - 从struct上继承extend
@@ -672,6 +696,7 @@ public class Course implements Serializable {
         sb.append(", structId=").append(structId);
         sb.append(", parentStructId=").append(parentStructId);
         sb.append(", courseModule=").append(courseModule);
+        sb.append(", vsType=").append(vsType);
         sb.append(", extend=").append(extend);
         sb.append(", title=").append(title);
         sb.append(", crowd=").append(crowd);
@@ -740,9 +765,9 @@ public class Course implements Serializable {
         }
 
         /**
-         * 设置课程类型
+         * 设置课程模块
          *
-         * @param courseModule 课程类型
+         * @param courseModule 课程模块
          */
         public Builder courseModule(String courseModule) {
             obj.setCourseModule(courseModule);
@@ -750,6 +775,16 @@ public class Course implements Serializable {
         }
 
         /**
+         * 设置1vs1课程类型
+         *
+         * @param vsType 1vs1课程类型
+         */
+        public Builder vsType(String vsType) {
+            obj.setVsType(vsType);
+            return this;
+        }
+
+        /**
          * 设置从struct上继承extend
          *
          * @param extend 从struct上继承extend

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

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

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

@@ -24,12 +24,30 @@ public class PreviewPaper implements Serializable {
     private Integer courseId;
 
     /**
+     * 课程模块
+     */
+    @Column(name = "`course_module`")
+    private String courseModule;
+
+    /**
      * 课程课时
      */
     @Column(name = "`course_no`")
     private Integer courseNo;
 
     /**
+     * 课程时间段
+     */
+    @Column(name = "`course_time`")
+    private Integer courseTime;
+
+    /**
+     * 预约id
+     */
+    @Column(name = "`appointment_id`")
+    private Integer appointmentId;
+
+    /**
      * 题目编号id:json
      */
     @Column(name = "`question_no_ids`")
@@ -124,6 +142,24 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
+     * 获取课程模块
+     *
+     * @return course_module - 课程模块
+     */
+    public String getCourseModule() {
+        return courseModule;
+    }
+
+    /**
+     * 设置课程模块
+     *
+     * @param courseModule 课程模块
+     */
+    public void setCourseModule(String courseModule) {
+        this.courseModule = courseModule;
+    }
+
+    /**
      * 获取课程课时
      *
      * @return course_no - 课程课时
@@ -142,6 +178,42 @@ public class PreviewPaper implements Serializable {
     }
 
     /**
+     * 获取课程时间段
+     *
+     * @return course_time - 课程时间段
+     */
+    public Integer getCourseTime() {
+        return courseTime;
+    }
+
+    /**
+     * 设置课程时间段
+     *
+     * @param courseTime 课程时间段
+     */
+    public void setCourseTime(Integer courseTime) {
+        this.courseTime = courseTime;
+    }
+
+    /**
+     * 获取预约id
+     *
+     * @return appointment_id - 预约id
+     */
+    public Integer getAppointmentId() {
+        return appointmentId;
+    }
+
+    /**
+     * 设置预约id
+     *
+     * @param appointmentId 预约id
+     */
+    public void setAppointmentId(Integer appointmentId) {
+        this.appointmentId = appointmentId;
+    }
+
+    /**
      * 获取题目编号id:json
      *
      * @return question_no_ids - 题目编号id:json
@@ -286,7 +358,10 @@ public class PreviewPaper implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", title=").append(title);
         sb.append(", courseId=").append(courseId);
+        sb.append(", courseModule=").append(courseModule);
         sb.append(", courseNo=").append(courseNo);
+        sb.append(", courseTime=").append(courseTime);
+        sb.append(", appointmentId=").append(appointmentId);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", paperModule=").append(paperModule);
         sb.append(", userIds=").append(userIds);
@@ -339,6 +414,16 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
+         * 设置课程模块
+         *
+         * @param courseModule 课程模块
+         */
+        public Builder courseModule(String courseModule) {
+            obj.setCourseModule(courseModule);
+            return this;
+        }
+
+        /**
          * 设置课程课时
          *
          * @param courseNo 课程课时
@@ -349,6 +434,26 @@ public class PreviewPaper implements Serializable {
         }
 
         /**
+         * 设置课程时间段
+         *
+         * @param courseTime 课程时间段
+         */
+        public Builder courseTime(Integer courseTime) {
+            obj.setCourseTime(courseTime);
+            return this;
+        }
+
+        /**
+         * 设置预约id
+         *
+         * @param appointmentId 预约id
+         */
+        public Builder appointmentId(Integer appointmentId) {
+            obj.setAppointmentId(appointmentId);
+            return this;
+        }
+
+        /**
          * 设置题目编号id:json
          *
          * @param questionNoIds 题目编号id:json

+ 229 - 53
server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourseAppointment.java

@@ -1,5 +1,6 @@
 package com.qxgmat.data.dao.entity;
 
+import com.alibaba.fastjson.JSONArray;
 import java.io.Serializable;
 import java.util.Date;
 import javax.persistence.*;
@@ -18,6 +19,24 @@ public class UserCourseAppointment implements Serializable {
     private Integer userId;
 
     /**
+     * 课时序号
+     */
+    @Column(name = "`no`")
+    private Integer no;
+
+    /**
+     * 课程名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 关联购课记录
+     */
+    @Column(name = "`record_id`")
+    private Integer recordId;
+
+    /**
      * 课程id
      */
     @Column(name = "`course_id`")
@@ -30,10 +49,22 @@ public class UserCourseAppointment implements Serializable {
     private String channel;
 
     /**
-     * 预约时间
+     * 预约开始时间
+     */
+    @Column(name = "`start_time`")
+    private Date startTime;
+
+    /**
+     * 预约结束时间
+     */
+    @Column(name = "`end_time`")
+    private Date endTime;
+
+    /**
+     * 作业id
      */
-    @Column(name = "`appointment_time`")
-    private Date appointmentTime;
+    @Column(name = "`paper_id`")
+    private Integer paperId;
 
     /**
      * 是否完成
@@ -41,20 +72,20 @@ public class UserCourseAppointment implements Serializable {
     @Column(name = "`is_finish`")
     private Integer isFinish;
 
-    @Column(name = "`create_time`")
-    private Date createTime;
-
     /**
      * 课后补充:json格式
      */
     @Column(name = "`supply_list`")
-    private String supplyList;
+    private JSONArray supplyList;
 
     /**
      * 笔记批阅:json格式
      */
     @Column(name = "`note_list`")
-    private String noteList;
+    private JSONArray noteList;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
 
     private static final long serialVersionUID = 1L;
 
@@ -91,6 +122,60 @@ public class UserCourseAppointment implements Serializable {
     }
 
     /**
+     * 获取课时序号
+     *
+     * @return no - 课时序号
+     */
+    public Integer getNo() {
+        return no;
+    }
+
+    /**
+     * 设置课时序号
+     *
+     * @param no 课时序号
+     */
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    /**
+     * 获取课程名称
+     *
+     * @return title - 课程名称
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置课程名称
+     *
+     * @param title 课程名称
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取关联购课记录
+     *
+     * @return record_id - 关联购课记录
+     */
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    /**
+     * 设置关联购课记录
+     *
+     * @param recordId 关联购课记录
+     */
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    /**
      * 获取课程id
      *
      * @return course_id - 课程id
@@ -127,53 +212,75 @@ public class UserCourseAppointment implements Serializable {
     }
 
     /**
-     * 获取预约时间
+     * 获取预约开始时间
      *
-     * @return appointment_time - 预约时间
+     * @return start_time - 预约开始时间
      */
-    public Date getAppointmentTime() {
-        return appointmentTime;
+    public Date getStartTime() {
+        return startTime;
     }
 
     /**
-     * 设置预约时间
+     * 设置预约开始时间
      *
-     * @param appointmentTime 预约时间
+     * @param startTime 预约开始时间
      */
-    public void setAppointmentTime(Date appointmentTime) {
-        this.appointmentTime = appointmentTime;
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
     }
 
     /**
-     * 获取是否完成
+     * 获取预约结束时间
      *
-     * @return is_finish - 是否完成
+     * @return end_time - 预约结束时间
      */
-    public Integer getIsFinish() {
-        return isFinish;
+    public Date getEndTime() {
+        return endTime;
     }
 
     /**
-     * 设置是否完成
+     * 设置预约结束时间
      *
-     * @param isFinish 是否完成
+     * @param endTime 预约结束时间
      */
-    public void setIsFinish(Integer isFinish) {
-        this.isFinish = isFinish;
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
     }
 
     /**
-     * @return create_time
+     * 获取作业id
+     *
+     * @return paper_id - 作业id
      */
-    public Date getCreateTime() {
-        return createTime;
+    public Integer getPaperId() {
+        return paperId;
     }
 
     /**
-     * @param createTime
+     * 设置作业id
+     *
+     * @param paperId 作业id
      */
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+
+    /**
+     * 获取是否完成
+     *
+     * @return is_finish - 是否完成
+     */
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    /**
+     * 设置是否完成
+     *
+     * @param isFinish 是否完成
+     */
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
     }
 
     /**
@@ -181,7 +288,7 @@ public class UserCourseAppointment implements Serializable {
      *
      * @return supply_list - 课后补充:json格式
      */
-    public String getSupplyList() {
+    public JSONArray getSupplyList() {
         return supplyList;
     }
 
@@ -190,7 +297,7 @@ public class UserCourseAppointment implements Serializable {
      *
      * @param supplyList 课后补充:json格式
      */
-    public void setSupplyList(String supplyList) {
+    public void setSupplyList(JSONArray supplyList) {
         this.supplyList = supplyList;
     }
 
@@ -199,7 +306,7 @@ public class UserCourseAppointment implements Serializable {
      *
      * @return note_list - 笔记批阅:json格式
      */
-    public String getNoteList() {
+    public JSONArray getNoteList() {
         return noteList;
     }
 
@@ -208,10 +315,24 @@ public class UserCourseAppointment implements Serializable {
      *
      * @param noteList 笔记批阅:json格式
      */
-    public void setNoteList(String noteList) {
+    public void setNoteList(JSONArray noteList) {
         this.noteList = noteList;
     }
 
+    /**
+     * @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();
@@ -220,13 +341,18 @@ public class UserCourseAppointment implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
+        sb.append(", no=").append(no);
+        sb.append(", title=").append(title);
+        sb.append(", recordId=").append(recordId);
         sb.append(", courseId=").append(courseId);
         sb.append(", channel=").append(channel);
-        sb.append(", appointmentTime=").append(appointmentTime);
+        sb.append(", startTime=").append(startTime);
+        sb.append(", endTime=").append(endTime);
+        sb.append(", paperId=").append(paperId);
         sb.append(", isFinish=").append(isFinish);
-        sb.append(", createTime=").append(createTime);
         sb.append(", supplyList=").append(supplyList);
         sb.append(", noteList=").append(noteList);
+        sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
     }
@@ -261,6 +387,46 @@ public class UserCourseAppointment implements Serializable {
         }
 
         /**
+         * 设置课时序号
+         *
+         * @param no 课时序号
+         */
+        public Builder no(Integer no) {
+            obj.setNo(no);
+            return this;
+        }
+
+        /**
+         * 设置笔记批阅:json格式
+         *
+         * @param noteList 笔记批阅:json格式
+         */
+        public Builder noteList(JSONArray noteList) {
+            obj.setNoteList(noteList);
+            return this;
+        }
+
+        /**
+         * 设置课程名称
+         *
+         * @param title 课程名称
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置关联购课记录
+         *
+         * @param recordId 关联购课记录
+         */
+        public Builder recordId(Integer recordId) {
+            obj.setRecordId(recordId);
+            return this;
+        }
+
+        /**
          * 设置课程id
          *
          * @param courseId 课程id
@@ -281,30 +447,42 @@ public class UserCourseAppointment implements Serializable {
         }
 
         /**
-         * 设置预约时间
+         * 设置预约开始时间
          *
-         * @param appointmentTime 预约时间
+         * @param startTime 预约开始时间
          */
-        public Builder appointmentTime(Date appointmentTime) {
-            obj.setAppointmentTime(appointmentTime);
+        public Builder startTime(Date startTime) {
+            obj.setStartTime(startTime);
             return this;
         }
 
         /**
-         * 设置是否完成
+         * 设置预约结束时间
          *
-         * @param isFinish 是否完成
+         * @param endTime 预约结束时间
          */
-        public Builder isFinish(Integer isFinish) {
-            obj.setIsFinish(isFinish);
+        public Builder endTime(Date endTime) {
+            obj.setEndTime(endTime);
             return this;
         }
 
         /**
-         * @param createTime
+         * 设置作业id
+         *
+         * @param paperId 作业id
          */
-        public Builder createTime(Date createTime) {
-            obj.setCreateTime(createTime);
+        public Builder paperId(Integer paperId) {
+            obj.setPaperId(paperId);
+            return this;
+        }
+
+        /**
+         * 设置是否完成
+         *
+         * @param isFinish 是否完成
+         */
+        public Builder isFinish(Integer isFinish) {
+            obj.setIsFinish(isFinish);
             return this;
         }
 
@@ -313,18 +491,16 @@ public class UserCourseAppointment implements Serializable {
          *
          * @param supplyList 课后补充:json格式
          */
-        public Builder supplyList(String supplyList) {
+        public Builder supplyList(JSONArray supplyList) {
             obj.setSupplyList(supplyList);
             return this;
         }
 
         /**
-         * 设置笔记批阅:json格式
-         *
-         * @param noteList 笔记批阅:json格式
+         * @param createTime
          */
-        public Builder noteList(String noteList) {
-            obj.setNoteList(noteList);
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
             return this;
         }
 

+ 210 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserInvoice.java

@@ -17,6 +17,42 @@ public class UserInvoice implements Serializable {
     @Column(name = "`user_id`")
     private Integer userId;
 
+    /**
+     * 订单id
+     */
+    @Column(name = "`order_id`")
+    private Integer orderId;
+
+    /**
+     * 发票类型
+     */
+    @Column(name = "`invoice_type`")
+    private String invoiceType;
+
+    /**
+     * 抬头
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 纳税人识别号
+     */
+    @Column(name = "`identity`")
+    private String identity;
+
+    /**
+     * 是否已下载
+     */
+    @Column(name = "`is_download`")
+    private Integer isDownload;
+
+    /**
+     * 是否已开票
+     */
+    @Column(name = "`is_finish`")
+    private Integer isFinish;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -55,6 +91,114 @@ public class UserInvoice 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 invoice_type - 发票类型
+     */
+    public String getInvoiceType() {
+        return invoiceType;
+    }
+
+    /**
+     * 设置发票类型
+     *
+     * @param invoiceType 发票类型
+     */
+    public void setInvoiceType(String invoiceType) {
+        this.invoiceType = invoiceType;
+    }
+
+    /**
+     * 获取抬头
+     *
+     * @return title - 抬头
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置抬头
+     *
+     * @param title 抬头
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取纳税人识别号
+     *
+     * @return identity - 纳税人识别号
+     */
+    public String getIdentity() {
+        return identity;
+    }
+
+    /**
+     * 设置纳税人识别号
+     *
+     * @param identity 纳税人识别号
+     */
+    public void setIdentity(String identity) {
+        this.identity = identity;
+    }
+
+    /**
+     * 获取是否已下载
+     *
+     * @return is_download - 是否已下载
+     */
+    public Integer getIsDownload() {
+        return isDownload;
+    }
+
+    /**
+     * 设置是否已下载
+     *
+     * @param isDownload 是否已下载
+     */
+    public void setIsDownload(Integer isDownload) {
+        this.isDownload = isDownload;
+    }
+
+    /**
+     * 获取是否已开票
+     *
+     * @return is_finish - 是否已开票
+     */
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    /**
+     * 设置是否已开票
+     *
+     * @param isFinish 是否已开票
+     */
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -76,6 +220,12 @@ public class UserInvoice implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
+        sb.append(", orderId=").append(orderId);
+        sb.append(", invoiceType=").append(invoiceType);
+        sb.append(", title=").append(title);
+        sb.append(", identity=").append(identity);
+        sb.append(", isDownload=").append(isDownload);
+        sb.append(", isFinish=").append(isFinish);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
@@ -101,6 +251,16 @@ public class UserInvoice implements Serializable {
         }
 
         /**
+         * 设置纳税人识别号
+         *
+         * @param identity 纳税人识别号
+         */
+        public Builder identity(String identity) {
+            obj.setIdentity(identity);
+            return this;
+        }
+
+        /**
          * 设置用户id
          *
          * @param userId 用户id
@@ -111,6 +271,56 @@ public class UserInvoice implements Serializable {
         }
 
         /**
+         * 设置订单id
+         *
+         * @param orderId 订单id
+         */
+        public Builder orderId(Integer orderId) {
+            obj.setOrderId(orderId);
+            return this;
+        }
+
+        /**
+         * 设置发票类型
+         *
+         * @param invoiceType 发票类型
+         */
+        public Builder invoiceType(String invoiceType) {
+            obj.setInvoiceType(invoiceType);
+            return this;
+        }
+
+        /**
+         * 设置抬头
+         *
+         * @param title 抬头
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置是否已下载
+         *
+         * @param isDownload 是否已下载
+         */
+        public Builder isDownload(Integer isDownload) {
+            obj.setIsDownload(isDownload);
+            return this;
+        }
+
+        /**
+         * 设置是否已开票
+         *
+         * @param isFinish 是否已开票
+         */
+        public Builder isFinish(Integer isFinish) {
+            obj.setIsFinish(isFinish);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

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

@@ -23,36 +23,6 @@ public class UserOrder implements Serializable {
     @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;
 
@@ -115,96 +85,6 @@ public class UserOrder implements Serializable {
     }
 
     /**
-     * 获取使用状态: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() {
@@ -245,11 +125,6 @@ public class UserOrder implements Serializable {
         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("]");
@@ -306,56 +181,6 @@ public class UserOrder implements Serializable {
         }
 
         /**
-         * 设置使用状态: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) {

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

@@ -54,6 +54,18 @@ public class UserOrderRecord implements Serializable {
     private String source;
 
     /**
+     * 绑定教师
+     */
+    @Column(name = "`teacher_id`")
+    private Integer teacherId;
+
+    /**
+     * vs课时数量
+     */
+    @Column(name = "`vs_number`")
+    private Integer vsNumber;
+
+    /**
      * 开通开始时间
      */
     @Column(name = "`start_time`")
@@ -83,6 +95,12 @@ public class UserOrderRecord implements Serializable {
     @Column(name = "`is_used`")
     private Integer isUsed;
 
+    /**
+     * 是否停用
+     */
+    @Column(name = "`is_stop`")
+    private Integer isStop;
+
     @Column(name = "`create_time`")
     private Date createTime;
 
@@ -229,6 +247,42 @@ public class UserOrderRecord implements Serializable {
     }
 
     /**
+     * 获取绑定教师
+     *
+     * @return teacher_id - 绑定教师
+     */
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    /**
+     * 设置绑定教师
+     *
+     * @param teacherId 绑定教师
+     */
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    /**
+     * 获取vs课时数量
+     *
+     * @return vs_number - vs课时数量
+     */
+    public Integer getVsNumber() {
+        return vsNumber;
+    }
+
+    /**
+     * 设置vs课时数量
+     *
+     * @param vsNumber vs课时数量
+     */
+    public void setVsNumber(Integer vsNumber) {
+        this.vsNumber = vsNumber;
+    }
+
+    /**
      * 获取开通开始时间
      *
      * @return start_time - 开通开始时间
@@ -319,6 +373,24 @@ public class UserOrderRecord implements Serializable {
     }
 
     /**
+     * 获取是否停用
+     *
+     * @return is_stop - 是否停用
+     */
+    public Integer getIsStop() {
+        return isStop;
+    }
+
+    /**
+     * 设置是否停用
+     *
+     * @param isStop 是否停用
+     */
+    public void setIsStop(Integer isStop) {
+        this.isStop = isStop;
+    }
+
+    /**
      * @return create_time
      */
     public Date getCreateTime() {
@@ -346,11 +418,14 @@ public class UserOrderRecord implements Serializable {
         sb.append(", service=").append(service);
         sb.append(", param=").append(param);
         sb.append(", source=").append(source);
+        sb.append(", teacherId=").append(teacherId);
+        sb.append(", vsNumber=").append(vsNumber);
         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(", isStop=").append(isStop);
         sb.append(", createTime=").append(createTime);
         sb.append("]");
         return sb.toString();
@@ -446,6 +521,26 @@ public class UserOrderRecord implements Serializable {
         }
 
         /**
+         * 设置绑定教师
+         *
+         * @param teacherId 绑定教师
+         */
+        public Builder teacherId(Integer teacherId) {
+            obj.setTeacherId(teacherId);
+            return this;
+        }
+
+        /**
+         * 设置vs课时数量
+         *
+         * @param vsNumber vs课时数量
+         */
+        public Builder vsNumber(Integer vsNumber) {
+            obj.setVsNumber(vsNumber);
+            return this;
+        }
+
+        /**
          * 设置开通开始时间
          *
          * @param startTime 开通开始时间
@@ -496,6 +591,16 @@ public class UserOrderRecord implements Serializable {
         }
 
         /**
+         * 设置是否停用
+         *
+         * @param isStop 是否停用
+         */
+        public Builder isStop(Integer isStop) {
+            obj.setIsStop(isStop);
+            return this;
+        }
+
+        /**
          * @param createTime
          */
         public Builder createTime(Date createTime) {

+ 0 - 371
server/data/src/main/java/com/qxgmat/data/dao/entity/UserPay.java

@@ -1,371 +0,0 @@
-package com.qxgmat.data.dao.entity;
-
-import com.alibaba.fastjson.JSONObject;
-import java.io.Serializable;
-import java.util.Date;
-import javax.persistence.*;
-
-@Table(name = "user_pay")
-public class UserPay implements Serializable {
-    @Id
-    @Column(name = "`id`")
-    @GeneratedValue(strategy = GenerationType.IDENTITY)
-    private Integer id;
-
-    /**
-     * 用户id
-     */
-    @Column(name = "`user_id`")
-    private Integer userId;
-
-    /**
-     * 模块
-     */
-    @Column(name = "`module`")
-    private String module;
-
-    /**
-     * 模块扩展信息: json
-     */
-    @Column(name = "`module_extend`")
-    private JSONObject moduleExtend;
-
-    /**
-     * 使用状态: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;
-
-    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 module - 模块
-     */
-    public String getModule() {
-        return module;
-    }
-
-    /**
-     * 设置模块
-     *
-     * @param module 模块
-     */
-    public void setModule(String module) {
-        this.module = module;
-    }
-
-    /**
-     * 获取模块扩展信息: json
-     *
-     * @return module_extend - 模块扩展信息: json
-     */
-    public JSONObject getModuleExtend() {
-        return moduleExtend;
-    }
-
-    /**
-     * 设置模块扩展信息: json
-     *
-     * @param moduleExtend 模块扩展信息: json
-     */
-    public void setModuleExtend(JSONObject moduleExtend) {
-        this.moduleExtend = moduleExtend;
-    }
-
-    /**
-     * 获取使用状态: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;
-    }
-
-    @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(", module=").append(module);
-        sb.append(", moduleExtend=").append(moduleExtend);
-        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("]");
-        return sb.toString();
-    }
-
-    public static UserPay.Builder builder() {
-        return new UserPay.Builder();
-    }
-
-    public static class Builder {
-        private UserPay obj;
-
-        public Builder() {
-            this.obj = new UserPay();
-        }
-
-        /**
-         * @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 module 模块
-         */
-        public Builder module(String module) {
-            obj.setModule(module);
-            return this;
-        }
-
-        /**
-         * 设置模块扩展信息: json
-         *
-         * @param moduleExtend 模块扩展信息: json
-         */
-        public Builder moduleExtend(JSONObject 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 UserPay build() {
-            return this.obj;
-        }
-    }
-}

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

@@ -9,6 +9,7 @@
     <result column="struct_id" jdbcType="INTEGER" property="structId" />
     <result column="parent_struct_id" jdbcType="INTEGER" property="parentStructId" />
     <result column="course_module" jdbcType="VARCHAR" property="courseModule" />
+    <result column="vs_type" jdbcType="VARCHAR" property="vsType" />
     <result column="extend" jdbcType="VARCHAR" property="extend" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="crowd" jdbcType="VARCHAR" property="crowd" />
@@ -43,9 +44,9 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `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`
+    `id`, `struct_id`, `parent_struct_id`, `course_module`, `vs_type`, `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">
     <!--

+ 0 - 25
server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseStudentVsMapper.xml

@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.qxgmat.data.dao.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="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>
-  <sql id="Base_Column_List">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    `id`, `course_id`, `teacher_id`, `user_id`, `start_time`, `end_time`, `add_method`, 
-    `is_used`, `create_time`
-  </sql>
-</mapper>

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

@@ -8,7 +8,10 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
+    <result column="course_module" jdbcType="VARCHAR" property="courseModule" />
     <result column="course_no" jdbcType="INTEGER" property="courseNo" />
+    <result column="course_time" jdbcType="INTEGER" property="courseTime" />
+    <result column="appointment_id" jdbcType="INTEGER" property="appointmentId" />
     <result column="question_no_ids" jdbcType="VARCHAR" property="questionNoIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
     <result column="paper_module" jdbcType="VARCHAR" property="paperModule" />
     <result column="user_ids" jdbcType="VARCHAR" property="userIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
@@ -22,7 +25,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title`, `course_id`, `course_no`, `question_no_ids`, `paper_module`, `user_ids`, 
-    `start_time`, `end_time`, `finish`, `create_time`, `update_time`
+    `id`, `title`, `course_id`, `course_module`, `course_no`, `course_time`, `appointment_id`, 
+    `question_no_ids`, `paper_module`, `user_ids`, `start_time`, `end_time`, `finish`, 
+    `create_time`, `update_time`
   </sql>
 </mapper>

+ 10 - 15
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseAppointmentMapper.xml

@@ -7,29 +7,24 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="no" jdbcType="INTEGER" property="no" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="record_id" jdbcType="INTEGER" property="recordId" />
     <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="start_time" jdbcType="TIMESTAMP" property="startTime" />
+    <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
+    <result column="paper_id" jdbcType="INTEGER" property="paperId" />
     <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
+    <result column="supply_list" jdbcType="VARCHAR" property="supplyList" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler" />
+    <result column="note_list" jdbcType="VARCHAR" property="noteList" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler" />
     <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`
+    `id`, `user_id`, `no`, `title`, `record_id`, `course_id`, `channel`, `start_time`, 
+    `end_time`, `paper_id`, `is_finish`, `supply_list`, `note_list`, `create_time`
   </sql>
 </mapper>

+ 8 - 1
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserInvoiceMapper.xml

@@ -7,12 +7,19 @@
     -->
     <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="invoice_type" jdbcType="VARCHAR" property="invoiceType" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="identity" jdbcType="VARCHAR" property="identity" />
+    <result column="is_download" jdbcType="INTEGER" property="isDownload" />
+    <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `create_time`
+    `id`, `user_id`, `order_id`, `invoice_type`, `title`, `identity`, `is_download`, 
+    `is_finish`, `create_time`
   </sql>
 </mapper>

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

@@ -8,11 +8,6 @@
     <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">
@@ -25,8 +20,7 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `module`, `is_use`, `end_time`, `use_time`, `start_time`, `expire_time`, 
-    `create_time`
+    `id`, `user_id`, `module`, `create_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -13,11 +13,14 @@
     <result column="service" jdbcType="VARCHAR" property="service" />
     <result column="param" jdbcType="VARCHAR" property="param" />
     <result column="source" jdbcType="VARCHAR" property="source" />
+    <result column="teacher_id" jdbcType="INTEGER" property="teacherId" />
+    <result column="vs_number" jdbcType="INTEGER" property="vsNumber" />
     <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="is_stop" jdbcType="INTEGER" property="isStop" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   <sql id="Base_Column_List">
@@ -25,6 +28,7 @@
       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`
+    `teacher_id`, `vs_number`, `start_time`, `end_time`, `use_start_time`, `use_end_time`, 
+    `is_used`, `is_stop`, `create_time`
   </sql>
 </mapper>

+ 0 - 26
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPayMapper.xml

@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="com.qxgmat.data.dao.UserPayMapper">
-  <resultMap id="BaseResultMap" type="com.qxgmat.data.dao.entity.UserPay">
-    <!--
-      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="module_extend" jdbcType="VARCHAR" property="moduleExtend" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
-    <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>
-  <sql id="Base_Column_List">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    `id`, `user_id`, `module`, `module_extend`, `is_use`, `end_time`, `use_time`, `start_time`, 
-    `expire_time`, `create_time`
-  </sql>
-</mapper>

+ 3 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserAskCourseRelationMapper.java

@@ -15,6 +15,9 @@ public interface UserAskCourseRelationMapper {
             @Param("courseId") Number courseId,
             @Param("answerStatus") Integer answerStatus,
             @Param("showStatus") Integer showStatus,
+            @Param("userId") Integer userId,
+            @Param("min") Integer min,
+            @Param("max") Integer max,
             String order,
             String direction
     );

+ 10 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskCourseRelationMapper.xml

@@ -28,6 +28,16 @@
     select
     <include refid="Id_Column_List" />
     from `user_ask_course` ua
+    left join `user` u on u.`id` = ua.`user_id`
+      <if test="userId != null">
+        and ua.`user_id` = #{userId,jdbcType=VARCHAR}
+      </if>
+      <if test="max != null">
+        and u.`total_money` &lt; ${max}
+      </if>
+      <if test="min != null">
+        and u.`total_money` &gt; ${min}
+      </if>
     left join `course` c on c.`id` = ua.`course_id`
       <if test="courseId != null">
         and c.`id` = #{courseId,jdbcType=VARCHAR}

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

@@ -161,5 +161,10 @@
             <columnOverride column="course_ids" javaType="Integer[]" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler"/>
             <columnOverride column="gift" javaType="com.alibaba.fastjson.JSONObject" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler"/>
         </table>
+        <table schema="qianxing" tableName="user_course_appointment" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false" delimitAllColumns="true">
+            <generatedKey column="id" sqlStatement="Mysql" identity="true"/>
+            <columnOverride column="supply_list" javaType="com.alibaba.fastjson.JSONArray" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler"/>
+            <columnOverride column="note_list" javaType="com.alibaba.fastjson.JSONArray" jdbcType="VARCHAR" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler"/>
+        </table>
     </context>
 </generatorConfiguration>

+ 144 - 10
server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java

@@ -6,9 +6,11 @@ import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
 import com.nuliji.tools.Transform;
 import com.qxgmat.data.constants.enums.module.CourseModule;
+import com.qxgmat.data.constants.enums.module.ProductType;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.DataType;
+import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
 import com.qxgmat.dto.admin.extend.*;
@@ -25,6 +27,7 @@ import org.springframework.web.bind.annotation.*;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpSession;
+import javax.xml.transform.TransformerFactory;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -75,6 +78,9 @@ public class CourseController {
     @Autowired
     private UsersService usersService;
 
+    @Autowired
+    private UserOrderRecordService userOrderRecordService;
+
 
     @RequestMapping(value = "/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加课程", httpMethod = "POST")
@@ -97,6 +103,7 @@ public class CourseController {
     @RequestMapping(value = "/delete", method = RequestMethod.DELETE)
     @ApiOperation(value = "删除课程", httpMethod = "DELETE")
     public Response<Boolean> delete(@RequestParam int id, HttpServletRequest request) {
+        Course entity = courseService.get(id);
         courseService.delete(id);
         managerLogService.log(request);
         return ResponseHelp.success(true);
@@ -114,10 +121,18 @@ public class CourseController {
     public Response<PageMessage<CourseListDto>> list(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer[] ids,
+            @RequestParam(required = false) String keyword,
             @RequestParam(required = false) String courseModule,
             @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) Boolean excludeVs,
             HttpSession session) {
-        Page<Course> p = courseService.listAdmin(page, size, CourseModule.ValueOf(courseModule), structId);
+        Page<Course> p;
+        if (ids != null && ids.length > 0){
+            p = courseService.select(ids);
+        }else{
+            p = courseService.listAdmin(page, size, keyword, CourseModule.ValueOf(courseModule), structId, excludeVs);
+        }
         List<CourseListDto> pr = Transform.convert(p, CourseListDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
@@ -424,14 +439,22 @@ public class CourseController {
     public Response<PageMessage<CourseTimeInfoDto>> listTime(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer[] ids,
             @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) String keyword,
             HttpSession session) {
-        Page<CourseTime> p = courseTimeService.listAdmin(page, size, courseId);
+
+        Page<CourseTime> p;
+        if (ids != null && ids.length > 0){
+            p = courseTimeService.select(ids);
+        }else{
+            p = courseTimeService.listAdmin(page, size, courseId, keyword);
+        }
         List<CourseTimeInfoDto> pr = Transform.convert(p, CourseTimeInfoDto.class);
 
         // 绑定学生数量
-        Collection ids = Transform.getIds(p, CourseTime.class, "id");
-        List<CourseStudentNumberRelation> relations = courseStudentOnlineService.groupByCourse(ids);
+        Collection timeIds = Transform.getIds(p, CourseTime.class, "id");
+        List<CourseStudentNumberRelation> relations = courseStudentOnlineService.groupByCourse(timeIds);
         Map map = Transform.getMap(relations, CourseStudentNumberRelation.class, "id", "number");
         Transform.combine(pr, map, CourseTimeInfoDto.class, "id", "studentNumber");
 
@@ -440,17 +463,17 @@ public class CourseController {
 
     @RequestMapping(value = "/student/online/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加学员", httpMethod = "POST")
-    public Response<CourseStudentOnline> addStudentVideo(@RequestBody @Validated CourseStudentOnline dto, HttpServletRequest request) {
-        CourseStudentOnline entity = Transform.dtoToEntity(dto);
-        entity = courseStudentOnlineService.add(entity);
+    public Response<CourseStudentOnline> addStudentVideo(@RequestBody @Validated CourseStudentOnline entity, HttpServletRequest request) {
+//        CourseStudentOnline entity = Transform.dtoToEntity(dto);
+        entity = courseStudentOnlineService.addStudent(entity);
         managerLogService.log(request);
         return ResponseHelp.success(Transform.convert(entity, CourseStudentOnline.class));
     }
 
     @RequestMapping(value = "/student/online/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "编辑学员", httpMethod = "PUT")
-    public Response<Boolean> editStudentVideo(@RequestBody @Validated CourseStudentOnline dto, HttpServletRequest request) {
-        CourseStudentOnline entity = Transform.dtoToEntity(dto);
+    public Response<Boolean> editStudentVideo(@RequestBody @Validated CourseStudentOnline entity, HttpServletRequest request) {
+//        CourseStudentOnline entity = Transform.dtoToEntity(dto);
         entity = courseStudentOnlineService.edit(entity);
         managerLogService.log(request);
         return ResponseHelp.success(true);
@@ -481,6 +504,115 @@ public class CourseController {
             HttpSession session) {
         Page<CourseStudentOnline> p = courseStudentOnlineService.listAdmin(page, size, courseId, timeId);
         List<CourseStudentOnlineListDto> pr = Transform.convert(p, CourseStudentOnlineListDto.class);
+
+        // 绑定用户
+        Collection userIds = Transform.getIds(p, CourseStudentOnline.class, "userId");
+        List<User> userList = usersService.select(userIds);
+        Transform.combine(pr, userList, CourseStudentOnlineListDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+
+        // 绑定时间段
+        Collection timeIds = Transform.getIds(p, CourseStudentOnline.class, "timeId");
+        List<CourseTime> timeList = courseTimeService.select(timeIds);
+        Transform.combine(pr, timeList, CourseStudentOnlineListDto.class, "timeId", "time", CourseTime.class, "id", CourseTimeExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/student/vs/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加vs学员", httpMethod = "POST")
+    private Response<Boolean> addStudentVs(@RequestBody @Validated UserCourseRecordDto dto){
+        UserOrderRecord entity = Transform.dtoToEntity(dto);
+        entity.setProductType(ProductType.COURSE.key);
+        entity.setOrderId(0);
+        entity.setProductId(dto.getCourseId());
+        entity.setTeacherId(dto.getTeacherId());
+        entity.setSource("offline");
+        entity.setIsUsed(1);
+        userOrderRecordService.add(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/student/vs/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改vs学员", httpMethod = "PUT")
+    private Response<Boolean> editStudentVs(@RequestBody @Validated UserCourseRecordDto dto){
+        UserOrderRecord entity = Transform.dtoToEntity(dto);
+        entity.setProductType(ProductType.COURSE.key);
+        entity.setOrderId(0);
+        entity.setProductId(dto.getCourseId());
+        entity.setTeacherId(dto.getTeacherId());
+        userOrderRecordService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/student/vs/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "删除vs学员", httpMethod = "DELETE")
+    private Response<Boolean> deleteStudentVs(@RequestParam int id){
+        userOrderRecordService.delete(id);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/student/vs/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取vs学员", httpMethod = "GET")
+    private Response<PageMessage<UserCourseStudentRecordInfoDto>> listStudentVs(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) Integer userId
+    ){
+        Page<UserOrderRecord> p = userOrderRecordService.listWithStudentAdmin(page, size, courseId, userId);
+        List<UserCourseStudentRecordInfoDto> pr = Transform.convert(p, UserCourseStudentRecordInfoDto.class);
+
+        // 绑定用户
+        Collection userIds = Transform.getIds(p, UserOrderRecord.class, "userId");
+        List<User> userList = usersService.select(userIds);
+        Transform.combine(pr, userList, UserCourseStudentRecordInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+
+        // 绑定教师
+        Collection teacherIds = Transform.getIds(p, UserOrderRecord.class, "teacherId");
+        List<CourseTeacher> teacherList = courseTeacherService.select(teacherIds);
+        Transform.combine(pr, teacherList, UserCourseStudentRecordInfoDto.class, "teacherId", "teacher", CourseTeacher.class, "id", CourseTeacherExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
+    @RequestMapping(value = "/study/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取学习记录", httpMethod = "GET")
+    private Response<PageMessage<UserCourseStudyRecordInfoDto>> listStudy(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer[] ids,
+            @RequestParam(required = false) String courseModule,
+            @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) Integer userId,
+            @RequestParam(required = false) String teacher
+    ){
+        Page<UserOrderRecord> p;
+        if (ids != null && ids.length > 0){
+            p = userOrderRecordService.select(ids);
+        }else{
+            p = userOrderRecordService.listWithStudyAdmin(page, size, CourseModule.ValueOf(courseModule), structId, courseId, userId, teacher);
+        }
+        List<UserCourseStudyRecordInfoDto> pr = Transform.convert(p, UserCourseStudyRecordInfoDto.class);
+
+        // 绑定用户
+        Collection userIds = Transform.getIds(p, UserOrderRecord.class, "userId");
+        List<User> userList = usersService.select(userIds);
+        Transform.combine(pr, userList, UserCourseStudyRecordInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+
+        // 绑定课程
+        Map courseMap = Transform.getMap(p, UserOrderRecord.class, "id", "productId");
+        Transform.combine(pr, courseMap, UserCourseStudyRecordInfoDto.class, "id", "courseId");
+        Collection courseIds = Transform.getIds(p, UserOrderRecord.class, "productId");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(pr, courseList, UserCourseStudyRecordInfoDto.class, "courseId", "course", Course.class, "id", CourseExtendDto.class);
+
+        // 绑定老师
+        Collection teacherIds = Transform.getIds(p, UserOrderRecord.class, "teacherId");
+        List<CourseTeacher> teacherList = courseTeacherService.select(teacherIds);
+        Map teacherMap = Transform.getMap(teacherList, CourseTeacher.class,"id", "realname");
+        Transform.combine(pr, teacherMap, UserCourseStudyRecordInfoDto.class, "teacherId", "teacher");
+
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
@@ -544,10 +676,12 @@ public class CourseController {
             @RequestParam(required = false) Integer courseId,
             @RequestParam(required = false) Integer answerStatus,
             @RequestParam(required = false) Integer showStatus,
+            @RequestParam(required = false) Integer userId,
+            @RequestParam(required = false) Integer moneyRang,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserAskCourse> p = userAskCourseService.listWithCourse(page, size, structId, courseId, AskStatus.ValueOf(answerStatus), showStatus, order, DirectionStatus.ValueOf(direction));
+        Page<UserAskCourse> p = userAskCourseService.listWithCourse(page, size, structId, courseId, AskStatus.ValueOf(answerStatus), showStatus, userId, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
         List<UserAskCourseListDto> pr = Transform.convert(p, UserAskCourseListDto.class);
 
         // 绑定用户

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

@@ -118,7 +118,7 @@ public class PreviewController {
             @RequestParam(required = false) Integer category,
             @RequestParam(required = false) Integer status,
             HttpSession session) {
-        Page<PreviewPaper> p = previewPaperService.select(page, size, category, PreviewStatus.ValueOf(status));
+        Page<PreviewPaper> p = previewPaperService.listByAdmin(page, size, category, PreviewStatus.ValueOf(status));
         List<PreviewListDto> pr = Transform.convert(p, PreviewListDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());

+ 87 - 16
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java

@@ -10,17 +10,21 @@ import com.qxgmat.data.constants.enums.status.FeedbackStatus;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
 import com.qxgmat.dto.admin.extend.*;
+import com.qxgmat.dto.admin.request.UserCourseAppointmentDto;
 import com.qxgmat.dto.admin.request.UserFeedbackErrorDto;
 import com.qxgmat.dto.admin.request.UserServiceRecordDto;
 import com.qxgmat.dto.admin.response.*;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.ManagerService;
+import com.qxgmat.service.UserPaperService;
 import com.qxgmat.service.UserServiceService;
 import com.qxgmat.service.extend.PreviewService;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
 import org.springframework.validation.annotation.Validated;
@@ -37,6 +41,7 @@ import java.util.Map;
 @RequestMapping("/admin/user")
 @Api(tags = "用户接口", description = "用户相关操作", produces = MediaType.APPLICATION_JSON_VALUE)
 public class UserController {
+    private static final Logger logger = LoggerFactory.getLogger(UserController.class);
     @Autowired
     private ShiroHelp shiroHelp;
 
@@ -59,7 +64,13 @@ public class UserController {
     private UserCourseService userCourseService;
 
     @Autowired
-    private UserPayService userPayService;
+    private UserPaperService userPaperService;
+
+    @Autowired
+    private UserReportService userReportService;
+
+    @Autowired
+    private UserOrderService userOrderService;
 
     @Autowired
     private ManagerService managerService;
@@ -71,6 +82,9 @@ public class UserController {
     private PreviewPaperService previewPaperService;
 
     @Autowired
+    private UserCourseAppointmentService userCourseAppointmentService;
+
+    @Autowired
     private UserFeedbackErrorService userFeedbackErrorService;
 
     @Autowired
@@ -110,11 +124,14 @@ public class UserController {
 
     @RequestMapping(value = "/detail", method = RequestMethod.GET)
     @ApiOperation(value = "获取用户", httpMethod = "GET")
-    public Response<User> detail(@RequestParam int id, HttpSession session) {
+    public Response<UserDetailDto> detail(@RequestParam int id, HttpSession session) {
         User entity = usersService.get(id);
+        UserDetailDto dto = Transform.convert(entity, UserDetailDto.class);
 
-        return ResponseHelp.success(Transform.convert(entity, User.class));
+
+        return ResponseHelp.success(dto);
     }
+
     @RequestMapping(value = "/list", method = RequestMethod.GET)
     @ApiOperation(value = "用户列表", httpMethod = "GET")
     public Response<PageMessage<UserListDto>> list(
@@ -139,10 +156,6 @@ public class UserController {
         Map<Object, Collection<UserService>> serviceByUser = userServiceService.mapByUser(userIds);
         Transform.combine(pr, serviceByUser, UserListDto.class, "id", "services", UserServiceExtendDto.class);
 
-        // 绑定用户课程
-        Map<Object, Collection<UserCourse>> courseByUser = userCourseService.mapByUser(userIds, true);
-        Transform.combine(pr, courseByUser, UserListDto.class, "id", "classes", UserCourseExtendDto.class);
-
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
@@ -169,16 +182,16 @@ public class UserController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
-    @RequestMapping(value = "/pay/list", method = RequestMethod.GET)
-    @ApiOperation(value = "用户消费列表", httpMethod = "GET")
-    public Response<PageMessage<UserListDto>> listPay(
+    @RequestMapping(value = "/order/list", method = RequestMethod.GET)
+    @ApiOperation(value = "用户订单列表", httpMethod = "GET")
+    public Response<PageMessage<UserListDto>> listOrder(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) Integer userId,
             @RequestParam(required = false) String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserPay> p = userPayService.select(page, size);
+        Page<UserOrder> p = userOrderService.select(page, size);
         List<UserListDto> pr = Transform.convert(p, UserListDto.class);
 
         Collection userIds = Transform.getIds(p, User.class, "id");
@@ -186,10 +199,6 @@ public class UserController {
         Map<Object, Collection<UserService>> serviceByUser = userServiceService.mapByUser(userIds);
         Transform.combine(pr, serviceByUser, UserListDto.class, "id", "services", UserServiceExtendDto.class);
 
-        // 绑定用户课程
-        Map<Object, Collection<UserCourse>> courseByUser = userCourseService.mapByUser(userIds, false);
-        Transform.combine(pr, courseByUser, UserListDto.class, "id", "classes", UserCourseExtendDto.class);
-
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
@@ -294,7 +303,7 @@ public class UserController {
 
     @RequestMapping(value = "/service/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "修改服务记录", httpMethod = "PUT")
-    private Response<Boolean> editFaq(@RequestBody @Validated UserServiceRecordDto dto){
+    private Response<Boolean> editService(@RequestBody @Validated UserServiceRecordDto dto){
         UserOrderRecord entity = Transform.dtoToEntity(dto);
         entity.setOrderId(0);
         entity.setProductId(0);
@@ -330,6 +339,68 @@ public class UserController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/course/appointment/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加课程预约", httpMethod = "POST")
+    public Response<UserCourseAppointment> addCourseAppointment(@RequestBody @Validated UserCourseAppointmentDto dto, HttpServletRequest request) {
+        UserCourseAppointment entity = Transform.dtoToEntity(dto);
+        entity = userCourseAppointmentService.addAppointment(entity);
+        managerLogService.log(request);
+        return ResponseHelp.success(Transform.convert(entity, CourseTime.class));
+    }
+
+    @RequestMapping(value = "/course/appointment/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "编辑课程预约", httpMethod = "PUT")
+    public Response<Boolean> editCourseAppointment(@RequestBody @Validated UserCourseAppointmentDto dto, HttpServletRequest request) {
+        UserCourseAppointment entity = Transform.dtoToEntity(dto);
+        entity = userCourseAppointmentService.edit(entity);
+        managerLogService.log(request);
+        return ResponseHelp.success(true);
+    }
+
+//    @RequestMapping(value = "/course/appointment/delete", method = RequestMethod.DELETE)
+//    @ApiOperation(value = "删除课程预约", httpMethod = "DELETE")
+//    public Response<Boolean> deleteCourseAppointment(@RequestParam int id, HttpServletRequest request) {
+//        userCourseAppointmentService.delete(id);
+//        managerLogService.log(request);
+//        return ResponseHelp.success(true);
+//    }
+
+    @RequestMapping(value = "/course/appointment/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "获取课程预约", httpMethod = "GET")
+    public Response<CourseTime> detailCourseAppointment(@RequestParam int id,HttpSession session) {
+        UserCourseAppointment entity = userCourseAppointmentService.get(id);
+        return ResponseHelp.success(Transform.convert(entity, UserCourseAppointment.class));
+    }
+
+    @RequestMapping(value = "/course/appointment/list", method = RequestMethod.GET)
+    @ApiOperation(value = "课程预约列表", httpMethod = "GET")
+    public Response<PageMessage<UserCourseAppointmentInfoDto>> listCourseAppointment(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) Integer[] ids,
+            @RequestParam(required = false) Integer recordId,
+            HttpSession session) {
+
+        Page<UserCourseAppointment> p;
+        if (ids != null && ids.length > 0){
+            p = userCourseAppointmentService.select(ids);
+        }else{
+            p = userCourseAppointmentService.listAdmin(page, size, recordId);
+        }
+        List<UserCourseAppointmentInfoDto> pr = Transform.convert(p, UserCourseAppointmentInfoDto.class);
+
+        Collection paperIds = Transform.getIds(p, UserCourseAppointment.class, "paperId");
+        List<UserPaper> userPaperList = userPaperService.select(paperIds);
+        Transform.combine(pr, userPaperList, UserCourseAppointmentInfoDto.class, "paperId", "userPaper", UserPaper.class, "id", UserPaperExtendDto.class);
+
+        // 获取最后一次作业结果
+        List<UserReport> reportList = userReportService.listWithLater(paperIds);
+        Map reportMap = Transform.getMap(reportList, UserReport.class, "id");
+        Transform.combine(pr, reportMap, UserCourseAppointmentInfoDto.class, "paperId", "reportId");
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/valid/mobile", method = RequestMethod.GET)
     @ApiOperation(value = "验证手机号", notes="查询手机对应账号", httpMethod = "GET")
     public Response<Boolean> validMobile(

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

@@ -44,7 +44,7 @@ public class CourseController {
     private UserCourseService userCourseService;
 
     @Autowired
-    private UserPayService userPayService;
+    private UserOrderRecordService userOrderRecordService;
 
 
     @RequestMapping(value = "/progress", method = RequestMethod.GET)
@@ -59,10 +59,10 @@ public class CourseController {
         Transform.combine(dtos, previewMap, UserCourseDetailDto.class, "courseId", "previews", UserPreviewPaperExtendDto.class);
 
         // 获取课程状态:已购买未开通
-        List<UserPay> pays = userPayService.listUnUse(user.getId(), ProductType.COURSE);
+        List<UserOrderRecord> records = userOrderRecordService.listUnUse(user.getId(), ProductType.COURSE);
         Collection ids = Transform.getIds(userCourseList, UserCourse.class, "courseId");
-        for(UserPay pay : pays){
-            Integer courseId = 0;
+        for(UserOrderRecord record : records){
+            Integer courseId = record.getProductId();
             if (!ids.contains(courseId)){
                 UserCourseDetailDto dto = new UserCourseDetailDto();
                 dto.setCourseId(courseId);

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

@@ -94,7 +94,7 @@ public class QuestionController {
     private UserCourseService userCourseService;
 
     @Autowired
-    private UserPayService userPayService;
+    private UserOrderService userOrderService;
 
     @Autowired
     private UserReportService userReportService;

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseExtendDto.java

@@ -13,6 +13,8 @@ public class CourseExtendDto {
 
     private String title;
 
+    private String courseModule;
+
     public Integer getId() {
         return id;
     }
@@ -44,4 +46,12 @@ public class CourseExtendDto {
     public void setParentStructId(Integer parentStructId) {
         this.parentStructId = parentStructId;
     }
+
+    public String getCourseModule() {
+        return courseModule;
+    }
+
+    public void setCourseModule(String courseModule) {
+        this.courseModule = courseModule;
+    }
 }

+ 29 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseTeacherExtendDto.java

@@ -0,0 +1,29 @@
+package com.qxgmat.dto.admin.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.CourseTeacher;
+
+import java.util.Date;
+
+@Dto(entity = CourseTeacher.class)
+public class CourseTeacherExtendDto {
+    private Integer id;
+
+    private String realname;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getRealname() {
+        return realname;
+    }
+
+    public void setRealname(String realname) {
+        this.realname = realname;
+    }
+}

+ 49 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseTimeExtendDto.java

@@ -0,0 +1,49 @@
+package com.qxgmat.dto.admin.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.CourseTime;
+
+import java.util.Date;
+
+@Dto(entity = CourseTime.class)
+public class CourseTimeExtendDto {
+    private Integer id;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Integer courseId;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+}

+ 9 - 18
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserCourseExtendDto.java

@@ -10,8 +10,7 @@ public class UserCourseExtendDto {
 
     private Integer id;
     private Integer courseId;
-    private Date startTime;
-    private Date expireTime;
+    private String title;
 
     public Integer getId() {
         return id;
@@ -21,22 +20,6 @@ public class UserCourseExtendDto {
         this.id = id;
     }
 
-    public Date getStartTime() {
-        return startTime;
-    }
-
-    public void setStartTime(Date startTime) {
-        this.startTime = startTime;
-    }
-
-    public Date getExpireTime() {
-        return expireTime;
-    }
-
-    public void setExpireTime(Date expireTime) {
-        this.expireTime = expireTime;
-    }
-
     public Integer getCourseId() {
         return courseId;
     }
@@ -44,4 +27,12 @@ public class UserCourseExtendDto {
     public void setCourseId(Integer courseId) {
         this.courseId = courseId;
     }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
 }

+ 49 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserPaperExtendDto.java

@@ -0,0 +1,49 @@
+package com.qxgmat.dto.admin.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserCourse;
+import com.qxgmat.data.dao.entity.UserPaper;
+
+@Dto(entity = UserPaper.class)
+public class UserPaperExtendDto {
+
+    private Integer id;
+
+    private Integer userId;
+
+    private String title;
+
+    private Integer times;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getTimes() {
+        return times;
+    }
+
+    public void setTimes(Integer times) {
+        this.times = times;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+}

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

@@ -0,0 +1,120 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserCourseAppointment;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+
+import java.util.Date;
+
+@Dto(entity = UserCourseAppointment.class)
+public class UserCourseAppointmentDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer courseId;
+
+    private Integer recordId;
+
+    private String channel;
+
+    private String title;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Integer isFinish;
+
+    private Object noteList;
+
+    private Object supplyList;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    public String getChannel() {
+        return channel;
+    }
+
+    public void setChannel(String channel) {
+        this.channel = channel;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Object getNoteList() {
+        return noteList;
+    }
+
+    public void setNoteList(Object noteList) {
+        this.noteList = noteList;
+    }
+
+    public Object getSupplyList() {
+        return supplyList;
+    }
+
+    public void setSupplyList(Object supplyList) {
+        this.supplyList = supplyList;
+    }
+
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
+    }
+}

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

@@ -0,0 +1,79 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+
+import java.util.Date;
+
+@Dto(entity = UserOrderRecord.class)
+public class UserCourseRecordDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer courseId;
+
+    private Integer teacherId;
+
+    private Integer vsNumber;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getVsNumber() {
+        return vsNumber;
+    }
+
+    public void setVsNumber(Integer vsNumber) {
+        this.vsNumber = vsNumber;
+    }
+}

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

@@ -16,6 +16,8 @@ public class CourseListDto {
 
     private String courseModule;
 
+    private String vsType;
+
     private String title;
 
     private String crowd;
@@ -148,4 +150,12 @@ public class CourseListDto {
     public void setUpdateTime(Date updateTime) {
         this.updateTime = updateTime;
     }
+
+    public String getVsType() {
+        return vsType;
+    }
+
+    public void setVsType(String vsType) {
+        this.vsType = vsType;
+    }
 }

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

@@ -2,6 +2,7 @@ package com.qxgmat.dto.admin.response;
 
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.CourseStudentOnline;
+import com.qxgmat.dto.admin.extend.CourseTimeExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 
 
@@ -15,6 +16,8 @@ public class CourseStudentOnlineListDto {
 
     private Integer timeId;
 
+    private CourseTimeExtendDto time;
+
     private Integer courseId;
 
     public Integer getId() {
@@ -56,4 +59,12 @@ public class CourseStudentOnlineListDto {
     public void setCourseId(Integer courseId) {
         this.courseId = courseId;
     }
+
+    public CourseTimeExtendDto getTime() {
+        return time;
+    }
+
+    public void setTime(CourseTimeExtendDto time) {
+        this.time = time;
+    }
 }

+ 162 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseAppointmentInfoDto.java

@@ -0,0 +1,162 @@
+package com.qxgmat.dto.admin.response;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserCourseAppointment;
+import com.qxgmat.dto.admin.extend.UserPaperExtendDto;
+
+import java.util.Date;
+
+@Dto(entity = UserCourseAppointment.class)
+public class UserCourseAppointmentInfoDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private Integer no;
+
+    private String title;
+
+    private Integer recordId;
+
+    private Integer courseId;
+
+    private String channel;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Integer paperId;
+
+    private UserPaperExtendDto userPaper;
+
+    private Integer reportId;
+
+    private Integer isFinish;
+
+    private JSONArray noteList;
+
+    private JSONArray supplyList;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getNo() {
+        return no;
+    }
+
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public String getChannel() {
+        return channel;
+    }
+
+    public void setChannel(String channel) {
+        this.channel = channel;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+
+    public UserPaperExtendDto getUserPaper() {
+        return userPaper;
+    }
+
+    public void setUserPaper(UserPaperExtendDto userPaper) {
+        this.userPaper = userPaper;
+    }
+
+    public Integer getIsFinish() {
+        return isFinish;
+    }
+
+    public void setIsFinish(Integer isFinish) {
+        this.isFinish = isFinish;
+    }
+
+    public JSONArray getNoteList() {
+        return noteList;
+    }
+
+    public void setNoteList(JSONArray noteList) {
+        this.noteList = noteList;
+    }
+
+    public JSONArray getSupplyList() {
+        return supplyList;
+    }
+
+    public void setSupplyList(JSONArray supplyList) {
+        this.supplyList = supplyList;
+    }
+
+    public Integer getReportId() {
+        return reportId;
+    }
+
+    public void setReportId(Integer reportId) {
+        this.reportId = reportId;
+    }
+}

+ 111 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseStudentRecordInfoDto.java

@@ -0,0 +1,111 @@
+package com.qxgmat.dto.admin.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.dto.admin.extend.CourseTeacherExtendDto;
+import com.qxgmat.dto.admin.extend.UserExtendDto;
+
+import java.util.Date;
+
+@Dto(entity = UserOrderRecord.class)
+public class UserCourseStudentRecordInfoDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private UserExtendDto user;
+
+    private Integer teacherId;
+
+    private CourseTeacherExtendDto teacher;
+
+    private String source;
+
+    private Integer isUsed;
+
+    private Integer isStop;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getIsUsed() {
+        return isUsed;
+    }
+
+    public void setIsUsed(Integer isUsed) {
+        this.isUsed = isUsed;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public UserExtendDto getUser() {
+        return user;
+    }
+
+    public void setUser(UserExtendDto user) {
+        this.user = user;
+    }
+
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    public CourseTeacherExtendDto getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(CourseTeacherExtendDto teacher) {
+        this.teacher = teacher;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getIsStop() {
+        return isStop;
+    }
+
+    public void setIsStop(Integer isStop) {
+        this.isStop = isStop;
+    }
+}

+ 152 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseStudyRecordInfoDto.java

@@ -0,0 +1,152 @@
+package com.qxgmat.dto.admin.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.dto.admin.extend.CourseExtendDto;
+import com.qxgmat.dto.admin.extend.CourseTeacherExtendDto;
+import com.qxgmat.dto.admin.extend.UserExtendDto;
+
+import java.util.Date;
+
+@Dto(entity = UserOrderRecord.class)
+public class UserCourseStudyRecordInfoDto {
+    private Integer id;
+
+    private Integer userId;
+
+    private UserExtendDto user;
+
+    private Integer courseId;
+
+    private CourseExtendDto course;
+
+    private String teacher;
+
+    private Integer teacherId;
+
+    private Integer vsNumber;
+
+    private String source;
+
+    private Integer isUsed;
+
+    private Integer isStop;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    private Date lastTime;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public Integer getIsUsed() {
+        return isUsed;
+    }
+
+    public void setIsUsed(Integer isUsed) {
+        this.isUsed = isUsed;
+    }
+
+    public String getSource() {
+        return source;
+    }
+
+    public void setSource(String source) {
+        this.source = source;
+    }
+
+    public UserExtendDto getUser() {
+        return user;
+    }
+
+    public void setUser(UserExtendDto user) {
+        this.user = user;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getIsStop() {
+        return isStop;
+    }
+
+    public void setIsStop(Integer isStop) {
+        this.isStop = isStop;
+    }
+
+    public Date getLastTime() {
+        return lastTime;
+    }
+
+    public void setLastTime(Date lastTime) {
+        this.lastTime = lastTime;
+    }
+
+    public Integer getCourseId() {
+        return courseId;
+    }
+
+    public void setCourseId(Integer courseId) {
+        this.courseId = courseId;
+    }
+
+    public CourseExtendDto getCourse() {
+        return course;
+    }
+
+    public void setCourse(CourseExtendDto course) {
+        this.course = course;
+    }
+
+    public String getTeacher() {
+        return teacher;
+    }
+
+    public void setTeacher(String teacher) {
+        this.teacher = teacher;
+    }
+
+    public Integer getTeacherId() {
+        return teacherId;
+    }
+
+    public void setTeacherId(Integer teacherId) {
+        this.teacherId = teacherId;
+    }
+
+    public Integer getVsNumber() {
+        return vsNumber;
+    }
+
+    public void setVsNumber(Integer vsNumber) {
+        this.vsNumber = vsNumber;
+    }
+}

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

@@ -24,8 +24,6 @@ public class UserDetailDto {
 
     private Collection<UserServiceExtendDto> services;
 
-    private Collection<UserCourseExtendDto> classes;
-
     public Integer getId() {
         return id;
     }
@@ -73,12 +71,4 @@ public class UserDetailDto {
     public void setServices(Collection<UserServiceExtendDto> services) {
         this.services = services;
     }
-
-    public Collection<UserCourseExtendDto> getClasses() {
-        return classes;
-    }
-
-    public void setClasses(Collection<UserCourseExtendDto> classes) {
-        this.classes = classes;
-    }
 }

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

@@ -30,8 +30,6 @@ public class UserListDto {
 
     private Collection<UserServiceExtendDto> services;
 
-    private Collection<UserCourseExtendDto> courses;
-
     public Integer getId() {
         return id;
     }
@@ -96,14 +94,6 @@ public class UserListDto {
         this.prepareStatus = prepareStatus;
     }
 
-    public Collection<UserCourseExtendDto> getCourses() {
-        return courses;
-    }
-
-    public void setCourses(Collection<UserCourseExtendDto> courses) {
-        this.courses = courses;
-    }
-
     public String getNickname() {
         return nickname;
     }

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

@@ -107,6 +107,10 @@ public class ManagerService extends AbstractService {
         return select(managerMapper, example, page, pageSize);
     }
 
+    public Page<Manager> select(Integer[] ids){
+        return page(()->select(managerMapper, ids), 1, ids.length);
+    }
+
     public List<Manager> select(Collection ids){
         return select(managerMapper, ids);
     }

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

@@ -152,6 +152,10 @@ public class UserCollectExperienceService extends AbstractService {
         return select(userCollectExperienceMapper, page, pageSize);
     }
 
+    public Page<UserCollectExperience> select(Integer[] ids){
+        return page(()->select(userCollectExperienceMapper, ids), 1, ids.length);
+    }
+
     public List<UserCollectExperience> select(Collection ids){
         return select(userCollectExperienceMapper, ids);
     }

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

@@ -180,6 +180,10 @@ public class UserCollectQuestionService extends AbstractService {
         return select(userCollectQuestionMapper, page, pageSize);
     }
 
+    public Page<UserCollectQuestion> select(Integer[] ids){
+        return page(()->select(userCollectQuestionMapper, ids), 1, ids.length);
+    }
+
     public List<UserCollectQuestion> select(Collection ids){
         return select(userCollectQuestionMapper, ids);
     }

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

@@ -72,6 +72,10 @@ public class UserNoteCourseService extends AbstractService {
         return select(userNoteCourseMapper, page, pageSize);
     }
 
+    public Page<UserNoteCourse> select(Integer[] ids){
+        return page(()->select(userNoteCourseMapper, ids), 1, ids.length);
+    }
+
     public List<UserNoteCourse> select(Collection ids){
         return select(userNoteCourseMapper, ids);
     }

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

@@ -205,6 +205,10 @@ public class UserNoteQuestionService extends AbstractService {
         return select(userNoteQuestionMapper, page, pageSize);
     }
 
+    public Page<UserNoteQuestion> select(Integer[] ids){
+        return page(()->select(userNoteQuestionMapper, ids), 1, ids.length);
+    }
+
     public List<UserNoteQuestion> select(Collection ids){
         return select(userNoteQuestionMapper, ids);
     }

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

@@ -242,6 +242,10 @@ public class UserPaperService extends AbstractService {
         return select(userPaperMapper, page, pageSize);
     }
 
+    public Page<UserPaper> select(Integer[] ids){
+        return page(()->select(userPaperMapper, ids), 1, ids.length);
+    }
+
     public List<UserPaper> select(Collection ids){
         return select(userPaperMapper, ids);
     }

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

@@ -258,11 +258,11 @@ public class UserQuestionService extends AbstractService {
         return select(userQuestionMapper, page, pageSize);
     }
 
-    public List<UserQuestion> select(Collection ids){
-        return select(userQuestionMapper, ids);
+    public Page<UserQuestion> select(Integer[] ids){
+        return page(()->select(userQuestionMapper, ids), 1, ids.length);
     }
 
-    public List<UserQuestion> select(Integer[] ids){
+    public List<UserQuestion> select(Collection ids){
         return select(userQuestionMapper, ids);
     }
 

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

@@ -144,6 +144,10 @@ public class UserServiceService extends AbstractService {
         return select(userServiceMapper, page, pageSize);
     }
 
+    public Page<UserService> select(Integer[] ids){
+        return page(()->select(userServiceMapper, ids), 1, ids.length);
+    }
+
     public List<UserService> select(Collection ids){
         return select(userServiceMapper, ids);
     }

+ 3 - 4
server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java

@@ -21,7 +21,7 @@ import com.qxgmat.data.relation.entity.UserPrepareRelation;
 import com.qxgmat.help.WechatHelp;
 import com.qxgmat.service.inline.UserCourseService;
 import com.qxgmat.service.inline.UserMessageService;
-import com.qxgmat.service.inline.UserPayService;
+import com.qxgmat.service.inline.UserOrderService;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Service;
 import org.springframework.transaction.annotation.Transactional;
@@ -53,7 +53,7 @@ public class UsersService extends AbstractService {
     private UserMessageService userMessageService;
 
     @Resource
-    private UserPayService userPayService;
+    private UserOrderService userOrderService;
 
     @Resource
     private UserCourseService userCourseService;
@@ -129,7 +129,7 @@ public class UsersService extends AbstractService {
                 // 更新消息
                 userMessageService.mergeUser(openUser.getId(), user.getId());
                 // 更新消费记录
-                userPayService.mergeUser(openUser.getId(), user.getId());
+                userOrderService.mergeUser(openUser.getId(), user.getId());
                 // 更新课程信息
                 userCourseService.mergeUser(openUser.getId(), user.getId());
                 // 更新服务信息
@@ -536,7 +536,6 @@ public class UsersService extends AbstractService {
         return page(()->select(userMapper, ids), 1, ids.length);
     }
 
-
     public List<User> select(Collection ids){
         return select(userMapper, ids);
     }

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

@@ -16,11 +16,11 @@ import com.qxgmat.data.constants.enums.trade.PayType;
 import com.qxgmat.data.constants.enums.trade.TradeStatus;
 import com.qxgmat.data.dao.PayMapper;
 import com.qxgmat.data.dao.entity.Pay;
-import com.qxgmat.data.dao.entity.UserPay;
+import com.qxgmat.data.dao.entity.UserOrder;
 import com.qxgmat.help.PayHelp;
 import com.qxgmat.service.inline.PayService;
 import com.qxgmat.service.inline.UserCourseService;
-import com.qxgmat.service.inline.UserPayService;
+import com.qxgmat.service.inline.UserOrderService;
 import com.qxgmat.service.UserServiceService;
 import com.qxgmat.util.annotation.Callback;
 import org.springframework.stereotype.Service;
@@ -54,7 +54,7 @@ public class TradeService extends AbstractService {
     private Map<ProductType, Callback> payCallback = new HashMap<>();;
 
     @Resource
-    private UserPayService userPayService;
+    private UserOrderService userOrderService;
 
     public interface Source {
         String WECHAT = "wechat";
@@ -75,10 +75,8 @@ public class TradeService extends AbstractService {
             Integer userId = pay.getUserId();
             JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
             // 写入用户购买
-            userPayService.add(UserPay.builder()
+            userOrderService.add(UserOrder.builder()
                     .module(pay.getModule())
-                    .moduleExtend(extend)
-                    .isUse(0)
                     .userId(userId).build());
             return true;
         });
@@ -87,10 +85,8 @@ public class TradeService extends AbstractService {
             Integer userId = pay.getUserId();
             JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
             // 写入用户购买
-            userPayService.add(UserPay.builder()
+            userOrderService.add(UserOrder.builder()
                     .module(pay.getModule())
-                    .moduleExtend(extend)
-                    .isUse(0)
                     .userId(userId).build());
             return true;
         });
@@ -99,10 +95,8 @@ public class TradeService extends AbstractService {
             Integer userId = pay.getUserId();
             JSONObject extend = JSONObject.parseObject(pay.getModuleExtend());
             // 写入用户购买
-            userPayService.add(UserPay.builder()
+            userOrderService.add(UserOrder.builder()
                     .module(pay.getModule())
-                    .moduleExtend(extend)
-                    .isUse(0)
                     .userId(userId).build());
             // 直接绑定数据关系
             return true;

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

@@ -82,6 +82,10 @@ public class AdService extends AbstractService {
         return select(adMapper, page, pageSize);
     }
 
+    public Page<Ad> select(Integer[] ids){
+        return page(()->select(adMapper, ids), 1, ids.length);
+    }
+
     public List<Ad> select(Collection ids){
         return select(adMapper, ids);
     }

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

@@ -90,6 +90,10 @@ public class CommentService extends AbstractService {
         return select(commentMapper, page, pageSize);
     }
 
+    public Page<Comment> select(Integer[] ids){
+        return page(()->select(commentMapper, ids), 1, ids.length);
+    }
+
     public List<Comment> select(Collection ids){
         return select(commentMapper, ids);
     }

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

@@ -81,6 +81,10 @@ public class CourseDataHistoryService extends AbstractService {
         return select(courseDataHistoryMapper, page, pageSize);
     }
 
+    public Page<CourseDataHistory> select(Integer[] ids){
+        return page(()->select(courseDataHistoryMapper, ids), 1, ids.length);
+    }
+
     public List<CourseDataHistory> select(Collection ids){
         return select(courseDataHistoryMapper, ids);
     }

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

@@ -93,6 +93,10 @@ public class CourseDataService extends AbstractService {
         return select(courseDataMapper, page, pageSize);
     }
 
+    public Page<CourseData> select(Integer[] ids){
+        return page(()->select(courseDataMapper, ids), 1, ids.length);
+    }
+
     public List<CourseData> select(Collection ids){
         return select(courseDataMapper, ids);
     }

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

@@ -93,6 +93,10 @@ public class CourseExperienceService extends AbstractService {
         return select(courseExperienceMapper, page, pageSize);
     }
 
+    public Page<CourseExperience> select(Integer[] ids){
+        return page(()->select(courseExperienceMapper, ids), 1, ids.length);
+    }
+
     public List<CourseExperience> select(Collection ids){
         return select(courseExperienceMapper, ids);
     }

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

@@ -120,6 +120,10 @@ public class CourseNoService extends AbstractService {
         return select(courseNoMapper, page, pageSize);
     }
 
+    public Page<CourseNo> select(Integer[] ids){
+        return page(()->select(courseNoMapper, ids), 1, ids.length);
+    }
+
     public List<CourseNo> select(Collection ids){
         return select(courseNoMapper, ids);
     }

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

@@ -63,6 +63,10 @@ public class CoursePackageService extends AbstractService {
         return select(coursePackageMapper, page, pageSize);
     }
 
+    public Page<CoursePackage> select(Integer[] ids){
+        return page(()->select(coursePackageMapper, ids), 1, ids.length);
+    }
+
     public List<CoursePackage> select(Collection ids){
         return select(coursePackageMapper, ids);
     }

+ 17 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseService.java

@@ -23,8 +23,14 @@ public class CourseService extends AbstractService {
     @Resource
     private CourseMapper courseMapper;
 
-    public Page<Course> listAdmin(int page, int size, CourseModule module, Integer structId){
+    public Page<Course> listAdmin(int page, int size, String keyword, CourseModule module, Integer structId, Boolean excludeVs){
         Example example = new Example(Course.class);
+        if (keyword != null) {
+            example.and(
+                    example.createCriteria()
+                            .andLike("title", "%"+keyword+"%")
+            );
+        }
         if(module != null){
             example.and(
                     example.createCriteria()
@@ -38,6 +44,12 @@ public class CourseService extends AbstractService {
                             .orEqualTo("parentStructId", structId)
             );
         }
+        if (excludeVs != null) {
+            example.and(
+                    example.createCriteria()
+                            .andNotEqualTo("courseModule", CourseModule.VS.key)
+            );
+        }
         return select(courseMapper, example, page, size);
     }
 
@@ -81,6 +93,10 @@ public class CourseService extends AbstractService {
         return select(courseMapper, page, pageSize);
     }
 
+    public Page<Course> select(Integer[] ids){
+        return page(()->select(courseMapper, ids), 1, ids.length);
+    }
+
     public List<Course> select(Collection ids){
         return select(courseMapper, ids);
     }

+ 23 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseStudentOnlineService.java

@@ -30,7 +30,7 @@ public class CourseStudentOnlineService extends AbstractService {
     private CourseStudentOnlineRelationMapper courseStudentOnlineRelationMapper;
 
     public Page<CourseStudentOnline> listAdmin(int page, int size, Integer courseId, Integer timeId){
-        Example example = new Example(CourseTime.class);
+        Example example = new Example(CourseStudentOnline.class);
         if(courseId != null){
             example.and(
                     example.createCriteria()
@@ -50,6 +50,24 @@ public class CourseStudentOnlineService extends AbstractService {
         return courseStudentOnlineRelationMapper.groupByTime(ids);
     }
 
+    public CourseStudentOnline getByUserAndTime(Integer userId, Integer timeId){
+        Example example = new Example(CourseStudentOnline.class);
+        example.and(
+                example.createCriteria()
+                .andEqualTo("userId", userId)
+                .andEqualTo("timeId", timeId)
+        );
+        return one(courseStudentOnlineMapper, example);
+    }
+
+    public CourseStudentOnline addStudent(CourseStudentOnline course){
+        CourseStudentOnline in = getByUserAndTime(course.getUserId(), course.getTimeId());
+        if(in != null){
+            throw new ParameterException("已添加");
+        }
+        return add(course);
+    }
+
     public CourseStudentOnline add(CourseStudentOnline course){
         int result = insert(courseStudentOnlineMapper, course);
         course = one(courseStudentOnlineMapper, course.getId());
@@ -90,6 +108,10 @@ public class CourseStudentOnlineService extends AbstractService {
         return select(courseStudentOnlineMapper, page, pageSize);
     }
 
+    public Page<CourseStudentOnline> select(Integer[] ids){
+        return page(()->select(courseStudentOnlineMapper, ids), 1, ids.length);
+    }
+
     public List<CourseStudentOnline> select(Collection ids){
         return select(courseStudentOnlineMapper, ids);
     }

+ 0 - 87
server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseStudentVsService.java

@@ -1,87 +0,0 @@
-package com.qxgmat.service.inline;
-
-import com.github.pagehelper.Page;
-import com.nuliji.tools.AbstractService;
-import com.nuliji.tools.exception.ParameterException;
-import com.nuliji.tools.exception.SystemException;
-import com.nuliji.tools.mybatis.Example;
-import com.qxgmat.data.dao.CourseStudentVsMapper;
-import com.qxgmat.data.dao.entity.CourseStudentVs;
-import com.qxgmat.data.dao.entity.CourseTime;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.stereotype.Service;
-
-import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
-
-@Service
-public class CourseStudentVsService extends AbstractService {
-    private static final Logger logger = LoggerFactory.getLogger(CourseStudentVsService.class);
-
-    @Resource
-    private CourseStudentVsMapper courseStudentVsMapper;
-
-    public Page<CourseStudentVs> listAdmin(int page, int size, Integer courseId, Integer timeId){
-        Example example = new Example(CourseTime.class);
-        if(courseId != null){
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("courseId", courseId)
-            );
-        }
-        if(timeId != null){
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("timeId", timeId)
-            );
-        }
-        return select(courseStudentVsMapper, example, page, size);
-    }
-
-    public CourseStudentVs add(CourseStudentVs course){
-        int result = insert(courseStudentVsMapper, course);
-        course = one(courseStudentVsMapper, course.getId());
-        if(course == null){
-            throw new SystemException("课时添加失败");
-        }
-        return course;
-    }
-
-    public CourseStudentVs edit(CourseStudentVs course){
-        CourseStudentVs in = one(courseStudentVsMapper, course.getId());
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        int result = update(courseStudentVsMapper, course);
-        return course;
-    }
-
-    public boolean delete(Number id){
-        CourseStudentVs in = one(courseStudentVsMapper, id);
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        int result = delete(courseStudentVsMapper, id);
-        return result > 0;
-    }
-
-    public CourseStudentVs get(Number id){
-        CourseStudentVs in = one(courseStudentVsMapper, id);
-
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        return in;
-    }
-
-    public Page<CourseStudentVs> select(int page, int pageSize){
-        return select(courseStudentVsMapper, page, pageSize);
-    }
-
-    public List<CourseStudentVs> select(Collection ids){
-        return select(courseStudentVsMapper, ids);
-    }
-
-}

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

@@ -8,6 +8,7 @@ import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.CourseExperienceMapper;
 import com.qxgmat.data.dao.CourseTeacherMapper;
+import com.qxgmat.data.dao.entity.Course;
 import com.qxgmat.data.dao.entity.CourseExperience;
 import com.qxgmat.data.dao.entity.CourseTeacher;
 import org.slf4j.Logger;
@@ -76,6 +77,10 @@ public class CourseTeacherService extends AbstractService {
         return select(courseTeacherMapper, page, pageSize);
     }
 
+    public Page<CourseTeacher> select(Integer[] ids){
+        return page(()->select(courseTeacherMapper, ids), 1, ids.length);
+    }
+
     public List<CourseTeacher> select(Collection ids){
         return select(courseTeacherMapper, ids);
     }

+ 12 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseTimeService.java

@@ -24,7 +24,7 @@ public class CourseTimeService extends AbstractService {
     @Resource
     private CourseTimeMapper courseTimeMapper;
 
-    public Page<CourseTime> listAdmin(int page, int size, Integer courseId){
+    public Page<CourseTime> listAdmin(int page, int size, Integer courseId, String keyword){
         Example example = new Example(CourseTime.class);
         if(courseId != null){
             example.and(
@@ -32,6 +32,13 @@ public class CourseTimeService extends AbstractService {
                             .andEqualTo("courseId", courseId)
             );
         }
+        if (keyword != null) {
+            example.and(
+                    example.createCriteria()
+                            .orLike("startTime", "%"+keyword+"%")
+                            .orLike("endTime", "%"+keyword+"%")
+            );
+        }
         example.orderBy("startTime").desc();
         return select(courseTimeMapper, example, page, size);
     }
@@ -76,6 +83,10 @@ public class CourseTimeService extends AbstractService {
         return select(courseTimeMapper, page, pageSize);
     }
 
+    public Page<CourseTime> select(Integer[] ids){
+        return page(()->select(courseTimeMapper, ids), 1, ids.length);
+    }
+
     public List<CourseTime> select(Collection ids){
         return select(courseTimeMapper, ids);
     }

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

@@ -142,6 +142,10 @@ public class ExaminationStructService extends AbstractService {
         return select(examinationStructMapper, page, pageSize);
     }
 
+    public Page<ExaminationStruct> select(Integer[] ids){
+        return page(()->select(examinationStructMapper, ids), 1, ids.length);
+    }
+
     public List<ExaminationStruct> select(Collection ids){
         return select(examinationStructMapper, ids);
     }

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

@@ -62,6 +62,10 @@ public class ExerciseQuestionService extends AbstractService {
         return select(exerciseQuestionMapper, page, pageSize);
     }
 
+    public Page<ExercisePaperQuestion> select(Integer[] ids){
+        return page(()->select(exerciseQuestionMapper, ids), 1, ids.length);
+    }
+
     public List<ExercisePaperQuestion> select(Collection ids){
         return select(exerciseQuestionMapper, ids);
     }

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

@@ -139,6 +139,10 @@ public class ExerciseStructService extends AbstractService {
         return select(exerciseStructMapper, page, pageSize);
     }
 
+    public Page<ExerciseStruct> select(Integer[] ids){
+        return page(()->select(exerciseStructMapper, ids), 1, ids.length);
+    }
+
     public List<ExerciseStruct> select(Collection ids){
         return select(exerciseStructMapper, ids);
     }

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

@@ -92,6 +92,10 @@ public class FaqService extends AbstractService {
         return select(faqMapper, page, pageSize);
     }
 
+    public Page<Faq> select(Integer[] ids){
+        return page(()->select(faqMapper, ids), 1, ids.length);
+    }
+
     public List<Faq> select(Collection ids){
         return select(faqMapper, ids);
     }

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

@@ -78,6 +78,10 @@ public class MessageService extends AbstractService {
         return select(messageMapper, page, pageSize);
     }
 
+    public Page<Message> select(Integer[] ids){
+        return page(()->select(messageMapper, ids), 1, ids.length);
+    }
+
     public List<Message> select(Collection ids){
         return select(messageMapper, ids);
     }

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


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