Selaa lähdekoodia

feat(server): 预习作业

Go 5 vuotta sitten
vanhempi
commit
e2fc2b3dad
55 muutettua tiedostoa jossa 2036 lisäystä ja 636 poistoa
  1. 2 0
      front/project/Constant.js
  2. 9 0
      front/project/admin/routes/course/detail/page.js
  3. 1 1
      front/project/admin/routes/course/vsDetail/page.js
  4. 2 2
      front/project/h5/routes/textbook/main/page.js
  5. 1 1
      front/project/h5/stores/course.js
  6. 1 1
      front/project/www/components/Login/index.js
  7. 13 0
      front/project/www/routes/examination/main/page.js
  8. 52 42
      front/project/www/routes/exercise/main/page.js
  9. 10 0
      front/project/www/routes/preview/list/index.js
  10. 59 0
      front/project/www/routes/preview/list/index.less
  11. 286 0
      front/project/www/routes/preview/list/page.js
  12. 10 2
      front/project/www/stores/course.js
  13. 7 6
      front/project/www/stores/question.js
  14. 0 7
      server/data/src/main/java/com/qxgmat/data/dao/CourseStudentOnlineMapper.java
  15. 23 23
      server/data/src/main/java/com/qxgmat/data/dao/entity/Course.java
  16. 0 195
      server/data/src/main/java/com/qxgmat/data/dao/entity/CourseStudentOnline.java
  17. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrderRecord.java
  18. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserPaper.java
  19. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserService.java
  20. 3 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CourseMapper.xml
  21. 5 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml
  22. 4 3
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserPaperMapper.xml
  23. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserServiceMapper.xml
  24. 28 0
      server/data/src/main/java/com/qxgmat/data/relation/UserOrderRecordRelationMapper.java
  25. 0 5
      server/data/src/main/java/com/qxgmat/data/relation/UserPaperRelationMapper.java
  26. 68 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml
  27. 0 21
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserPaperRelationMapper.xml
  28. 45 18
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  29. 8 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/PreviewController.java
  30. 8 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  31. 89 58
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  32. 67 14
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  33. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/SentenceController.java
  34. 5 9
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  35. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/CourseStudentOnlineDto.java
  36. 15 15
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CourseStudentOnlineListDto.java
  37. 140 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserCourseAppointmentExtendDto.java
  38. 109 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserServiceRecordExtendDto.java
  39. 102 21
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseDetailDto.java
  40. 142 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseProgressDto.java
  41. 92 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExaminationGroupDto.java
  42. 10 9
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserTextbookInfoDto.java
  43. 23 1
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  44. 10 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java
  45. 18 7
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  46. 132 28
      server/gateway-api/src/main/java/com/qxgmat/service/extend/PreviewService.java
  47. 32 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  48. 0 119
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CourseStudentOnlineService.java
  49. 14 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExaminationPaperService.java
  50. 117 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewAssignService.java
  51. 10 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewPaperService.java
  52. 12 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseAppointmentService.java
  53. 11 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseProgressService.java
  54. 95 17
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java
  55. 1 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java

+ 2 - 0
front/project/Constant.js

@@ -70,6 +70,8 @@ export const ExperiencePercent = [{ label: '50+', value: '_50' }, { label: '100+
 
 export const CourseModule = [{ label: '视频课程', value: 'video' }, { label: '小班课程', value: 'online' }, { label: '1v1课程', value: 'vs' }];
 
+export const CourseModuleShow = [{ label: '在线课程', value: 'online', courseModules: ['video', 'online'] }, { label: '1V1私教', value: 'vs', courseModules: ['vs'] }];
+
 export const CourseVsType = [{ label: '新手辅导', value: 'novice' }, { label: '诊断辅导', value: 'coach' }, { label: '系统授课', value: 'system' }, { label: '答疑课', value: 'answer' }];
 
 export const CourseVideoType = [{ label: '基础刷题', value: 'base' }, { label: '系统授课', value: 'system' }, { label: '思维提升', value: 'thinking' }];

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

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

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

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

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

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

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

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

+ 1 - 1
front/project/www/components/Login/index.js

@@ -84,7 +84,7 @@ export default class Login extends Component {
 
   scanLogin() {
     User.loginWechat('').then((result) => {
-      if (result.id) {
+      if (result.bindMobile) {
         this.close();
       } else {
         this.setState({ type: BIND_PHONE });

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

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

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

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

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

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

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

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

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

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

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

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

+ 7 - 6
front/project/www/stores/question.js

@@ -2,18 +2,19 @@ import BaseStore from '@src/stores/base';
 
 export default class QuestionStore extends BaseStore {
   startLink(type, item) {
-    const w = window.open('about:blank');
-    w.location.href = `/paper/process/${type}/${item.id}`;
+    openLink(`/paper/process/${type}/${item.id}`);
   }
 
   continueLink(type, item) {
-    const w = window.open('about:blank');
-    w.location.href = `/paper/process/${type}/${item.id}?r=${item.report.id}`;
+    // const w = window.open('about:blank');
+    // w.location.href = `/paper/process/${type}/${item.id}?r=${item.report.id}`;
+    openLink(`/paper/process/${type}/${item.id}?r=${item.report.id}`);
   }
 
   reportLink(item) {
-    const w = window.open('about:blank');
-    w.location.href = `/paper/report/${item.report.id}`;
+    // const w = window.open('about:blank');
+    // w.location.href = `/paper/report/${item.report.id}`;
+    openLink(`/paper/report/${item.report.id}`);
   }
 
   /**

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

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

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

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

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

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

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

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

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

@@ -42,6 +42,12 @@ public class UserPaper implements Serializable {
     private Integer originId;
 
     /**
+     * 关联记录id
+     */
+    @Column(name = "`record_id`")
+    private Integer recordId;
+
+    /**
      * 题目编号id列表:json
      */
     @Column(name = "`question_no_ids`")
@@ -208,6 +214,24 @@ public class UserPaper implements Serializable {
     }
 
     /**
+     * 获取关联记录id
+     *
+     * @return record_id - 关联记录id
+     */
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    /**
+     * 设置关联记录id
+     *
+     * @param recordId 关联记录id
+     */
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    /**
      * 获取题目编号id列表:json
      *
      * @return question_no_ids - 题目编号id列表:json
@@ -399,6 +423,7 @@ public class UserPaper implements Serializable {
         sb.append(", paperModule=").append(paperModule);
         sb.append(", paperOrigin=").append(paperOrigin);
         sb.append(", originId=").append(originId);
+        sb.append(", recordId=").append(recordId);
         sb.append(", questionNoIds=").append(questionNoIds);
         sb.append(", questionNumber=").append(questionNumber);
         sb.append(", times=").append(times);
@@ -483,6 +508,16 @@ public class UserPaper implements Serializable {
         }
 
         /**
+         * 设置关联记录id
+         *
+         * @param recordId 关联记录id
+         */
+        public Builder recordId(Integer recordId) {
+            obj.setRecordId(recordId);
+            return this;
+        }
+
+        /**
          * 设置题目编号id列表:json
          *
          * @param questionNoIds 题目编号id列表:json

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qxgmat.data.relation.UserNoteQuestionRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.UserNoteQuestion">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <resultMap id="NumberMap" type="com.qxgmat.data.relation.entity.CourseStudentNumberRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+    <id column="number" jdbcType="INTEGER" property="number" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    up.`id`
+  </sql>
+
+  <!--
+    统计学生人数
+  -->
+  <select id="groupByTime" resultMap="NumberMap">
+    select
+    count(cs.`id`) as `number`, cs.`no` as `id`
+    from `user_order_record` uor
+    where
+    uor.`no` IN
+    <foreach collection="ids" item="item" index="index" open="(" close=")" separator=",">
+      #{item}
+    </foreach>
+  </select>
+  <!--
+    用户笔记题目列表
+  -->
+  <select id="list" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `user_note_question` ucq
+    left join `question_no` qn on qn.`id` = ucq.`question_no_id`
+    <if test="module != null">
+      and qn.`module` = #{module,jdbcType=VARCHAR}
+    </if>
+    left join `question` q on q.`id` = ucq.`question_id`
+    <if test="questionType != null">
+      and q.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    where
+    qn.`id` &gt; 0
+    and q.`id` &gt; 0
+    <if test="userId != null">
+      and ucq.`user_id` = #{userId,jdbcType=VARCHAR}
+    </if>
+    <if test="startTime != null">
+      and ucq.`createTime` &gt; #{startTime,jdbcType=VARCHAR}
+    </if>
+    <if test="endTime != null">
+      and ucq.`createTime` &lt; #{endTime,jdbcType=VARCHAR}
+    </if>
+
+    order by ${order} ${direction}
+  </select>
+
+</mapper>

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

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

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

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

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

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

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

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

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

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

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

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

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

@@ -220,7 +220,7 @@ public class SentenceController
         if (user != null){
             // 获取做题记录
             Collection ids = Transform.getIds(p, SentencePaper.class, "id");
-            List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.SENTENCE, ids);
+            List<UserPaper> userPaperList = userPaperService.listWithOrigin(user.getId(), PaperOrigin.SENTENCE, ids, null);
             Transform.combine(pr, userPaperList, UserSentencePaperDto.class, "id", "paper", UserPaper.class, "originId", UserPaperBaseExtendDto.class);
             // 绑定userPaperId,用于关联report
             Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");

+ 5 - 9
server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java

@@ -1,19 +1,14 @@
 package com.qxgmat.controller.api;
 
 import com.github.pagehelper.Page;
-import com.nuliji.tools.PageMessage;
-import com.nuliji.tools.Response;
-import com.nuliji.tools.ResponseHelp;
-import com.nuliji.tools.Tools;
+import com.nuliji.tools.*;
 import com.nuliji.tools.exception.AuthException;
 import com.nuliji.tools.exception.ParameterException;
 import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.ServiceKey;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
-import com.qxgmat.data.dao.entity.TextbookLibrary;
-import com.qxgmat.data.dao.entity.TextbookLibraryHistory;
-import com.qxgmat.data.dao.entity.TextbookTopic;
-import com.qxgmat.data.dao.entity.User;
+import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.dto.extend.UserServiceRecordExtendDto;
 import com.qxgmat.dto.response.UserTextbookInfoDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.UserServiceService;
@@ -77,7 +72,8 @@ public class TextbookController
         dto.setLatest(latest);
         if (user != null){
             dto.setHasService(userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK));
-            dto.setUnUseRecord(userOrderRecordService.getUnUseService(user.getId(), ServiceKey.TEXTBOOK));
+            UserOrderRecord record = userOrderRecordService.getUnUseService(user.getId(), ServiceKey.TEXTBOOK);
+            dto.setUnUseRecord(Transform.convert(record, UserServiceRecordExtendDto.class));
         }
         TextbookLibrary second = textbookLibraryService.getSecond();
         dto.setSecond(second);

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

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

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

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

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

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

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

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

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

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

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

@@ -0,0 +1,142 @@
+package com.qxgmat.dto.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.dto.extend.CourseExtendDto;
+import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
+
+import java.util.Date;
+import java.util.List;
+
+@Dto(entity = UserOrderRecord.class)
+public class UserCourseProgressDto {
+    private Integer id;
+
+    private Integer productId;
+
+    private CourseExtendDto course;
+
+    private Date startTime;
+
+    private Date endTime;
+
+    private Date useStartTime;
+
+    private Date useEndTime;
+
+    private Integer isUse;
+
+    private Integer isStop;
+
+    private Integer isSuspend;
+
+    private Date suspendTime;
+
+    private Date restoreTime;
+
+    private List<UserPaperBaseExtendDto> papers;
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public List<UserPaperBaseExtendDto> getPapers() {
+        return papers;
+    }
+
+    public void setPapers(List<UserPaperBaseExtendDto> papers) {
+        this.papers = papers;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getProductId() {
+        return productId;
+    }
+
+    public void setProductId(Integer productId) {
+        this.productId = productId;
+    }
+
+    public CourseExtendDto getCourse() {
+        return course;
+    }
+
+    public void setCourse(CourseExtendDto course) {
+        this.course = course;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Date getUseStartTime() {
+        return useStartTime;
+    }
+
+    public void setUseStartTime(Date useStartTime) {
+        this.useStartTime = useStartTime;
+    }
+
+    public Date getUseEndTime() {
+        return useEndTime;
+    }
+
+    public void setUseEndTime(Date useEndTime) {
+        this.useEndTime = useEndTime;
+    }
+
+    public Integer getIsUse() {
+        return isUse;
+    }
+
+    public void setIsUse(Integer isUse) {
+        this.isUse = isUse;
+    }
+
+    public Integer getIsStop() {
+        return isStop;
+    }
+
+    public void setIsStop(Integer isStop) {
+        this.isStop = isStop;
+    }
+
+    public Integer getIsSuspend() {
+        return isSuspend;
+    }
+
+    public void setIsSuspend(Integer isSuspend) {
+        this.isSuspend = isSuspend;
+    }
+
+    public Date getSuspendTime() {
+        return suspendTime;
+    }
+
+    public void setSuspendTime(Date suspendTime) {
+        this.suspendTime = suspendTime;
+    }
+
+    public Date getRestoreTime() {
+        return restoreTime;
+    }
+
+    public void setRestoreTime(Date restoreTime) {
+        this.restoreTime = restoreTime;
+    }
+}

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

@@ -0,0 +1,92 @@
+package com.qxgmat.dto.response;
+
+import com.qxgmat.dto.extend.UserServiceRecordExtendDto;
+
+public class UserExaminationGroupDto {
+    private Integer id;
+    private String titleZh;
+    private String titleEn;
+    private String title;
+
+    private Integer paperNumber;
+
+    private Integer userNumber;
+
+    private Integer minTimes;
+
+    private Boolean hasService;
+
+    private UserServiceRecordExtendDto unUseRecord;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitleZh() {
+        return titleZh;
+    }
+
+    public void setTitleZh(String titleZh) {
+        this.titleZh = titleZh;
+    }
+
+    public String getTitleEn() {
+        return titleEn;
+    }
+
+    public void setTitleEn(String titleEn) {
+        this.titleEn = titleEn;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public Integer getUserNumber() {
+        return userNumber;
+    }
+
+    public void setUserNumber(Integer userNumber) {
+        this.userNumber = userNumber;
+    }
+
+    public Integer getMinTimes() {
+        return minTimes;
+    }
+
+    public void setMinTimes(Integer minTimes) {
+        this.minTimes = minTimes;
+    }
+
+    public Integer getPaperNumber() {
+        return paperNumber;
+    }
+
+    public void setPaperNumber(Integer paperNumber) {
+        this.paperNumber = paperNumber;
+    }
+
+    public Boolean getHasService() {
+        return hasService;
+    }
+
+    public void setHasService(Boolean hasService) {
+        this.hasService = hasService;
+    }
+
+    public UserServiceRecordExtendDto getUnUseRecord() {
+        return unUseRecord;
+    }
+
+    public void setUnUseRecord(UserServiceRecordExtendDto unUseRecord) {
+        this.unUseRecord = unUseRecord;
+    }
+}

+ 10 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserTextbookInfoDto.java

@@ -1,6 +1,7 @@
 package com.qxgmat.dto.response;
 
 import com.qxgmat.data.dao.entity.TextbookLibrary;
+import com.qxgmat.dto.extend.UserServiceRecordExtendDto;
 
 public class UserTextbookInfoDto {
     private TextbookLibrary latest;
@@ -9,7 +10,7 @@ public class UserTextbookInfoDto {
 
     private Boolean hasService;
 
-    private Integer unUseRecord;
+    private UserServiceRecordExtendDto unUseRecord;
 
     private Boolean emailSubscribe;
 
@@ -21,14 +22,6 @@ public class UserTextbookInfoDto {
         this.hasService = hasService;
     }
 
-    public Integer getUnUseRecord() {
-        return unUseRecord;
-    }
-
-    public void setUnUseRecord(Integer unUseRecord) {
-        this.unUseRecord = unUseRecord;
-    }
-
     public TextbookLibrary getLatest() {
         return latest;
     }
@@ -52,4 +45,12 @@ public class UserTextbookInfoDto {
     public void setEmailSubscribe(Boolean emailSubscribe) {
         this.emailSubscribe = emailSubscribe;
     }
+
+    public UserServiceRecordExtendDto getUnUseRecord() {
+        return unUseRecord;
+    }
+
+    public void setUnUseRecord(UserServiceRecordExtendDto unUseRecord) {
+        this.unUseRecord = unUseRecord;
+    }
 }

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

@@ -75,9 +75,10 @@ public class UserPaperService extends AbstractService {
      * @param userId
      * @param origin
      * @param ids
+     * @param recordId
      * @return
      */
-    public List<UserPaper> listWithOrigin(Integer userId, PaperOrigin origin, Collection ids){
+    public List<UserPaper> listWithOrigin(Integer userId, PaperOrigin origin, Collection ids, Integer recordId){
         Example example = new Example(UserPaper.class);
         example.and(
                 example.createCriteria()
@@ -85,6 +86,12 @@ public class UserPaperService extends AbstractService {
                 .andEqualTo("paperOrigin", origin.key)
                 .andIn("originId", ids)
         );
+        if (recordId != null){
+            example.and(
+                    example.createCriteria()
+                        .andEqualTo("recordId", recordId)
+            );
+        }
         return select(userPaperMapper, example);
     }
 
@@ -157,6 +164,21 @@ public class UserPaperService extends AbstractService {
     }
 
     /**
+     * 重置做题信息:不自动关联最后次做题记录
+     * @param ids
+     * @return
+     */
+    public Boolean reset(Collection ids, Integer userId){
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("id", ids)
+                        .andEqualTo("userId", userId)
+        );
+        return update(userPaperMapper, example, UserPaper.builder().isReset(1).build()) > 0;
+    }
+
+    /**
      * 累加做题记录到paper
      * @param report
      */

+ 10 - 1
server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java

@@ -26,11 +26,20 @@ public class CourseExtendService {
      */
     public int computeExpire(Integer vsNumber, Course course){
         // day / 10
-        Integer expireDays = course.getExpireDays();
+        Integer expireDays = course.getExpirePreDays();
 
         return Math.min(vsNumber / 10, 0)  * expireDays;
     }
 
+    /**
+     * 获取video课程有效期
+     * @param course
+     * @return
+     */
+    public int computeExpire(Course course){
+        return course.getExpireDays();
+    }
+
     public void suspendCourse(Integer userId, Integer courseId){
 
     }

+ 18 - 7
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -383,7 +383,7 @@ public class OrderFlowService {
                 expireDay = courseExtendService.computeExpire(record.getNumber(), course);
             }else{
                 // 根据设置进行计算
-
+                expireDay = courseExtendService.computeExpire(course);
             }
             Date startTime = time;
             Date endTime = Tools.addDate(startTime, expireDay);
@@ -433,30 +433,41 @@ public class OrderFlowService {
             }
 
             Date startTime = time;
-            Date endTime = Tools.addDate(startTime, expireDay);
+            Date endTime = null;
+            if(expireDay > 0){
+                // 设置结束有效期
+                endTime = Tools.addDate(startTime, expireDay);
+            }
             UserService userService = userServiceService.getService(record.getUserId(), serviceKey);
             if (userService == null){
                 userService = UserService.builder()
                         .userId(record.getUserId())
                         .isSubscribe(record.getIsSubscribe())
+                        .isReset(0)
                         .startTime(startTime)
                         .expireTime(endTime)
                         .build();
                 userService = userServiceService.add(userService);
             }else{
-                if (userService.getExpireTime().before(time)){
+                if (userService.getExpireTime() != null && userService.getExpireTime().before(time)){
                     // 已到期 - 续期
                     userService.setStartTime(startTime);
                     userService.setExpireTime(endTime);
                 }else{
                     if (serviceKey == ServiceKey.QX_CAT){
-                        // 未到期 - 报错
-                        throw new ParameterException("已开通当前服务");
+                        if (userService.getIsReset() == 0){
+                            // 未到期 - 报错
+                            throw new ParameterException("已开通当前服务");
+                        }
+                        // 重置
+                        userService.setIsReset(0);
                     }
                     // 未到期 - 延长有效期
                     startTime = userService.getExpireTime();
-                    endTime = Tools.addDate(userService.getExpireTime(), expireDay);
-                    userService.setExpireTime(endTime);
+                    if (expireDay > 0){
+                        endTime = Tools.addDate(userService.getExpireTime(), expireDay);
+                        userService.setExpireTime(endTime);
+                    }
                 }
                 userService.setIsSubscribe(record.getIsSubscribe());
                 userService = userServiceService.edit(userService);

+ 132 - 28
server/gateway-api/src/main/java/com/qxgmat/service/extend/PreviewService.java

@@ -8,20 +8,15 @@ import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.constants.enums.QuestionType;
-import com.qxgmat.data.constants.enums.module.PaperModule;
-import com.qxgmat.data.constants.enums.module.PaperOrigin;
-import com.qxgmat.data.constants.enums.module.QuestionModule;
+import com.qxgmat.data.constants.enums.module.*;
 import com.qxgmat.data.constants.enums.status.PreviewStatus;
 import com.qxgmat.data.dao.PreviewPaperMapper;
-import com.qxgmat.data.dao.entity.PreviewPaper;
-import com.qxgmat.data.dao.entity.UserPaper;
-import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.relation.UserPaperRelationMapper;
 import com.qxgmat.data.relation.UserReportRelationMapper;
 import com.qxgmat.data.relation.entity.UserPreviewPaperRelation;
 import com.qxgmat.service.UserPaperService;
-import com.qxgmat.service.inline.QuestionNoService;
-import com.qxgmat.service.inline.UserReportService;
+import com.qxgmat.service.inline.*;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -36,7 +31,7 @@ public class PreviewService extends AbstractService {
     private static final Logger logger = LoggerFactory.getLogger(PreviewService.class);
 
     @Resource
-    private PreviewPaperMapper previewPaperMapper;
+    private PreviewPaperService previewPaperService;
 
     @Resource
     private UserReportService userReportService;
@@ -45,10 +40,22 @@ public class PreviewService extends AbstractService {
     private UserPaperService userPaperService;
 
     @Resource
-    private UserReportRelationMapper userReportRelationMapper;
+    private UserOrderRecordService userOrderRecordService;
 
     @Resource
-    private UserPaperRelationMapper userPaperRelationMapper;
+    private CourseService courseService;
+
+    @Resource
+    private CourseNoService courseNoService;
+
+    @Resource
+    private PreviewAssignService previewAssignService;
+
+    @Resource
+    private UserCourseAppointmentService userCourseAppointmentService;
+
+    @Resource
+    private UserCourseProgressService userCourseProgressService;
 
     /**
      * 获取用户分组作业列表
@@ -56,16 +63,88 @@ public class PreviewService extends AbstractService {
      * @param top
      * @return
      */
-    public Map<Object, Collection<UserPreviewPaperRelation>> groupByCategory(Number userId, Number top){
-        List<UserPaper> p = userPaperRelationMapper.listPreviewGroupTop(userId, top);
+    public Map<Object, Collection<UserPreviewPaperRelation>> groupByCourseId(Integer userId, Collection recordIds, Integer top){
         Map<Object, Collection<UserPreviewPaperRelation>> relationMap = new HashMap<>();
+        for(Object id : recordIds){
+            Integer recordId = (Integer)id;
+            relationMap.put(recordId, list(userId, recordId, null, 0, top));
+        }
+        return relationMap;
+    }
 
-        if(p.size() == 0) return relationMap;
-
-        Collection ids = Transform.getIds(p, UserPaper.class, "id");
+    /**
+     * 返回用户的预习作业列表
+     * @param recordId
+     * @param userId
+     * @param endTime
+     * @param times
+     * @return
+     */
+    public List<UserPreviewPaperRelation> list(Integer recordId, Integer userId, String endTime, Integer times, Integer top){
+        // 根据不同的课程,执行不同的查询方案
+        UserOrderRecord record = userOrderRecordService.get(recordId);
+        if (record == null){
+            throw new ParameterException("记录不存在");
+        }
+        if (!record.getUserId().equals(userId)){
+            throw new ParameterException("记录不存在");
+        }
+        if (!record.getProductType().equals(ProductType.COURSE.key)){
+            throw new ParameterException("记录不存在");
+        }
+        Course course = courseService.get(record.getProductId());
+        CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
+        List<PreviewAssign> previewAssignList = new ArrayList<>(0);
+        switch(courseModule){
+            case VS:
+                // 查询记录对应预约情况
+                List<UserCourseAppointment> appointmentList = userCourseAppointmentService.listByRecord(recordId);
+                Collection appointmentIds = Transform.getIds(appointmentList, UserCourseAppointment.class, "id");
+                previewAssignList = previewAssignService.listByAppointment(appointmentIds, endTime, top);
+                break;
+            case ONLINE:
+                // 查询记录对应时间段内
+                previewAssignList = previewAssignService.listByTime(record.getTimeId(), endTime, top);
+                replaceTitle(previewAssignList);
+                break;
+            case VIDEO:
+                // 获取课时,并关联当前记录的paper
+                if (endTime != null){
+                    // 无论列表还是卡片,都只显示2条
+                    top = 2;
+                    List<CourseNo> courseNoList = courseNoService.allCourse(course.getId());
+                    // 查询课时进度
+                    List<UserCourseProgress> progressList =userCourseProgressService.listCourse(record.getId(), course.getId());
+                    Map progressMap = Transform.getMap(progressList, UserCourseProgress.class, "courseNoId");
 
+                    Collections.reverse(courseNoList);
+                    int min = 1;
+                    for(CourseNo no : courseNoList){
+                        // 如果进度不过半,按当前课时+下一课时
+                        // 如果进度过半,下2次课时
+                        UserCourseProgress progress = (UserCourseProgress)progressMap.get(no.getId());
+                        if(progress == null) continue;
+                        if (progress.getProgress() > 50) {
+                            min = no.getNo() + 1;
+                        }else{
+                            min = no.getNo();
+                        }
+                        break;
+                    }
+                    int max = min+top -1;
+                    int finalMin = min;
+                    List<CourseNo> select = courseNoList.stream().filter(row->row.getNo() >= finalMin && row.getNo()<=max).collect(Collectors.toList());
+                    previewAssignList = previewAssignService.listByCourseNos(course.getId(), getIds(select, CourseNo.class, "id"));
+                }else{
+                    previewAssignList = previewAssignService.listByCourse(course.getId());
+                }
+                replaceTitle(previewAssignList);
+                break;
+        }
+        Collection assignIds = Transform.getIds(previewAssignList, PreviewAssign.class, "id");
         // 获取详细数据
-        List<UserPaper> list = userPaperService.select(ids);
+        List<UserPaper> list = userPaperService.listWithOrigin(userId, PaperOrigin.PREVIEW, assignIds, recordId);
+        Collection ids = Transform.getIds(list, UserPaper.class, "id");
         List<UserPreviewPaperRelation> pr = Transform.convert(list, UserPreviewPaperRelation.class);
 
         // 获取最后一次作业结果
@@ -73,17 +152,42 @@ public class PreviewService extends AbstractService {
 
         Transform.combine(pr, reportList, UserPreviewPaperRelation.class, "id", "report", UserReport.class, "paperId");
 
-        for(UserPreviewPaperRelation row: pr){
-            List<UserPreviewPaperRelation> l;
-            Number courseId = row.getPaper().getCourseId();
-            if(!relationMap.containsKey(courseId)){
-                l = new ArrayList<>();
-                relationMap.put(courseId, l);
-            }else{
-                l = (List<UserPreviewPaperRelation>)relationMap.get(courseId);
-            }
-            l.add(row);
+        return pr;
+    }
+
+    /**
+     * 根据试卷,获取当前关联的学习记录
+     * @param assignId
+     * @return
+     */
+    public Integer getRecord(Integer userId, Integer assignId){
+        PreviewAssign assign = previewAssignService.get(assignId);
+        if (assign == null){
+            throw new ParameterException("记录不存在");
         }
-        return relationMap;
+        Course course = courseService.get(assign.getCourseId());
+        CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
+        switch(courseModule){
+            case VS:
+                UserCourseAppointment appointment = userCourseAppointmentService.get(assign.getCourseAppointment());
+                return appointment.getRecordId();
+            case ONLINE:
+                UserOrderRecord timeRecord = userOrderRecordService.getByUserAndTime(userId, assign.getCourseId(), assign.getCourseTime());
+                return timeRecord.getId();
+            case VIDEO:
+                // 获取当前该课程记录
+                UserOrderRecord record = userOrderRecordService.getByUserAndCourse(userId, assign.getCourseId(), true);
+                return record != null ? record.getId() : 0;
+            default:
+                return 0;
+        }
+
+    }
+
+    private void replaceTitle(List<PreviewAssign> previewAssignList){
+        Collection previewIds = Transform.getIds(previewAssignList, PreviewAssign.class, "paperId");
+        List<PreviewPaper> paperList = previewPaperService.select(previewIds);
+        Map paperTitle = Transform.getMap(paperList, PreviewPaper.class, "id", "title");
+        Transform.combine(previewAssignList, paperTitle, PreviewAssign.class, "paperId", "title");
     }
 }

+ 32 - 1
server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java

@@ -141,6 +141,12 @@ public class QuestionFlowService {
                 case VS:
                     userPaper.setTitle(assign.getTitle());
             }
+            // 新paper绑定当前记录关系
+            if (userPaper.getRecordId() == 0){
+                // 获取用户当前课程记录
+                Integer recordId = previewService.getRecord(userPaper.getUserId(), id);
+                userPaper.setRecordId(recordId);
+            }
 
             userPaper.setQuestionNoIds(paper.getQuestionNoIds());
             // 根据papermodule得到考试时长
@@ -656,6 +662,7 @@ public class QuestionFlowService {
      * @param userId
      * @return
      */
+    @Transactional
     public Boolean restart(Integer userPaperId, Integer userId){
         // 获取最后一次report,并生成结果
         UserReport userReport = userReportService.getLastByPaper(userId, userPaperId);
@@ -670,11 +677,35 @@ public class QuestionFlowService {
     }
 
     /**
+     * 重置模考系列
+     * @param structId
+     * @param userId
+     * @return
+     */
+    @Transactional
+    public Boolean restartExamination(Integer structId, Integer userId){
+        List<ExaminationPaper> paperList = examinationPaperService.listByTwo(structId);
+        Collection ids = Transform.getIds(paperList, ExaminationPaper.class, "id");
+        List<UserPaper> userPaperList = userPaperService.listWithOrigin(userId, PaperOrigin.EXAMINATION, ids, null);
+        if (paperList.size() != userPaperList.size()){
+            throw new ParameterException("未完成所有");
+        }
+        Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
+        List<UserReport> reportList = userReportService.listWithLater(paperIds);
+        for(UserReport report: reportList){
+            if(report.getIsFinish() == 0){
+                throw new ParameterException("未完成所有");
+            }
+        }
+        return userPaperService.reset(paperIds, userId);
+    }
+
+    /**
      * 累计考试学习时间
      * @param userId
      * @return
      */
-    public Integer studyTime(Integer userId){
+    public Integer studyTime(Integer userId, Date startTime, Date endTime){
         return 0;
     }
 

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

@@ -1,119 +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.CourseStudentOnlineMapper;
-import com.qxgmat.data.dao.entity.CourseStudentOnline;
-import com.qxgmat.data.dao.entity.CourseTime;
-import com.qxgmat.data.relation.CourseStudentOnlineRelationMapper;
-import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
-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;
-import java.util.Map;
-
-@Service
-public class CourseStudentOnlineService extends AbstractService {
-    private static final Logger logger = LoggerFactory.getLogger(CourseStudentOnlineService.class);
-
-    @Resource
-    private CourseStudentOnlineMapper courseStudentOnlineMapper;
-
-    @Resource
-    private CourseStudentOnlineRelationMapper courseStudentOnlineRelationMapper;
-
-    public Page<CourseStudentOnline> listAdmin(int page, int size, Integer courseId, Integer timeId){
-        Example example = new Example(CourseStudentOnline.class);
-        if(courseId != null){
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("courseId", courseId)
-            );
-        }
-        if(timeId != null){
-            example.and(
-                    example.createCriteria()
-                            .andEqualTo("timeId", timeId)
-            );
-        }
-        return select(courseStudentOnlineMapper, example, page, size);
-    }
-
-    public List<CourseStudentNumberRelation> groupByCourse(Collection ids){
-        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());
-        if(course == null){
-            throw new SystemException("课时添加失败");
-        }
-        return course;
-    }
-
-    public CourseStudentOnline edit(CourseStudentOnline course){
-        CourseStudentOnline in = one(courseStudentOnlineMapper, course.getId());
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        int result = update(courseStudentOnlineMapper, course);
-        return course;
-    }
-
-    public boolean delete(Number id){
-        CourseStudentOnline in = one(courseStudentOnlineMapper, id);
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        int result = delete(courseStudentOnlineMapper, id);
-        return result > 0;
-    }
-
-    public CourseStudentOnline get(Number id){
-        CourseStudentOnline in = one(courseStudentOnlineMapper, id);
-
-        if(in == null){
-            throw new ParameterException("课时不存在");
-        }
-        return in;
-    }
-
-    public Page<CourseStudentOnline> select(int page, int pageSize){
-        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);
-    }
-
-}

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

@@ -37,6 +37,20 @@ public class ExaminationPaperService extends AbstractService {
         return one(examinationPaperMapper, example);
     }
 
+    /**
+     * 根据第二层获取paper
+     * @param id
+     * @return
+     */
+    public List<ExaminationPaper> listByTwo(Integer id){
+        Example example = new Example(ExaminationPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("structTwo", id)
+        );
+        return select(examinationPaperMapper, example);
+    }
+
     public ExaminationPaper add(ExaminationPaper paper){
         int result = insert(examinationPaperMapper, paper);
         paper = one(examinationPaperMapper, paper.getId());

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

@@ -48,6 +48,123 @@ public class PreviewAssignService extends AbstractService {
         return select(previewAssignMapper, example, page, size);
     }
 
+    public PreviewAssign getByCourseNo(Integer courseId, Integer no){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                .andEqualTo("courseId", courseId)
+                .andEqualTo("courseNo", no)
+        );
+        return one(previewAssignMapper, example);
+    }
+
+    public boolean removeCourseNo(Integer courseId, Integer no){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+                        .andEqualTo("courseNo", no)
+        );
+        return delete(previewAssignMapper, example) > 0;
+    }
+
+    /**
+     * 用于查询视频课程所有作业
+     * @param courseId
+     * @return
+     */
+    public List<PreviewAssign> listByCourse(Integer courseId){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+        );
+        return select(previewAssignMapper, example);
+    }
+
+    /**
+     * 用于查询视频课程指定课时作业
+     * @param courseId
+     * @return
+     */
+    public List<PreviewAssign> listByCourseNos(Integer courseId, Collection ids){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+                        .andIn("courseNo", ids)
+        );
+        return select(previewAssignMapper, example);
+    }
+
+    /**
+     * 用户查询1v1相对的预约作业
+     * @param ids
+     * @return
+     */
+    public List<PreviewAssign> listByAppointment(Collection ids, String endTime, Integer top){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("courseAppointment", ids)
+        );
+        if (endTime != null){
+            example.and(
+                    example.createCriteria()
+                        .andLessThanOrEqualTo("endTime", endTime)
+            );
+        }
+        example.orderBy("startTime").asc();
+        if (top != null){
+            return select(previewAssignMapper, example, 1, top);
+        }
+        return select(previewAssignMapper, example);
+    }
+
+    public boolean removeCourseAppointment(Integer courseId, Integer id){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+                        .andEqualTo("courseAppointment", id)
+        );
+        return delete(previewAssignMapper, example) > 0;
+    }
+
+    /**
+     * 用户查询小班课时间段内的预习作业
+     * @param timeId
+     * @return
+     */
+    public List<PreviewAssign> listByTime(Integer timeId, String endTime, Integer top){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseTime", timeId)
+        );
+        if (endTime != null){
+            example.and(
+                    example.createCriteria()
+                            .andLessThanOrEqualTo("endTime", endTime)
+            );
+        }
+        example.orderBy("startTime").asc();
+        if (top != null){
+            return select(previewAssignMapper, example, 1, top);
+        }
+        return select(previewAssignMapper, example);
+    }
+
+    public boolean removeCourseTime(Integer courseId, Integer timeId){
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+                        .andEqualTo("courseTime", timeId)
+        );
+        return delete(previewAssignMapper, example) > 0;
+    }
+
     public PreviewAssign add(PreviewAssign assign){
         int result = insert(previewAssignMapper, assign);
         assign = one(previewAssignMapper, assign.getId());

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

@@ -56,6 +56,16 @@ public class PreviewPaperService extends AbstractService {
         return p;
     }
 
+    public boolean removeCourseNo(Integer courseId, Integer no){
+        Example example = new Example(PreviewPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+                        .andEqualTo("courseNo", no)
+        );
+        return delete(previewPaperMapper, example) > 0;
+    }
+
     public PreviewPaper add(PreviewPaper paper){
         int result = insert(previewPaperMapper, paper);
         paper = one(previewPaperMapper, paper.getId());

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

@@ -78,6 +78,18 @@ public class UserCourseAppointmentService extends AbstractService {
         return add(appointment);
     }
 
+    public Boolean deleteAppointment(Number id){
+        UserCourseAppointment in = get(id);
+        List<UserCourseAppointment> nos = listByRecord(in.getRecordId());
+        for(UserCourseAppointment no : nos){
+            if (no.getNo() < in.getNo()){
+                continue;
+            }
+            edit(UserCourseAppointment.builder().id(no.getId()).no(no.getNo() - 1).build());
+        }
+        return delete(id);
+    }
+
     public UserCourseAppointment add(UserCourseAppointment appointment){
         int result = insert(userCourseAppointmentMapper, appointment);
         appointment = one(userCourseAppointmentMapper, appointment.getId());

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

@@ -4,6 +4,7 @@ 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.UserCourseProgressMapper;
 import com.qxgmat.data.dao.entity.UserCourse;
 import com.qxgmat.data.dao.entity.UserCourseProgress;
@@ -22,6 +23,16 @@ public class UserCourseProgressService extends AbstractService {
     @Resource
     private UserCourseProgressMapper userCourseProgressMapper;
 
+    public List<UserCourseProgress> listCourse(Integer recordId, Integer courseId){
+        Example example = new Example(UserCourseProgress.class);
+        example.and(
+                example.createCriteria()
+                    .andEqualTo("recordId", recordId)
+                    .andEqualTo("courseId", courseId)
+        );
+        return select(userCourseProgressMapper, example);
+    }
+
     public UserCourseProgress add(UserCourseProgress progress){
         int result = insert(userCourseProgressMapper, progress);
         progress = one(userCourseProgressMapper, progress.getId());

+ 95 - 17
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java

@@ -2,6 +2,7 @@ package com.qxgmat.service.inline;
 
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
@@ -12,6 +13,8 @@ import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.UserOrderRecordMapper;
 import com.qxgmat.data.dao.entity.UserOrder;
 import com.qxgmat.data.dao.entity.UserOrderRecord;
+import com.qxgmat.data.relation.UserOrderRecordRelationMapper;
+import com.qxgmat.data.relation.entity.CourseStudentNumberRelation;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -26,6 +29,83 @@ public class UserOrderRecordService extends AbstractService {
     @Resource
     private UserOrderRecordMapper userOrderRecordMapper;
 
+    @Resource
+    private UserOrderRecordRelationMapper userOrderRecordRelationMapper;
+
+    public Page<UserOrderRecord> listAdminByOnline(int page, int size, Integer courseId, Integer timeId){
+        Example example = new Example(UserOrderRecord.class);
+        if(courseId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("productType", ProductType.COURSE.key)
+                            .andEqualTo("productId", courseId)
+            );
+        }
+        if(timeId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("timeId", timeId)
+            );
+        }
+        return select(userOrderRecordMapper, example, page, size);
+    }
+
+    public void changeStudentTime(Integer courseId, Integer timeId, Date startTime, Date endTime){
+        Example example = new Example(UserOrderRecord.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("productType", ProductType.COURSE.key)
+                        .andEqualTo("productId", courseId)
+                        .andEqualTo("timeId", timeId)
+        );
+        update(userOrderRecordMapper, example, UserOrderRecord.builder().startTime(startTime).endTime(endTime).build());
+    }
+
+    public List<CourseStudentNumberRelation> groupByCourse(Collection ids){
+        return userOrderRecordRelationMapper.groupByTime(ids);
+    }
+
+    public UserOrderRecord getByUserAndTime(Integer userId, Integer courseId, Integer timeId){
+        Example example = new Example(UserOrderRecord.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("productType", ProductType.COURSE.key)
+                        .andEqualTo("productId", courseId)
+                        .andEqualTo("timeId", timeId)
+        );
+        return one(userOrderRecordMapper, example);
+    }
+
+    public UserOrderRecord addStudent(UserOrderRecord course){
+        UserOrderRecord in = getByUserAndTime(course.getUserId(), course.getProductId(), course.getTimeId());
+        if(in != null){
+            throw new ParameterException("已添加");
+        }
+        return add(course);
+    }
+
+    public UserOrderRecord getByUserAndCourse(Integer userId, Integer courseId, Boolean process){
+        Example example = new Example(UserOrderRecord.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("productId", courseId)
+        );
+        if (process != null){
+             example.and(
+                    process?  example.createCriteria()
+                    .andEqualTo("isUse", 1)
+                    .andGreaterThanOrEqualTo("useEndTime", new Date()):
+                            example.createCriteria()
+                     .andEqualTo("isUse", 1)
+                     .andLessThanOrEqualTo("useEndTime", new Date())
+
+            );
+        }
+        return one(userOrderRecordMapper, example);
+    }
+
     public Page<UserOrderRecord> listAdmin(int page, int size, Integer userId, ProductType productType, Integer productId, ServiceKey service, Boolean needMoney, Boolean needPackage, String order, DirectionStatus direction){
         Example example = new Example(UserOrderRecord.class);
         if(userId != null){
@@ -132,7 +212,7 @@ public class UserOrderRecordService extends AbstractService {
      * @param key
      * @return
      */
-    public Integer getUnUseService(Integer userId, ServiceKey key){
+    public UserOrderRecord getUnUseService(Integer userId, ServiceKey key){
         Example example = new Example(UserOrderRecord.class);
         example.and(
                 example.createCriteria()
@@ -144,7 +224,7 @@ public class UserOrderRecordService extends AbstractService {
         );
         example.orderBy("startTime").asc();
         UserOrderRecord record = one(userOrderRecordMapper, example);
-        return record!=null?record.getId() : 0;
+        return record;
     }
 
     /**
@@ -215,23 +295,21 @@ public class UserOrderRecordService extends AbstractService {
      * @param userId
      * @return
      */
-    public Page<UserOrderRecord> listWithStudyAdmin(int page, int size, CourseModule module, Integer structId, Integer courseId, Integer userId, String teacher){
-        Example example = new Example(UserOrderRecord.class);
-        example.and(
-                example.createCriteria().andEqualTo("productType", ProductType.COURSE.key)
-        );
-        if (courseId != null){
-            example.and(
-                    example.createCriteria().andEqualTo("productId", courseId)
-            );
-        }
-        if (userId != null){
-            example.and(
-                    example.createCriteria().andEqualTo("userId", userId)
-            );
+    public Page<UserOrderRecord> listWithStudyAdmin(int page, int size, String[] modules, Integer structId, Integer courseId, Integer userId, String teacher, String order, DirectionStatus direction){
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
         }
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<UserOrderRecord> p = page(
+            ()-> userOrderRecordRelationMapper.listWithStudyAdmin(modules, structId, courseId, userId, finalOrder, finalDirection.key)
+        , page, size);
 
-        return select(userOrderRecordMapper, example, page, size);
+        Collection ids = Transform.getIds(p, UserOrderRecord.class, "id");
+        Transform.replace(p, select(ids), UserOrderRecord.class, "id");
+
+        return p;
     }
 
     /**

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

@@ -218,6 +218,7 @@ public class UserReportService extends AbstractService {
         userReportRelationMapper.accumulation(question.getReportId(), 1, question.getUserTime(), question.getIsCorrect());
     }
 
+
     public UserReport add(UserReport report){
         int result = insert(userReportMapper, report);
         report = one(userReportMapper, report.getId());