瀏覽代碼

feat(server): 后台学习记录

Go 5 年之前
父節點
當前提交
fdb4127bd9
共有 93 個文件被更改,包括 2311 次插入1478 次删除
  1. 40 5
      front/project/Constant.js
  2. 40 32
      front/project/admin/routes/course/experienceDetail/page.js
  3. 2 2
      front/project/admin/routes/course/student/page.js
  4. 42 19
      front/project/admin/routes/interaction/askQuestion/page.js
  5. 5 1
      front/project/admin/routes/interaction/askQuestionDetail/page.js
  6. 98 135
      front/project/admin/routes/interaction/comment/page.js
  7. 83 52
      front/project/admin/routes/interaction/faq/page.js
  8. 120 43
      front/project/admin/routes/interaction/feedback/page.js
  9. 88 104
      front/project/admin/routes/show/comment/page.js
  10. 54 336
      front/project/admin/routes/show/deploy/page.js
  11. 64 44
      front/project/admin/routes/show/faq/page.js
  12. 24 18
      front/project/admin/routes/student/askCourse/page.js
  13. 42 19
      front/project/admin/routes/student/askQuestion/page.js
  14. 6 2
      front/project/admin/routes/student/askQuestionDetail/page.js
  15. 27 23
      front/project/admin/routes/student/studyDetail/page.js
  16. 30 34
      front/project/admin/routes/user/recordAll/page.js
  17. 22 32
      front/project/admin/routes/user/recordBuy/page.js
  18. 1 1
      front/project/admin/stores/system.js
  19. 5 1
      front/project/admin/stores/user.js
  20. 16 16
      front/project/www/routes/examination/list/page.js
  21. 2 2
      front/project/www/routes/paper/question/page.js
  22. 3 2
      front/project/www/static/login.html
  23. 3 3
      front/project/www/stores/my.js
  24. 3 1
      front/src/layouts/FormLayout/index.js
  25. 37 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/AskModule.java
  26. 175 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExaminationPaper.java
  27. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserAskCourse.java
  28. 86 16
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserAskQuestion.java
  29. 0 35
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserCourseAppointment.java
  30. 105 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserFeedbackError.java
  31. 53 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserOrderRecord.java
  32. 7 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExaminationPaperMapper.xml
  33. 4 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserAskCourseMapper.xml
  34. 6 4
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserAskQuestionMapper.xml
  35. 1 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserCourseAppointmentMapper.xml
  36. 5 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserFeedbackErrorMapper.xml
  37. 3 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserOrderRecordMapper.xml
  38. 24 0
      server/data/src/main/java/com/qxgmat/data/relation/CommentRelationMapper.java
  39. 9 0
      server/data/src/main/java/com/qxgmat/data/relation/ExaminationPaperRelationMapper.java
  40. 25 0
      server/data/src/main/java/com/qxgmat/data/relation/FaqRelationMapper.java
  41. 1 0
      server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java
  42. 6 0
      server/data/src/main/java/com/qxgmat/data/relation/UserCourseRecordRelationMapper.java
  43. 3 0
      server/data/src/main/java/com/qxgmat/data/relation/UserFeedbackErrorRelationMapper.java
  44. 59 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/CommentRelationMapper.xml
  45. 22 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExaminationPaperRelationMapper.xml
  46. 62 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/FaqRelationMapper.xml
  47. 3 3
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskCourseRelationMapper.xml
  48. 8 5
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml
  49. 17 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserCourseRecordRelationMapper.xml
  50. 14 3
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserFeedbackErrorRelationMapper.xml
  51. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRecordRelationMapper.xml
  52. 3 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserRelationMapper.xml
  53. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserTextbookFeedbackRelationMapper.xml
  54. 0 17
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/AdController.java
  55. 13 2
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  56. 10 6
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  57. 58 11
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  58. 89 8
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  59. 20 4
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  60. 12 13
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  61. 1 4
      server/gateway-api/src/main/java/com/qxgmat/controller/api/SentenceController.java
  62. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  63. 23 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/InfoExtendDto.java
  64. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserPaperExtendDto.java
  65. 5 5
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserReportExtendDto.java
  66. 9 9
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/UserCourseAppointmentDto.java
  67. 1 1
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/AdListDto.java
  68. 0 122
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CommentDto.java
  69. 29 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/CommentInfoDto.java
  70. 29 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/FaqInfoDto.java
  71. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskCourseListDto.java
  72. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskQuestionDetailDto.java
  73. 20 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskQuestionListDto.java
  74. 7 130
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseAppointmentInfoDto.java
  75. 66 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseProgressInfoDto.java
  76. 20 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserCourseStudentRecordInfoDto.java
  77. 0 51
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserPreviewListDto.java
  78. 9 9
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorDto.java
  79. 50 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserExaminationPaperDto.java
  80. 38 3
      server/gateway-api/src/main/java/com/qxgmat/service/UserPaperService.java
  81. 13 5
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java
  82. 2 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  83. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/PreviewService.java
  84. 16 4
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  85. 22 28
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CommentService.java
  86. 28 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/ExaminationPaperService.java
  87. 22 28
      server/gateway-api/src/main/java/com/qxgmat/service/inline/FaqService.java
  88. 17 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/PreviewAssignService.java
  89. 2 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java
  90. 40 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseRecordService.java
  91. 2 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserFeedbackErrorService.java
  92. 8 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java
  93. 2 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java

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


+ 40 - 32
front/project/admin/routes/course/experienceDetail/page.js

@@ -100,41 +100,49 @@ export default class extends Page {
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='作者信息'>
           <Row>
-            <Col span={6}>
-              {getFieldDecorator('prepareStatus', {
-                rules: [{
-                  required: true, message: '请选择',
-                }],
-              })(
-                <Select select={PrepareStatus} placeholder='身份' />,
-              )}
+            <Col span={12}>
+              <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 14 }} label='身份'>
+                {getFieldDecorator('prepareStatus', {
+                  rules: [{
+                    required: true, message: '请选择',
+                  }],
+                })(
+                  <Select select={PrepareStatus} placeholder='身份' />,
+                )}
+              </Form.Item>
             </Col>
-            <Col span={6}>
-              {getFieldDecorator('experienceDay', {
-                rules: [{
-                  required: true, message: '请输入备考天数',
-                }],
-              })(
-                <InputNumber placeholder='备考周期: 天' />,
-              )}
+            <Col span={12}>
+              <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 14 }} label='备考周期'>
+                {getFieldDecorator('experienceDay', {
+                  rules: [{
+                    required: true, message: '请输入备考天数',
+                  }],
+                })(
+                  <InputNumber placeholder='备考周期: 天' />,
+                )}
+              </Form.Item>
             </Col>
-            <Col span={6}>
-              {getFieldDecorator('experienceScore', {
-                rules: [{
-                  required: true, message: '请选择',
-                }],
-              })(
-                <Select select={ExperienceScore} placeholder='分手成绩' />,
-              )}
+            <Col span={12}>
+              <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 14 }} label='分手成绩'>
+                {getFieldDecorator('experienceScore', {
+                  rules: [{
+                    required: true, message: '请选择',
+                  }],
+                })(
+                  <Select select={ExperienceScore} placeholder='分手成绩' />,
+                )}
+              </Form.Item>
             </Col>
-            <Col span={6}>
-              {getFieldDecorator('experiencePercent', {
-                rules: [{
-                  required: true, message: '请选择',
-                }],
-              })(
-                <Select select={ExperiencePercent} placeholder='提分范围' />,
-              )}
+            <Col span={12}>
+              <Form.Item labelCol={{ span: 8 }} wrapperCol={{ span: 14 }} label='提分范围'>
+                {getFieldDecorator('experiencePercent', {
+                  rules: [{
+                    required: true, message: '请选择',
+                  }],
+                })(
+                  <Select select={ExperiencePercent} placeholder='提分范围' />,
+                )}
+              </Form.Item>
             </Col>
           </Row>
         </Form.Item>

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

@@ -143,7 +143,7 @@ export default class extends Page {
       title: '学员名称',
       dataIndex: 'user.nickname',
       render: (text, record) => {
-        return `${text}(${record.mobile})`;
+        return `${text}(${record.user.mobile})`;
       },
     }, {
       title: '课时数',
@@ -293,7 +293,7 @@ export default class extends Page {
   addVsStudentAction() {
     const { id } = this.params;
     const { data } = this.state;
-    this.vsAddList[4].type = data.vsType === 'novice' ? 'hidden' : 'number';
+    this.vsAddList[3].type = data.vsType === 'novice' ? 'hidden' : 'number';
     asyncForm('添加', this.vsAddList, {}, info => {
       if (data.vsType === 'novice') {
         // 写死:新手每次1课时

+ 42 - 19
front/project/admin/routes/interaction/askQuestion/page.js

@@ -6,15 +6,16 @@ import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { getMap, bindSearch, formatDate, formatSeconds } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget } from '../../../../Constant';
+import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget, AskModule } from '../../../../Constant';
 import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
 
 const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 const AskStatusMap = getMap(AskStatus, 'value', 'label');
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
+const AskModuleMap = getMap(AskModule, 'value', 'label');
 export default class extends Page {
   init() {
     this.actionList = [{
@@ -24,6 +25,13 @@ export default class extends Page {
       needSelect: 1,
     }];
     this.filterForm = [{
+      key: 'askModule',
+      type: 'select',
+      allowClear: true,
+      name: '板块',
+      select: AskModule,
+      placeholder: '请选择',
+    }, {
       key: 'questionType',
       type: 'select',
       allowClear: true,
@@ -38,7 +46,7 @@ export default class extends Page {
       select: AskStatus,
       number: true,
     }, {
-      key: 'money',
+      key: 'moneyRang',
       type: 'select',
       allowClear: true,
       name: '消费金额',
@@ -75,34 +83,43 @@ export default class extends Page {
       placeholder: '请输入',
     }];
     this.columns = [{
+      title: '板块',
+      dataIndex: 'askModule',
+      render: (text) => {
+        return AskModuleMap[text];
+      },
+    }, {
       title: '题型',
       dataIndex: 'type',
       render: (text, record) => {
-        return QuestionTypeMap[record.question.type];
+        return QuestionTypeMap[record.question.questionType];
       },
-    },
-    {
+    }, {
       title: '题目id',
       dataIndex: 'questionNo.no',
-    },
-    {
+    }, {
+      title: '提问者',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '消费金额',
+      dataIndex: 'user.totalMoney',
+    }, {
       title: '提问时间',
       dataIndex: 'createTime',
       render: (text) => {
         return formatDate(text);
       },
-    },
-    {
-      title: '提问摘要',
-      dataIndex: 'content',
     }, {
-      title: '提问者',
-      dataIndex: 'user.nickname',
-    }, {
-      title: '回答状态',
-      dataIndex: 'answerStatus',
-      render: (text) => {
-        return AskStatusMap[text] || text;
+      title: '倒计时',
+      dataIndex: 'askTime',
+      render: (text, record) => {
+        const end = new Date(record.answerTime) || new Date();
+        const cost = (end.getTime() - new Date(record.createTime).getTime()) / 1000;
+        if (text) {
+          if (text - cost > 0) return `${formatSeconds(text - cost)}/${formatSeconds(text)}`;
+          return `0/${formatSeconds(text)}`;
+        }
+        return '-';
       },
     }, {
       title: '回答者',
@@ -114,6 +131,12 @@ export default class extends Page {
         return text ? formatDate(text) : '';
       },
     }, {
+      title: '回答状态',
+      dataIndex: 'answerStatus',
+      render: (text) => {
+        return AskStatusMap[text] || text;
+      },
+    }, {
       title: '展示状态',
       dataIndex: 'showStatus',
       render: (text) => {

+ 5 - 1
front/project/admin/routes/interaction/askQuestionDetail/page.js

@@ -8,12 +8,13 @@ import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
 import { formatFormError, formatDate, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { UserUrl, AskTarget, QuestionType } from '../../../../Constant';
+import { UserUrl, AskTarget, QuestionType, AskModule } from '../../../../Constant';
 // import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
 
 const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 const AskTargetMap = getMap(AskTarget, 'value', 'label');
+const AskModuleMap = getMap(AskModule, 'value', 'label');
 export default class extends Page {
   init() {
     // Exercise.allStruct().then(result => {
@@ -88,6 +89,9 @@ export default class extends Page {
     return <Block>
       <h1>题目信息</h1>
       <Form>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='板块'>
+          {AskModuleMap[data.askModule]}
+        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
           {QuestionTypeMap[question.type]}
         </Form.Item>

+ 98 - 135
front/project/admin/routes/interaction/comment/page.js

@@ -3,91 +3,44 @@ import './index.less';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
-import ActionLayout from '@src/layouts/ActionLayout';
+// import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { getMap, bindSearch, formatDate, formatTreeData } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
-import { ChannelModule, SwitchSelect } from '../../../../Constant';
+import { CommentChannel, SwitchSelect, MoneyRange } from '../../../../Constant';
 import { System } from '../../../stores/system';
 import { User } from '../../../stores/user';
+import { Course } from '../../../stores/course';
 
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
-const ChannelModuleMap = getMap(ChannelModule, 'value', 'label');
+const CommentChannelMap = getMap(CommentChannel, 'value', 'label');
 export default class extends Page {
   init() {
-    this.actionList = [{
-      key: 'add',
-      type: 'primary',
-      name: '创建',
-    }];
     this.itemList = [{
       key: 'id',
       type: 'hidden',
     }, {
-      key: 'channel',
-      type: 'select',
-      allowClear: true,
-      name: '频道',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'position',
-      type: 'select',
-      allowClear: true,
-      name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'nickname',
-      type: 'input',
-      name: '学员昵称',
-    }, {
-      key: 'avatar',
-      type: 'image',
-      name: '学员头像',
-      onUpload: ({ file }) => {
-        return System.uploadImage(file).then(result => { return result; });
-      },
-    }, {
-      key: 'content',
-      type: 'textarea',
-      name: '评价内容',
-    }];
-    this.userItemList = [{
-      key: 'id',
-      type: 'hidden',
-    }, {
-      key: 'channel',
-      type: 'select',
-      allowClear: true,
-      name: '频道',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'position',
-      type: 'select',
-      allowClear: true,
-      name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
       key: 'content',
       type: 'textarea',
       name: '评价内容',
     }];
+    this.filterF = null;
     this.filterForm = [{
       key: 'channel',
-      type: 'select',
+      type: 'cascader',
       allowClear: true,
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(CommentChannel.filter(row => row.type !== 'manual'), 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.filterForm, this, value.join('-'), null);
+      },
     }, {
       key: 'position',
       type: 'select',
       allowClear: true,
       name: '位置',
-      select: ChannelModule,
+      select: [],
       placeholder: '请选择',
     }, {
       key: 'userId',
@@ -98,74 +51,73 @@ export default class extends Page {
       number: true,
       placeholder: '请输入',
     }, {
+      key: 'moneyRang',
+      type: 'select',
+      allowClear: true,
+      name: '消费金额',
+      select: MoneyRange,
+      number: true,
+    }, {
       key: 'isSpecial',
       type: 'select',
       allowClear: true,
-      name: '精选',
+      name: '展示',
       number: true,
       select: SwitchSelect,
     }];
-    this.columns = [
-      {
-        title: '频道',
-        dataIndex: 'channel',
-        render: (text, record) => {
-          return ChannelModuleMap[record.channel];
-        },
+    this.columns = [{
+      title: '频道',
+      dataIndex: 'channel',
+      render: (text, record) => {
+        return CommentChannelMap[record.channel];
       },
-      {
-        title: '位置',
-        dataIndex: 'position',
+    }, {
+      title: '位置',
+      dataIndex: 'position',
+    }, {
+      title: '用户',
+      dataIndex: 'user',
+      render: (text, record) => {
+        let extend = '';
+        if (record.isSystem) extend = '系统创建';
+        else if (!record.userId) extend = '未注册';
+        return `${text.nickname || record.nickname}${extend ? `(${extend})` : ''}`;
       },
-      {
-        title: '内容',
-        dataIndex: 'content',
+    }, {
+      title: '时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
       },
-      {
-        title: '用户',
-        dataIndex: 'user',
-        render: (text, record) => {
-          let extend = '';
-          if (record.isSystem) extend = '系统创建';
-          else if (!record.userId) extend = '未注册';
-          return `${text.nickname || record.nickname}${extend ? `(${extend})` : ''}`;
-        },
-      }, {
-        title: '时间',
-        dataIndex: 'createTime',
-        render: (text) => {
-          return formatDate(text);
-        },
-      }, {
-        title: '精选',
-        dataIndex: 'isSpecial',
-        render: (text) => {
-          return SwitchSelectMap[text] || text;
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {(
-              <a onClick={() => {
-                this.editAction(record);
-              }}>编辑</a>
-            )}
-            {!!record.isSpecial && (
-              <a onClick={() => {
-                this.special(record, 0);
-              }}>取消精选</a>
-            )}
-            {!record.isSpecial && (
-              <a onClick={() => {
-                this.special(record, 1);
-              }}>精选</a>
-            )}
-          </div>;
-        },
+    }, {
+      title: '展示',
+      dataIndex: 'isSpecial',
+      render: (text) => {
+        return SwitchSelectMap[text] || text;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <a onClick={() => {
+              this.editAction(record);
+            }}>编辑</a>
+          )}
+          {!!record.isSpecial && (
+            <a onClick={() => {
+              this.special(record, 0);
+            }}>取消展示</a>
+          )}
+          {!record.isSpecial && (
+            <a onClick={() => {
+              this.special(record, 1);
+            }}>展示</a>
+          )}
+        </div>;
       },
-    ];
+    }];
     bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);
     }, (row) => {
@@ -174,6 +126,29 @@ export default class extends Page {
         value: row.id,
       };
     }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
+    this.changeSearch(this.filterForm, this, this.state.search.channel, this.state.search.position);
+    this.state.search.channel = this.state.search.channel ? this.state.search.channel.split('-') : '';
+  }
+
+  changeSearch(list, component, key, value) {
+    if (key === 'course-video' || key === 'course-vs' || key === 'course_data') {
+      bindSearch(list, 'position', component, (search) => {
+        if (key === 'course-video') {
+          return Course.list(Object.assign({ courseModule: 'video' }, search));
+        } if (key === 'course-vs') {
+          return Course.list(Object.assign({ courseModule: 'vs' }, search));
+        }
+        return Course.listData(search);
+      }, (row) => {
+        return {
+          title: row.title,
+          value: row.id,
+        };
+      }, value ? Number(value) : null, null);
+      list[1].disabled = false;
+    } else {
+      list[1].disabled = true;
+    }
   }
 
   initData() {
@@ -182,21 +157,8 @@ export default class extends Page {
     });
   }
 
-  addAction() {
-    asyncForm('创建评价', this.itemList, {}, data => {
-      return System.addComment(data).then(() => {
-        asyncSMessage('添加成功!');
-        this.refresh();
-      });
-    });
-  }
-
   editAction(row) {
-    let item = this.itemList;
-    if (row.userId) {
-      item = this.userItemList;
-    }
-    asyncForm('编辑', item, row, data => {
+    asyncForm('编辑', this.itemList, row, data => {
       return System.editComment(data).then(() => {
         asyncSMessage('编辑成功!');
         this.refresh();
@@ -205,7 +167,7 @@ export default class extends Page {
   }
 
   special(row, isSpecial) {
-    System.editComment({ id: row.id, isSpecial }).then(() => {
+    System.editComment({ id: row.id, isSpecial, isShow: isSpecial }).then(() => {
       asyncSMessage('操作成功!');
       this.refresh();
     });
@@ -215,18 +177,19 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {
+          data.channel = data.channel.join('-');
           this.search(data);
         }} />
-      <ActionLayout
+      {/* <ActionLayout
         itemList={this.actionList}
         selectedKeys={this.state.selectedKeys}
         onAction={key => this.onAction(key)}
-      />
+      /> */}
       <TableLayout
-        select
         columns={this.tableSort(this.columns)}
         list={this.state.list}
         pagination={this.state.page}

+ 83 - 52
front/project/admin/routes/interaction/faq/page.js

@@ -3,15 +3,17 @@ import './index.less';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
-import ActionLayout from '@src/layouts/ActionLayout';
+// import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, formatDate } from '@src/services/Tools';
+import { getMap, formatDate, formatTreeData, bindSearch } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
-import { ChannelModule, SwitchSelect, AskStatus } from '../../../../Constant';
+import { FaqChannel, SwitchSelect, AskStatus, MoneyRange } from '../../../../Constant';
 import { System } from '../../../stores/system';
+import { User } from '../../../stores/user';
+import { Course } from '../../../stores/course';
 
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
-const ChannelModuleMap = getMap(ChannelModule, 'value', 'label');
+const FaqChannelMap = getMap(FaqChannel, 'value', 'label');
 const AskStatusMap = getMap(AskStatus, 'value', 'label');
 export default class extends Page {
   init() {
@@ -20,20 +22,6 @@ export default class extends Page {
       key: 'id',
       type: 'hidden',
     }, {
-      key: 'channel',
-      type: 'select',
-      allowClear: true,
-      name: '频道',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'position',
-      type: 'select',
-      allowClear: true,
-      name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
       key: 'content',
       type: 'textarea',
       name: '用户留言',
@@ -55,19 +43,24 @@ export default class extends Page {
       type: 'textarea',
       name: '编辑回复',
     }];
+    this.filterF = null;
     this.filterForm = [{
       key: 'channel',
-      type: 'select',
+      type: 'cascader',
       allowClear: true,
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(FaqChannel, 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.filterForm, this, value.join('-'), null);
+      },
     }, {
       key: 'position',
       type: 'select',
       allowClear: true,
       name: '位置',
-      select: ChannelModule,
+      select: [],
+      number: true,
       placeholder: '请选择',
     }, {
       key: 'answerStatus',
@@ -77,10 +70,25 @@ export default class extends Page {
       name: '状态',
       select: AskStatus,
     }, {
+      key: 'userId',
+      type: 'select',
+      allowClear: true,
+      name: '用户',
+      select: [],
+      number: true,
+      placeholder: '请输入',
+    }, {
+      key: 'moneyRang',
+      type: 'select',
+      allowClear: true,
+      name: '消费金额',
+      select: MoneyRange,
+      number: true,
+    }, {
       key: 'isSpecial',
       type: 'select',
       allowClear: true,
-      name: '精选',
+      name: '展示',
       number: true,
       select: SwitchSelect,
     }];
@@ -88,28 +96,24 @@ export default class extends Page {
       title: '频道',
       dataIndex: 'channel',
       render: (text, record) => {
-        return ChannelModuleMap[record.channel];
+        return FaqChannelMap[record.channel];
       },
     }, {
       title: '位置',
-      dataIndex: 'position',
+      dataIndex: 'positionDetail.title',
     }, {
       title: '提问时间',
+      sorter: true,
       dataIndex: 'createTime',
       render: (text) => {
         return formatDate(text);
       },
     }, {
       title: '提问者',
-      dataIndex: 'user',
-      render: (text, record) => {
-        if (record.isSystem) return '系统创建';
-        if (!record.userId) return '未注册';
-        return text ? text.nickname : '';
-      },
+      dataIndex: 'user.nickname',
     }, {
-      title: '问题摘要',
-      dataIndex: 'content',
+      title: '消费金额',
+      dataIndex: 'user.totalMoney',
     }, {
       title: '回答状态',
       dataIndex: 'answerStatus',
@@ -117,10 +121,17 @@ export default class extends Page {
         return AskStatusMap[text] || '';
       },
     }, {
-      title: '精选',
+      title: '回答时间',
+      sorter: true,
+      dataIndex: 'answerTime',
+      render: (text) => {
+        return text ? formatDate(text) : '';
+      },
+    }, {
+      title: '展示',
       dataIndex: 'isSpecial',
-      render: (text, record) => {
-        return record.status > 0 ? SwitchSelectMap[text] || text : '-';
+      render: (text) => {
+        return SwitchSelectMap[text] || text;
       },
     }, {
       title: '操作',
@@ -132,7 +143,7 @@ export default class extends Page {
               this.editAction(record);
             }}>编辑</a>
           )}
-          {!record.isSystem && record.status === 0 && (
+          {record.answerStatus === 0 && (
             <a onClick={() => {
               this.answerAction(record);
             }}>回复</a>
@@ -140,16 +151,45 @@ export default class extends Page {
           {!!record.isSpecial && (
             <a onClick={() => {
               this.special(record, 0);
-            }}>取消精选</a>
+            }}>取消展示</a>
           )}
           {!record.isSpecial && (
             <a onClick={() => {
               this.special(record, 1);
-            }}>精选</a>
+            }}>展示</a>
           )}
         </div>;
       },
     }];
+    bindSearch(this.filterForm, 'userId', this, (search) => {
+      return User.list(search);
+    }, (row) => {
+      return {
+        title: `${row.nickname}(${row.mobile})`,
+        value: row.id,
+      };
+    }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
+    this.changeSearch(this.filterForm, this, this.state.search.channel, this.state.search.position);
+    this.state.search.channel = this.state.search.channel ? this.state.search.channel.split('-') : '';
+  }
+
+  changeSearch(list, component, key, value) {
+    if (key === 'course-video' || key === 'course_data') {
+      bindSearch(list, 'position', component, (search) => {
+        if (key === 'course-video') {
+          return Course.list(Object.assign({ courseModule: 'video' }, search));
+        }
+        return Course.listData(search);
+      }, (row) => {
+        return {
+          title: row.title,
+          value: row.id,
+        };
+      }, value ? Number(value) : null, null);
+      list[1].disabled = false;
+    } else {
+      list[1].disabled = true;
+    }
   }
 
   initData() {
@@ -158,17 +198,6 @@ export default class extends Page {
     });
   }
 
-  addAction() {
-    asyncForm('创建', this.itemList, {}, data => {
-      return System.addFAQ(data).then(() => {
-        asyncSMessage('添加成功!');
-        this.refresh();
-      });
-    }).then(component => {
-      this.formF = component;
-    });
-  }
-
   editAction(row) {
     asyncForm('编辑', this.itemList, row, data => {
       return System.editFAQ(data).then(() => {
@@ -193,7 +222,7 @@ export default class extends Page {
   }
 
   special(row, isSpecial) {
-    System.editFAQ({ id: row.id, isSpecial }).then(() => {
+    System.editFAQ({ id: row.id, isSpecial, isShow: isSpecial }).then(() => {
       asyncSMessage('编辑成功!');
       this.refresh();
     });
@@ -203,16 +232,18 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {
+          data.channel = data.channel.join('-');
           this.search(data);
         }} />
-      <ActionLayout
+      {/* <ActionLayout
         itemList={this.actionList}
         selectedKeys={this.state.selectedKeys}
         onAction={key => this.onAction(key)}
-      />
+      /> */}
       <TableLayout
         columns={this.tableSort(this.columns)}
         list={this.state.list}

+ 120 - 43
front/project/admin/routes/interaction/feedback/page.js

@@ -9,11 +9,14 @@ import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { getMap, formatDate, bindSearch } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { FeedbackStatus, FeedbackModule, MoneyRange, AskTarget } from '../../../../Constant';
+import { FeedbackStatus, FeedbackModule, MoneyRange, AskTarget, FeedbackQuestionType } from '../../../../Constant';
 import { User } from '../../../stores/user';
+import { Question } from '../../../stores/question';
+import { Course } from '../../../stores/course';
 
 const FeedbackStatusMap = getMap(FeedbackStatus, 'value', 'label');
 const FeedbackModuleMap = getMap(FeedbackModule, 'value', 'label');
+const FeedbackQuestionTypeMap = getMap(FeedbackQuestionType, 'value', 'label');
 const AskTargetMap = getMap(AskTarget, 'value', 'label');
 export default class extends Page {
   init() {
@@ -33,6 +36,7 @@ export default class extends Page {
       name: '批量忽略',
       needSelect: 1,
     }];
+    this.filterF = null;
     this.filterForm = [{
       key: 'module',
       type: 'select',
@@ -40,6 +44,35 @@ export default class extends Page {
       name: '类型',
       select: FeedbackModule,
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.filterForm, this, value, null);
+        this.filterF.setFieldsValue({ questionType: null, keyword: null, target: null, moduleId: null });
+      },
+    }, {
+      key: 'questionType',
+      type: 'select',
+      allowClear: true,
+      name: '单项',
+      select: FeedbackQuestionType,
+    }, {
+      key: 'keyword',
+      type: 'input',
+      allowClear: true,
+      name: '题目id',
+      placeholder: '题目ID',
+    }, {
+      key: 'target',
+      type: 'select',
+      allowClear: true,
+      name: '勘误区域',
+      select: AskTarget,
+    }, {
+      key: 'moduleId',
+      type: 'select',
+      allowClear: true,
+      name: '资料',
+      select: [],
+      placeholder: '资料',
     }, {
       key: 'status',
       type: 'select',
@@ -56,7 +89,7 @@ export default class extends Page {
       number: true,
       placeholder: '请输入',
     }, {
-      key: 'money',
+      key: 'moneyRang',
       type: 'select',
       allowClear: true,
       name: '消费金额',
@@ -68,52 +101,58 @@ export default class extends Page {
       allowClear: true,
       name: '勘误名称',
     }];
-    this.columns = [
-      {
-        title: '类型',
-        dataIndex: 'module',
-        render: (text) => {
-          return FeedbackModuleMap[text];
-        },
+    this.columns = [{
+      title: '类型',
+      dataIndex: 'module',
+      render: (text) => {
+        return FeedbackModuleMap[text];
       },
-      {
-        title: '提交时间',
-        dataIndex: 'createTime',
-        render: (text) => {
-          return text ? formatDate(text) : '-';
-        },
+    }, {
+      title: '学科单项',
+      dataIndex: 'questionType',
+      render: (text) => {
+        return FeedbackQuestionTypeMap[text];
       },
-      {
-        title: '提交人',
-        dataIndex: 'user.nickname',
+    }, {
+      title: '对象',
+      dataIndex: 'title',
+    }, {
+      title: '勘误区域',
+      dataIndex: 'target',
+      render: (text) => {
+        return AskTargetMap[text] || '';
       },
-      {
-        title: '消费金额',
-        dataIndex: 'user.totalMoney',
+    }, {
+      title: '提交时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return text ? formatDate(text) : '-';
       },
-      {
-        title: '勘误对象',
-        dataIndex: 'title',
-      }, {
-        title: '处理状态',
-        dataIndex: 'status',
-        render: (text) => {
-          return FeedbackStatusMap[text] || text;
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {(
-              <a onClick={() => {
-                this.detailAction(record);
-              }}>查看</a>
-            )}
-          </div>;
-        },
+    }, {
+      title: '用户',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '消费金额',
+      dataIndex: 'user.totalMoney',
+    }, {
+      title: '处理状态',
+      dataIndex: 'status',
+      render: (text) => {
+        return FeedbackStatusMap[text] || text;
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <a onClick={() => {
+              this.detailAction(record);
+            }}>查看</a>
+          )}
+        </div>;
       },
-    ];
+    }];
     bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);
     }, (row) => {
@@ -122,6 +161,43 @@ export default class extends Page {
         value: row.id,
       };
     }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
+    this.changeSearch(this.filterForm, this, this.state.search.module, this.state.search.moduleId);
+  }
+
+  changeSearch(list, component, key, value) {
+    if (key === 'data') {
+      bindSearch(list, 'moduleId', component, (search) => {
+        if (key === 'question') {
+          return Question.listNo(search);
+        }
+        return Course.listData(search);
+      }, (row) => {
+        if (key === 'question') {
+          return {
+            title: row.title,
+            value: row.questionId,
+          };
+        }
+        return {
+          title: row.title,
+          value: row.id,
+        };
+      }, value ? Number(value) : null, null);
+      list[1].disabled = true;
+      list[2].disabled = true;
+      list[3].disabled = true;
+      list[4].disabled = false;
+    } else if (key === 'question') {
+      list[1].disabled = false;
+      list[2].disabled = false;
+      list[3].disabled = false;
+      list[4].disabled = true;
+    } else {
+      list[1].disabled = true;
+      list[2].disabled = true;
+      list[3].disabled = true;
+      list[4].disabled = true;
+    }
   }
 
   initData() {
@@ -205,6 +281,7 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {

+ 88 - 104
front/project/admin/routes/show/comment/page.js

@@ -5,14 +5,14 @@ import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { getMap, formatDate, bindSearch, formatTreeData } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
-import { ChannelModule, SwitchSelect } from '../../../../Constant';
+import { CommentChannel, SystemSelect } from '../../../../Constant';
 import { System } from '../../../stores/system';
-import { User } from '../../../stores/user';
+import { Course } from '../../../stores/course';
 
-const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
-const ChannelModuleMap = getMap(ChannelModule, 'value', 'label');
+const CommentChannelMap = getMap(CommentChannel, 'value', 'label');
+const SystemSelectMap = getMap(SystemSelect, 'value', 'label');
 export default class extends Page {
   init() {
     this.actionList = [{
@@ -20,22 +20,26 @@ export default class extends Page {
       type: 'primary',
       name: '创建',
     }];
+    this.formF = null;
     this.itemList = [{
       key: 'id',
       type: 'hidden',
     }, {
       key: 'channel',
-      type: 'select',
+      type: 'cascader',
       allowClear: true,
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(CommentChannel, 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.itemList, this.formF, value.join('-'), null, 2);
+      },
     }, {
       key: 'position',
       type: 'select',
       allowClear: true,
       name: '位置',
-      select: ChannelModule,
+      select: [],
       placeholder: '请选择',
     }, {
       key: 'nickname',
@@ -57,123 +61,94 @@ export default class extends Page {
       key: 'id',
       type: 'hidden',
     }, {
-      key: 'channel',
-      type: 'select',
-      allowClear: true,
-      name: '频道',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'position',
-      type: 'select',
-      allowClear: true,
-      name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
       key: 'content',
       type: 'textarea',
       name: '评价内容',
     }];
+    this.filterF = null;
     this.filterForm = [{
       key: 'channel',
-      type: 'select',
+      type: 'cascader',
       allowClear: true,
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(CommentChannel, 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.filterForm, this, value.join('-'), null);
+      },
     }, {
       key: 'position',
       type: 'select',
       allowClear: true,
       name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'userId',
-      type: 'select',
-      allowClear: true,
-      name: '用户',
       select: [],
-      number: true,
-      placeholder: '请输入',
+      placeholder: '请选择',
     }, {
-      key: 'isSpecial',
+      key: 'isSystem',
       type: 'select',
       allowClear: true,
-      name: '精选',
       number: true,
-      select: SwitchSelect,
+      name: '来源',
+      select: SystemSelect,
     }];
-    this.columns = [
-      {
-        title: '频道',
-        dataIndex: 'channel',
-        render: (text, record) => {
-          return ChannelModuleMap[record.channel];
-        },
+    this.columns = [{
+      title: '频道',
+      dataIndex: 'channel',
+      render: (text, record) => {
+        return CommentChannelMap[record.channel];
       },
-      {
-        title: '位置',
-        dataIndex: 'position',
+    }, {
+      title: '商品名称',
+      dataIndex: 'positionDetail.title',
+    }, {
+      title: '创建时间',
+      sorter: true,
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
       },
-      {
-        title: '内容',
-        dataIndex: 'content',
+    }, {
+      title: '来源',
+      dataIndex: 'isSystem',
+      render: (text) => {
+        return SystemSelectMap[text];
       },
-      {
-        title: '用户',
-        dataIndex: 'user',
-        render: (text, record) => {
-          let extend = '';
-          if (record.isSystem) extend = '系统创建';
-          else if (!record.userId) extend = '未注册';
-          return `${text.nickname || record.nickname}${extend ? `(${extend})` : ''}`;
-        },
-      }, {
-        title: '时间',
-        dataIndex: 'createTime',
-        render: (text) => {
-          return formatDate(text);
-        },
-      }, {
-        title: '精选',
-        dataIndex: 'isSpecial',
-        render: (text) => {
-          return SwitchSelectMap[text] || text;
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {(
-              <a onClick={() => {
-                this.editAction(record);
-              }}>编辑</a>
-            )}
-            {!!record.isSpecial && (
-              <a onClick={() => {
-                this.special(record, 0);
-              }}>取消精选</a>
-            )}
-            {!record.isSpecial && (
-              <a onClick={() => {
-                this.special(record, 1);
-              }}>精选</a>
-            )}
-          </div>;
-        },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {(
+            <a onClick={() => {
+              this.editAction(record);
+            }}>编辑</a>
+          )}
+        </div>;
       },
-    ];
-    bindSearch(this.filterForm, 'userId', this, (search) => {
-      return User.list(search);
-    }, (row) => {
-      return {
-        title: `${row.nickname}(${row.mobile})`,
-        value: row.id,
-      };
-    }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
+    }];
+    this.changeSearch(this.filterForm, this, this.state.search.channel, this.state.search.position);
+    this.state.search.channel = this.state.search.channel ? this.state.search.channel.split('-') : '';
+  }
+
+  changeSearch(list, component, key, value, index = 1) {
+    if (key === 'course-video' || key === 'course-vs' || key === 'course_data') {
+      bindSearch(list, 'position', component, (search) => {
+        if (key === 'course-video') {
+          return Course.list(Object.assign({ courseModule: 'video' }, search));
+        } if (key === 'course-vs') {
+          return Course.list(Object.assign({ courseModule: 'vs' }, search));
+        }
+        return Course.listData(search);
+      }, (row) => {
+        return {
+          title: row.title,
+          value: row.id,
+        };
+      }, value ? Number(value) : null, null);
+      list[index].disabled = false;
+    } else {
+      list[index].disabled = true;
+    }
   }
 
   initData() {
@@ -184,10 +159,15 @@ export default class extends Page {
 
   addAction() {
     asyncForm('创建评价', this.itemList, {}, data => {
+      data.isShow = 1;
+      data.isSystem = 1;
+      data.isSpecial = 1;
       return System.addComment(data).then(() => {
         asyncSMessage('添加成功!');
         this.refresh();
       });
+    }).then(component => {
+      this.formF = component;
     });
   }
 
@@ -201,11 +181,14 @@ export default class extends Page {
         asyncSMessage('编辑成功!');
         this.refresh();
       });
+    }).then(component => {
+      this.formF = component;
+      this.changeSearch(this.filterForm, this, row.channel, row.position, 2);
     });
   }
 
-  special(row, isSpecial) {
-    System.editComment({ id: row.id, isSpecial }).then(() => {
+  special(row, isShow) {
+    System.editComment({ id: row.id, isShow }).then(() => {
       asyncSMessage('操作成功!');
       this.refresh();
     });
@@ -215,9 +198,11 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {
+          data.channel = data.channel.join('-');
           this.search(data);
         }} />
       <ActionLayout
@@ -226,7 +211,6 @@ export default class extends Page {
         onAction={key => this.onAction(key)}
       />
       <TableLayout
-        select
         columns={this.tableSort(this.columns)}
         list={this.state.list}
         pagination={this.state.page}

+ 54 - 336
front/project/admin/routes/show/deploy/page.js

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

+ 64 - 44
front/project/admin/routes/show/faq/page.js

@@ -5,13 +5,14 @@ import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap } from '@src/services/Tools';
+import { getMap, formatDate, bindSearch, formatTreeData } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
-import { ChannelModule, SwitchSelect, AskStatus } from '../../../../Constant';
+import { FaqChannel, SystemSelect } from '../../../../Constant';
 import { System } from '../../../stores/system';
+import { Course } from '../../../stores/course';
 
-const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
-const ChannelModuleMap = getMap(ChannelModule, 'value', 'label');
+const FaqChannelMap = getMap(FaqChannel, 'value', 'label');
+const SystemSelectMap = getMap(SystemSelect, 'value', 'label');
 export default class extends Page {
   init() {
     this.actionList = [{
@@ -25,17 +26,18 @@ export default class extends Page {
       type: 'hidden',
     }, {
       key: 'channel',
-      type: 'select',
-      allowClear: true,
+      type: 'cascader',
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(FaqChannel, 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.itemList, this.formF, value.join('-'), null, 2);
+      },
     }, {
       key: 'position',
       type: 'select',
-      allowClear: true,
       name: '位置',
-      select: ChannelModule,
+      select: [],
       placeholder: '请选择',
     }, {
       key: 'content',
@@ -46,52 +48,54 @@ export default class extends Page {
       type: 'textarea',
       name: '编辑回复',
     }];
+    this.filterF = null;
     this.filterForm = [{
       key: 'channel',
-      type: 'select',
+      type: 'cascader',
       allowClear: true,
       name: '频道',
-      select: ChannelModule,
+      select: formatTreeData(FaqChannel, 'value', 'label', 'parent'),
       placeholder: '请选择',
+      onChange: (value) => {
+        this.changeSearch(this.filterForm, this, value.join('-'), null);
+      },
     }, {
       key: 'position',
       type: 'select',
       allowClear: true,
       name: '位置',
-      select: ChannelModule,
-      placeholder: '请选择',
-    }, {
-      key: 'answerStatus',
-      type: 'select',
-      allowClear: true,
       number: true,
-      name: '状态',
-      select: AskStatus,
+      select: [],
+      placeholder: '请选择',
     }, {
-      key: 'isSpecial',
+      key: 'isSystem',
       type: 'select',
       allowClear: true,
-      name: '精选',
       number: true,
-      select: SwitchSelect,
+      name: '来源',
+      select: SystemSelect,
     }];
     this.columns = [{
       title: '频道',
       dataIndex: 'channel',
       render: (text, record) => {
-        return ChannelModuleMap[record.channel];
+        return FaqChannelMap[record.channel];
       },
     }, {
       title: '位置',
-      dataIndex: 'position',
+      dataIndex: 'positionDetail.title',
     }, {
-      title: '问题摘要',
-      dataIndex: 'content',
+      title: '创建时间',
+      sorter: true,
+      dataIndex: 'createTime',
+      render: (text) => {
+        return formatDate(text);
+      },
     }, {
-      title: '精选',
-      dataIndex: 'isSpecial',
-      render: (text, record) => {
-        return record.status > 0 ? SwitchSelectMap[text] || text : '-';
+      title: '来源',
+      dataIndex: 'isSystem',
+      render: (text) => {
+        return SystemSelectMap[text];
       },
     }, {
       title: '操作',
@@ -103,19 +107,31 @@ export default class extends Page {
               this.editAction(record);
             }}>编辑</a>
           )}
-          {!!record.isSpecial && (
-            <a onClick={() => {
-              this.special(record, 0);
-            }}>取消精选</a>
-          )}
-          {!record.isSpecial && (
-            <a onClick={() => {
-              this.special(record, 1);
-            }}>精选</a>
-          )}
         </div>;
       },
     }];
+
+    this.changeSearch(this.filterForm, this, this.state.search.channel, this.state.search.position);
+    this.state.search.channel = this.state.search.channel ? this.state.search.channel.split('-') : '';
+  }
+
+  changeSearch(list, component, key, value, index = 1) {
+    if (key === 'course-video' || key === 'course_data') {
+      bindSearch(list, 'position', component, (search) => {
+        if (key === 'course-video') {
+          return Course.list(Object.assign({ courseModule: 'video' }, search));
+        }
+        return Course.listData(search);
+      }, (row) => {
+        return {
+          title: row.title,
+          value: row.id,
+        };
+      }, value ? Number(value) : null, null);
+      list[index].disabled = false;
+    } else {
+      list[index].disabled = true;
+    }
   }
 
   initData() {
@@ -126,7 +142,9 @@ export default class extends Page {
 
   addAction() {
     asyncForm('创建', this.itemList, {}, data => {
-      data.faqModule = 'system';
+      data.isShow = 1;
+      data.isSystem = 1;
+      data.isSpecial = 1;
       return System.addFAQ(data).then(() => {
         asyncSMessage('添加成功!');
         this.refresh();
@@ -138,18 +156,18 @@ export default class extends Page {
 
   editAction(row) {
     asyncForm('编辑', this.itemList, row, data => {
-      data.faqModule = 'system';
       return System.editFAQ(data).then(() => {
         asyncSMessage('编辑成功!');
         this.refresh();
       });
     }).then(component => {
       this.formF = component;
+      this.changeSearch(this.filterForm, this, row.channel, row.position, 2);
     });
   }
 
-  special(row, isSpecial) {
-    System.editFAQ({ id: row.id, isSpecial }).then(() => {
+  show(row, isShow) {
+    System.editFAQ({ id: row.id, isShow }).then(() => {
       asyncSMessage('编辑成功!');
       this.refresh();
     });
@@ -159,9 +177,11 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {
+          data.channel = data.channel.join('-');
           this.search(data);
         }} />
       <ActionLayout

+ 24 - 18
front/project/admin/routes/student/askCourse/page.js

@@ -62,7 +62,7 @@ export default class extends Page {
       number: true,
       placeholder: '请输入',
     }, {
-      key: 'money',
+      key: 'moneyRang',
       type: 'select',
       allowClear: true,
       name: '消费金额',
@@ -75,26 +75,32 @@ export default class extends Page {
       render: (text, record) => {
         return `${record.course.parentStructId ? `${this.exerciseMap[record.course.parentStructId]}-` : ''}${this.exerciseMap[record.course.structId]}`;
       },
-    },
-    {
+    }, {
       title: '课程',
       dataIndex: 'course.title',
-    },
-    {
+    }, {
+      title: '课时',
+      dataIndex: 'courseNo.no',
+    }, {
       title: '位置',
       dataIndex: 'position',
-      render: (text, record) => {
-        return `P${record.courseNo.no}:${text}`;
+      render: (text) => {
+        return `${text}`;
       },
-    },
-    {
-      title: '提问摘要',
-      dataIndex: 'content',
     }, {
       title: '提问者',
       dataIndex: 'user.nickname',
     }, {
-      title: '承诺时间',
+      title: '消费金额',
+      dataIndex: 'user.totalMoney',
+    }, {
+      title: '提问时间',
+      dataIndex: 'createTime',
+      render: (text) => {
+        return text ? formatDate(text) : '';
+      },
+    }, {
+      title: '倒计时',
       dataIndex: 'askTime',
       render: (text, record) => {
         const end = new Date(record.answerTime) || new Date();
@@ -106,12 +112,6 @@ export default class extends Page {
         return '-';
       },
     }, {
-      title: '回答状态',
-      dataIndex: 'answerStatus',
-      render: (text) => {
-        return AskStatusMap[text] || text;
-      },
-    }, {
       title: '回答者',
       dataIndex: 'manager.username',
     }, {
@@ -121,6 +121,12 @@ export default class extends Page {
         return text ? formatDate(text) : '';
       },
     }, {
+      title: '回答状态',
+      dataIndex: 'answerStatus',
+      render: (text) => {
+        return AskStatusMap[text] || text;
+      },
+    }, {
       title: '展示状态',
       dataIndex: 'showStatus',
       render: (text) => {

+ 42 - 19
front/project/admin/routes/student/askQuestion/page.js

@@ -6,15 +6,16 @@ import Block from '@src/components/Block';
 import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { getMap, bindSearch, formatDate } from '@src/services/Tools';
+import { getMap, bindSearch, formatDate, formatSeconds } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget } from '../../../../Constant';
+import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget, AskModule } from '../../../../Constant';
 import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
 
 const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 const AskStatusMap = getMap(AskStatus, 'value', 'label');
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
+const AskModuleMap = getMap(AskModule, 'value', 'label');
 export default class extends Page {
   init() {
     this.actionList = [{
@@ -24,6 +25,13 @@ export default class extends Page {
       needSelect: 1,
     }];
     this.filterForm = [{
+      key: 'askModule',
+      type: 'select',
+      allowClear: true,
+      name: '板块',
+      select: AskModule,
+      placeholder: '请选择',
+    }, {
       key: 'questionType',
       type: 'select',
       allowClear: true,
@@ -38,7 +46,7 @@ export default class extends Page {
       select: AskStatus,
       number: true,
     }, {
-      key: 'money',
+      key: 'moneyRang',
       type: 'select',
       allowClear: true,
       name: '消费金额',
@@ -75,34 +83,43 @@ export default class extends Page {
       placeholder: '请输入',
     }];
     this.columns = [{
+      title: '板块',
+      dataIndex: 'askModule',
+      render: (text) => {
+        return AskModuleMap[text];
+      },
+    }, {
       title: '题型',
       dataIndex: 'type',
       render: (text, record) => {
-        return QuestionTypeMap[record.question.type];
+        return QuestionTypeMap[record.question.questionType];
       },
-    },
-    {
+    }, {
       title: '题目id',
       dataIndex: 'questionNo.no',
-    },
-    {
+    }, {
+      title: '提问者',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '消费金额',
+      dataIndex: 'user.totalMoney',
+    }, {
       title: '提问时间',
       dataIndex: 'createTime',
       render: (text) => {
         return formatDate(text);
       },
-    },
-    {
-      title: '提问摘要',
-      dataIndex: 'content',
     }, {
-      title: '提问者',
-      dataIndex: 'user.nickname',
-    }, {
-      title: '回答状态',
-      dataIndex: 'answerStatus',
-      render: (text) => {
-        return AskStatusMap[text] || text;
+      title: '倒计时',
+      dataIndex: 'askTime',
+      render: (text, record) => {
+        const end = new Date(record.answerTime) || new Date();
+        const cost = (end.getTime() - new Date(record.createTime).getTime()) / 1000;
+        if (text) {
+          if (text - cost > 0) return `${formatSeconds(text - cost)}/${formatSeconds(text)}`;
+          return `0/${formatSeconds(text)}`;
+        }
+        return '-';
       },
     }, {
       title: '回答者',
@@ -114,6 +131,12 @@ export default class extends Page {
         return text ? formatDate(text) : '';
       },
     }, {
+      title: '回答状态',
+      dataIndex: 'answerStatus',
+      render: (text) => {
+        return AskStatusMap[text] || text;
+      },
+    }, {
       title: '展示状态',
       dataIndex: 'showStatus',
       render: (text) => {

+ 6 - 2
front/project/admin/routes/student/askQuestionDetail/page.js

@@ -8,12 +8,13 @@ import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
 import { formatFormError, formatDate, getMap } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { UserUrl, AskTarget, QuestionType } from '../../../../Constant';
+import { UserUrl, AskTarget, QuestionType, AskModule } from '../../../../Constant';
 // import { User } from '../../../stores/user';
 import { Question } from '../../../stores/question';
 
 const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 const AskTargetMap = getMap(AskTarget, 'value', 'label');
+const AskModuleMap = getMap(AskModule, 'value', 'label');
 export default class extends Page {
   init() {
     // Exercise.allStruct().then(result => {
@@ -88,8 +89,11 @@ export default class extends Page {
     return <Block>
       <h1>题目信息</h1>
       <Form>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='板块'>
+          {AskModuleMap[data.askModule]}
+        </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
-          {QuestionTypeMap[question.type]}
+          {QuestionTypeMap[question.questionType]}
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目id'>
           <a href='' target='_blank'>{questionNo.no}</a>

+ 27 - 23
front/project/admin/routes/student/studyDetail/page.js

@@ -7,7 +7,7 @@ import Block from '@src/components/Block';
 // import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
-import { formatDate } from '@src/services/Tools';
+import { formatDate, formatSecond, formatPercent } from '@src/services/Tools';
 import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
 import { UserUrl } from '../../../../Constant';
 import { Course } from '../../../stores/course';
@@ -18,28 +18,33 @@ import { System } from '../../../stores/system';
 export default class extends Page {
   init() {
     this.videoColumns = [{
-      title: '时间段',
-      dataIndex: 'time',
-      render: (text) => {
-        return `${formatDate(text.startTime, 'YYYY-MM-DD')}~${formatDate(text.endTime, 'YYYY-MM-DD')}`;
-      },
+      title: '课时',
+      dataIndex: 'courseNo.no',
     }, {
-      title: '学员id',
-      dataIndex: 'userId',
+      title: '课时名称',
+      dataIndex: 'courseNo.title',
     }, {
-      title: '学员名称',
-      dataIndex: 'user.nickname',
+      title: '学习记录',
+      dataIndex: 'records',
+      render: (text) => {
+        return (text || []).map(row => {
+          return <p>{formatDate(row.createTime, 'YYYY-MM-DD HH:mm:ss')} {formatSecond(row.userTime)}</p>;
+        });
+      },
     }, {
-      title: '手机号',
-      dataIndex: 'user.mobile',
+      title: '预习作业进度',
+      dataIndex: 'userPaper',
+      render: (text, record) => {
+        return `${text.times}遍+${formatPercent(record.userReport.userNumber, record.userReport.questionNumber)}`;
+      },
     }, {
       title: '操作',
       dataIndex: 'handler',
       render: (text, record) => {
         return <div className="table-button">
           {<a onClick={() => {
-            this.deleteOnlineStudent(record);
-          }}>删除</a>}
+            User.locationUser(record.userId, `${UserUrl}/my/report`);
+          }}>查看</a>}
         </div>;
       },
     }];
@@ -61,7 +66,7 @@ export default class extends Page {
       showTime: true,
       name: '上课时间',
     }, {
-      key: 'channel',
+      key: 'cctalkChannel',
       type: 'input',
       name: '频道号',
     }];
@@ -85,7 +90,7 @@ export default class extends Page {
       dataIndex: 'title',
     }, {
       title: '频道号',
-      dataIndex: 'channel',
+      dataIndex: 'cctalkChannel',
     }, {
       title: '学习进度',
       dataIndex: 'isFinish',
@@ -136,8 +141,7 @@ export default class extends Page {
           return;
         }
         const { course } = row;
-        this.setState({ module: course.courseModule });
-        this.setState({ data: row });
+        this.setState({ data: row, module: course.courseModule });
         this.refresh();
       });
   }
@@ -159,15 +163,15 @@ export default class extends Page {
   }
 
   refreshVideo() {
-    // const { id } = this.params;
-    // Course.listStudentOnline(Object.assign({ courseId: id }, this.state.search)).then(result => {
-    //   this.setTableData(result.list, result.total);
-    // });
+    const { id } = this.params;
+    User.allCourseRecord(Object.assign({ recordId: id }, this.state.search)).then(result => {
+      this.setTableData(result, result ? result.length : 0);
+    });
   }
 
   refreshVs() {
     const { id } = this.params;
-    User.listCourseAppointment(Object.assign({ courseId: id }, this.state.search)).then(result => {
+    User.listCourseAppointment(Object.assign({ recordId: id }, this.state.search)).then(result => {
       result.list = result.list.map(row => {
         row.startTime = moment(row.startTime);
         row.endTime = moment(row.endTime);

+ 30 - 34
front/project/admin/routes/user/recordAll/page.js

@@ -6,7 +6,7 @@ import FilterLayout from '@src/layouts/FilterLayout';
 import ActionLayout from '@src/layouts/ActionLayout';
 import TableLayout from '@src/layouts/TableLayout';
 import { getMap, formatDate, formatMoney, bindSearch } from '@src/services/Tools';
-import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
+import { asyncSMessage, asyncForm, asyncDelConfirm } from '@src/services/AsyncTools';
 import { ServiceParamMap, ServiceKey, MobileArea, RecordSource, ProductTypeMain } from '../../../../Constant';
 import { User } from '../../../stores/user';
 import { Course } from '../../../stores/course';
@@ -136,31 +136,15 @@ export default class extends Page {
       select: ProductTypeMain,
       onChange: (value) => {
         // 根据服务
-        if (value === 'service') {
-          this.filterForm[2].disabled = true;
-          this.filterForm[3].disabled = false;
-          this.filterForm[3].select = ServiceParamList[value] || [];
-        } else {
-          this.filterForm[2].disabled = false;
-          this.filterForm[3].disabled = true;
-          bindSearch(this.filterForm, 'productId', this.filterF, (search) => {
-            if (value === 'course') {
-              return Course.list(search);
-            }
-            return Course.listData(search);
-          }, (row) => {
-            return {
-              title: row.title,
-              key: row.id,
-            };
-          }, null, null);
-        }
+        this.changeSearch(this.filterForm, this.filterF, value, null);
+        this.filterF.setFieldsValue({ productId: null, service: null });
       },
     }, {
       key: 'productId',
       type: 'select',
       allowClear: true,
       name: '具体名称',
+      number: true,
       select: [],
     }, {
       key: 'service',
@@ -246,24 +230,34 @@ export default class extends Page {
       };
     }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
 
-    if (this.state.search.productId) {
-      bindSearch(this.filterForm, 'productId', this.filterF, (search) => {
-        if (this.state.search.productType === 'course') {
+    this.changeSearch(this.filterForm, this, this.state.search.productType, this.state.search.productId);
+  }
+
+  initFilter() {
+
+  }
+
+  changeSearch(list, component, key, value) {
+    if (key === 'service') {
+      list[2].disabled = true;
+      list[3].disabled = false;
+    } else if (key === 'course' || key === 'data') {
+      list[2].disabled = false;
+      list[3].disabled = true;
+      bindSearch(list, 'productId', component, (search) => {
+        if (key === 'course') {
           return Course.list(search);
         }
         return Course.listData(search);
       }, (row) => {
         return {
           title: row.title,
-          key: row.id,
+          value: row.id,
         };
-      }, Number(this.state.search.productId), null);
-      this.filterForm[3].disabled = true;
-    } else if (this.state.search.service) {
-      this.filterForm[2].disabled = true;
+      }, value ? Number(value) : null, null);
     } else {
-      this.filterForm[2].disabled = true;
-      this.filterForm[3].disabled = true;
+      list[2].disabled = true;
+      list[3].disabled = true;
     }
   }
 
@@ -304,9 +298,11 @@ export default class extends Page {
   }
 
   stopAction(id) {
-    return User.stopRecord({ id }).then(() => {
-      asyncSMessage('停用成功!');
-      this.refresh();
+    asyncDelConfirm('停用确认', '是否停用选中记录?', () => {
+      return User.stopRecord({ id }).then(() => {
+        asyncSMessage('停用成功!');
+        this.refresh();
+      });
     });
   }
 
@@ -314,7 +310,7 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
-        ref={(ref) => { this.filterF = ref; }}
+        ref={(ref) => { if (!this.filterF) { this.filterF = ref; } }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {

+ 22 - 32
front/project/admin/routes/user/recordBuy/page.js

@@ -14,9 +14,9 @@ import { Course } from '../../../stores/course';
 const ServiceKeyMap = getMap(ServiceKey, 'value', 'label');
 const ProductTypeMainMap = getMap(ProductTypeMain, 'value', 'label');
 const RecordBuySourceMap = getMap(RecordBuySource, 'value', 'label');
-const ServiceParamList = getMap(Object.keys(ServiceParamMap).map(key => {
-  return { list: ServiceParamMap[key], key };
-}), 'key', 'list');
+// const ServiceParamList = getMap(Object.keys(ServiceParamMap).map(key => {
+//   return { list: ServiceParamMap[key], key };
+// }), 'key', 'list');
 const ServiceParamRelation = getMap(Object.keys(ServiceParamMap).map(key => {
   return { map: getMap(ServiceParamMap[key], 'value', 'label'), key };
 }), 'key', 'map');
@@ -39,31 +39,14 @@ export default class extends Page {
       select: ProductTypeMain,
       onChange: (value) => {
         // 根据服务
-        if (value === 'service') {
-          this.filterForm[2].disabled = true;
-          this.filterForm[3].disabled = false;
-          this.filterForm[3].select = ServiceParamList[value] || [];
-        } else {
-          this.filterForm[2].disabled = false;
-          this.filterForm[3].disabled = true;
-          bindSearch(this.filterForm, 'productId', this.filterF, (search) => {
-            if (value === 'course') {
-              return Course.list(search);
-            }
-            return Course.listData(search);
-          }, (row) => {
-            return {
-              title: row.title,
-              key: row.id,
-            };
-          }, null, null);
-        }
+        this.changeSearch(this.filterForm, this, value, null);
       },
     }, {
       key: 'productId',
       type: 'select',
       allowClear: true,
       name: '具体名称',
+      number: true,
       select: [],
     }, {
       key: 'service',
@@ -147,24 +130,30 @@ export default class extends Page {
       };
     }, this.state.search.userId ? Number(this.state.search.userId) : null, null);
 
-    if (this.state.search.productId) {
-      bindSearch(this.filterForm, 'productId', this.filterF, (search) => {
-        if (this.state.search.productType === 'course') {
+    this.changeSearch(this.filterForm, this, this.state.search.productType, this.state.search.productId);
+  }
+
+  changeSearch(list, component, key, value) {
+    if (key === 'service') {
+      list[2].disabled = true;
+      list[3].disabled = false;
+    } else if (key === 'course' || key === 'data') {
+      list[2].disabled = false;
+      list[3].disabled = true;
+      bindSearch(list, 'productId', component, (search) => {
+        if (key === 'course') {
           return Course.list(search);
         }
         return Course.listData(search);
       }, (row) => {
         return {
           title: row.title,
-          key: row.id,
+          value: row.id,
         };
-      }, Number(this.state.search.productId), null);
-      this.filterForm[3].disabled = true;
-    } else if (this.state.search.service) {
-      this.filterForm[2].disabled = true;
+      }, value ? Number(value) : null, null);
     } else {
-      this.filterForm[2].disabled = true;
-      this.filterForm[3].disabled = true;
+      list[2].disabled = true;
+      list[3].disabled = true;
     }
   }
 
@@ -178,6 +167,7 @@ export default class extends Page {
     return <Block flex>
       <FilterLayout
         show
+        ref={(ref) => { this.filterF = ref; }}
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {

+ 1 - 1
front/project/admin/stores/system.js

@@ -169,7 +169,7 @@ export default class SystemStore extends BaseStore {
     return this.apiGet('/setting/sentence_info');
   }
 
-  setTSentenceInfo(params) {
+  setSentenceInfo(params) {
     return this.apiPut('/setting/sentence_info', params);
   }
 

+ 5 - 1
front/project/admin/stores/user.js

@@ -81,6 +81,10 @@ export default class UserStore extends BaseStore {
     return this.apiGet('/user/valid/mobile', params);
   }
 
+  allCourseRecord(params) {
+    return this.apiGet('/user/course/record/all', params);
+  }
+
   listCourseAppointment(params) {
     return this.apiGet('/user/course/appointment/list', params);
   }
@@ -122,7 +126,7 @@ export default class UserStore extends BaseStore {
   }
 
   stopRecord(params) {
-    return this.apiGet('/user/record/stop', params);
+    return this.apiPut('/user/record/stop', params);
   }
 
   listRecord(params) {

+ 16 - 16
front/project/www/routes/examination/list/page.js

@@ -42,11 +42,11 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.totalScore}分${record.report.score.totalRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.totalScore / record.totalTimes)}分</div>
             {this.state.showPrev && record.prevReport && <div className="prev">
-              <div className="night f-s-16 f-w-b">{record.prevReport.score.total}分{record.prevReport.score.totalRank}th</div>
-              <div className="f-s-12">全站: {Math.round(record.totalScore / record.totalTimes)}分</div>
+              <div className="night f-s-16 f-w-b">{record.prevReport.score.totalScore}分{record.prevReport.score.totalRank}th</div>
+              <div className="f-s-12">全站: {Math.round(record.secondTotalScore / record.secondTotalTimes)}分</div>
             </div>}
           </div>
         );
@@ -58,11 +58,11 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.verbalScore}分${record.report.score.verbalRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.verbalScore / record.totalTimes)}分</div>
             {this.state.showPrev && record.prevReport && <div className="prev">
-              <div className="night f-s-16 f-w-b">{record.prevReport.score.verbal}分{record.prevReport.score.verbalRank}th</div>
-              <div className="f-s-12">全站: {Math.round(record.verbalScore / record.totalTimes)}分</div>
+              <div className="night f-s-16 f-w-b">{record.prevReport.score.verbalScore}分{record.prevReport.score.verbalRank}th</div>
+              <div className="f-s-12">全站: {Math.round(record.secondVerbalScore / record.secondTotalTimes)}分</div>
             </div>}
           </div>
         );
@@ -74,11 +74,11 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.quantScore}分${record.report.score.quantRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.quantScore / record.totalTimes)}分</div>
             {this.state.showPrev && record.prevReport && <div className="prev">
-              <div className="night f-s-16 f-w-b">{record.prevReport.score.quant}分{record.prevReport.score.quantRank}th</div>
-              <div className="f-s-12">全站: {Math.round(record.quantScore / record.totalTimes)}分</div>
+              <div className="night f-s-16 f-w-b">{record.prevReport.score.quantScore}分{record.prevReport.score.quantRank}th</div>
+              <div className="f-s-12">全站: {Math.round(record.secondQuantScore / record.secondTotalTimes)}分</div>
             </div>}
           </div>
         );
@@ -90,11 +90,11 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.irScore}分${record.report.score.irRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.irScore / record.totalTimes)}分</div>
             {this.state.showPrev && record.prevReport && <div className="prev">
-              <div className="night f-s-16 f-w-b">{record.prevReport.score.ir}分{record.prevReport.score.irRank}th</div>
-              <div className="f-s-12">全站: {Math.round(record.irScore / record.totalTimes)}分</div>
+              <div className="night f-s-16 f-w-b">{record.prevReport.score.irScore}分{record.prevReport.score.irRank}th</div>
+              <div className="f-s-12">全站: {Math.round(record.secondIrScore / record.secondTotalTimes)}分</div>
             </div>}
           </div>
         );
@@ -175,7 +175,7 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.totalScore}分${record.report.score.totalRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.totalScore / record.totalTimes)}分</div>
           </div>
         );
@@ -187,7 +187,7 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.verbalScore}分${record.report.score.verbalRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.verbalScore / record.totalTimes)}分</div>
           </div>
         );
@@ -199,7 +199,7 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.quantScore}分${record.report.score.quantRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.quantScore / record.totalTimes)}分</div>
           </div>
         );
@@ -211,7 +211,7 @@ export default class extends Page {
       render: (record) => {
         return (
           <div className="table-row">
-            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.total}分${record.report.score.totalRank}th` : '-分-th'}</div>
+            <div className="night f-s-16 f-w-b">{record.report ? `${record.report.score.irScore}分${record.report.score.irRank}th` : '-分-th'}</div>
             <div className="f-s-12">全站: {Math.round(record.irScore / record.totalTimes)}分</div>
           </div>
         );

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

@@ -123,9 +123,9 @@ export default class extends Page {
   }
 
   submitFeedbackError() {
-    const { feedback = {}, question = {}, questionNo = {} } = this.state;
+    const { feedback = {}, userQuestion = {}, questionNo = {} } = this.state;
     if (feedback.originContent === '' || feedback.content === '' || feedback.target === '') return;
-    My.addFeedbackErrorQuestion(question.id, questionNo.title, feedback.target, feedback.originContent, feedback.content).then(() => {
+    My.addFeedbackErrorQuestion(userQuestion.id, questionNo.title, feedback.target, feedback.originContent, feedback.content).then(() => {
       this.setState({ feedbackModal: false, feedbackOkModal: true });
     }).catch(err => {
       this.setState({ feedbackError: err.message });

+ 3 - 2
front/project/www/static/login.html

@@ -203,15 +203,16 @@
   }
   var code = getQuery('code');
   if (code) {
-    window.parent.postMessage('code:' + code, '*');
+    window.top.postMessage('code:' + code, '*');
   } else {
     document.getElementById('loading').style.display = 'none';
   }
   new WxLogin({
     id: 'root',
+    self_redirect: true,
     appid: getQuery('appid'),
     scope: 'snsapi_login',
-    redirect_uri: getQuery('redirectUri'),
+    redirect_uri: getQuery('redirectUri') + '/login.html',
   });
 </script>
 

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

@@ -255,14 +255,14 @@ export default class MyStore extends BaseStore {
 
   /**
    * 添加题目勘误
-   * @param {*} moduleId
+   * @param {*} userQuestionId
    * @param {*} title
    * @param {*} position
    * @param {*} originContent
    * @param {*} content
    */
-  addFeedbackErrorQuestion(moduleId, title, position, originContent, content) {
-    return this.apiPost('/my/feedback/error/question', { moduleId, title, position, originContent, content });
+  addFeedbackErrorQuestion(userQuestionId, title, position, originContent, content) {
+    return this.apiPost('/my/feedback/error/question', { userQuestionId, title, position, originContent, content });
   }
 
   /**

+ 3 - 1
front/src/layouts/FormLayout/index.js

@@ -1,6 +1,6 @@
 import React, { Component } from 'react';
 import moment from 'moment';
-import { Form, Button, Switch, DatePicker, Input, InputNumber, Modal, Alert } from 'antd';
+import { Form, Button, Switch, DatePicker, Input, InputNumber, Modal, Alert, Cascader } from 'antd';
 import Select from '../../components/Select';
 import Multiple from '../../components/Multiple';
 import Radio from '../../components/Radio';
@@ -82,6 +82,8 @@ class FormLayout extends Component {
             disabled={!!item.disabled}
           />
         );
+      case 'cascader':
+        return <Cascader {...item} className={item.class} options={item.select} placeholder={item.placeholder} />;
       case 'render':
         return item.render(item, this.props.data, this.props.form);
       case 'textarea':

+ 37 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/module/AskModule.java

@@ -0,0 +1,37 @@
+package com.qxgmat.data.constants.enums.module;
+
+// 组卷模块
+public enum AskModule {
+    EXERCISE("exercise"),
+    EXAMINATION("examination"),
+    ;
+    public String key;
+    private AskModule(String key){
+        this.key = key;
+    }
+
+    public static AskModule ValueOf(String name){
+        if (name == null) return null;
+        return AskModule.valueOf(name.toUpperCase());
+    }
+
+    /**
+     * 根据origin类型判断组卷类型
+     * @param module
+     * @return
+     */
+    public static AskModule WithPaper(PaperModule module){
+        switch(module){
+            case SENTENCE:
+                return EXERCISE;
+            case TEXTBOOK:
+                return EXAMINATION;
+            case EXERCISE:
+                return EXERCISE;
+            case EXAMINATION:
+                return EXAMINATION;
+            default:
+                return null;
+        }
+    }
+}

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

@@ -70,6 +70,36 @@ public class ExaminationPaper implements Serializable {
     @Column(name = "`ir_score`")
     private Integer irScore;
 
+    /**
+     * 第二次总分
+     */
+    @Column(name = "`second_total_score`")
+    private Integer secondTotalScore;
+
+    /**
+     * 第二次总做卷次数
+     */
+    @Column(name = "`second_total_times`")
+    private Integer secondTotalTimes;
+
+    /**
+     * 第二次总Q分
+     */
+    @Column(name = "`second_quant_score`")
+    private Integer secondQuantScore;
+
+    /**
+     * 第二次总V分
+     */
+    @Column(name = "`second_verbal_score`")
+    private Integer secondVerbalScore;
+
+    /**
+     * 第二次总ir分
+     */
+    @Column(name = "`second_ir_score`")
+    private Integer secondIrScore;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -266,6 +296,96 @@ public class ExaminationPaper implements Serializable {
         this.irScore = irScore;
     }
 
+    /**
+     * 获取第二次总分
+     *
+     * @return second_total_score - 第二次总分
+     */
+    public Integer getSecondTotalScore() {
+        return secondTotalScore;
+    }
+
+    /**
+     * 设置第二次总分
+     *
+     * @param secondTotalScore 第二次总分
+     */
+    public void setSecondTotalScore(Integer secondTotalScore) {
+        this.secondTotalScore = secondTotalScore;
+    }
+
+    /**
+     * 获取第二次总做卷次数
+     *
+     * @return second_total_times - 第二次总做卷次数
+     */
+    public Integer getSecondTotalTimes() {
+        return secondTotalTimes;
+    }
+
+    /**
+     * 设置第二次总做卷次数
+     *
+     * @param secondTotalTimes 第二次总做卷次数
+     */
+    public void setSecondTotalTimes(Integer secondTotalTimes) {
+        this.secondTotalTimes = secondTotalTimes;
+    }
+
+    /**
+     * 获取第二次总Q分
+     *
+     * @return second_quant_score - 第二次总Q分
+     */
+    public Integer getSecondQuantScore() {
+        return secondQuantScore;
+    }
+
+    /**
+     * 设置第二次总Q分
+     *
+     * @param secondQuantScore 第二次总Q分
+     */
+    public void setSecondQuantScore(Integer secondQuantScore) {
+        this.secondQuantScore = secondQuantScore;
+    }
+
+    /**
+     * 获取第二次总V分
+     *
+     * @return second_verbal_score - 第二次总V分
+     */
+    public Integer getSecondVerbalScore() {
+        return secondVerbalScore;
+    }
+
+    /**
+     * 设置第二次总V分
+     *
+     * @param secondVerbalScore 第二次总V分
+     */
+    public void setSecondVerbalScore(Integer secondVerbalScore) {
+        this.secondVerbalScore = secondVerbalScore;
+    }
+
+    /**
+     * 获取第二次总ir分
+     *
+     * @return second_ir_score - 第二次总ir分
+     */
+    public Integer getSecondIrScore() {
+        return secondIrScore;
+    }
+
+    /**
+     * 设置第二次总ir分
+     *
+     * @param secondIrScore 第二次总ir分
+     */
+    public void setSecondIrScore(Integer secondIrScore) {
+        this.secondIrScore = secondIrScore;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -283,6 +403,11 @@ public class ExaminationPaper implements Serializable {
         sb.append(", quantScore=").append(quantScore);
         sb.append(", verbalScore=").append(verbalScore);
         sb.append(", irScore=").append(irScore);
+        sb.append(", secondTotalScore=").append(secondTotalScore);
+        sb.append(", secondTotalTimes=").append(secondTotalTimes);
+        sb.append(", secondQuantScore=").append(secondQuantScore);
+        sb.append(", secondVerbalScore=").append(secondVerbalScore);
+        sb.append(", secondIrScore=").append(secondIrScore);
         sb.append("]");
         return sb.toString();
     }
@@ -406,6 +531,56 @@ public class ExaminationPaper implements Serializable {
             return this;
         }
 
+        /**
+         * 设置第二次总分
+         *
+         * @param secondTotalScore 第二次总分
+         */
+        public Builder secondTotalScore(Integer secondTotalScore) {
+            obj.setSecondTotalScore(secondTotalScore);
+            return this;
+        }
+
+        /**
+         * 设置第二次总做卷次数
+         *
+         * @param secondTotalTimes 第二次总做卷次数
+         */
+        public Builder secondTotalTimes(Integer secondTotalTimes) {
+            obj.setSecondTotalTimes(secondTotalTimes);
+            return this;
+        }
+
+        /**
+         * 设置第二次总Q分
+         *
+         * @param secondQuantScore 第二次总Q分
+         */
+        public Builder secondQuantScore(Integer secondQuantScore) {
+            obj.setSecondQuantScore(secondQuantScore);
+            return this;
+        }
+
+        /**
+         * 设置第二次总V分
+         *
+         * @param secondVerbalScore 第二次总V分
+         */
+        public Builder secondVerbalScore(Integer secondVerbalScore) {
+            obj.setSecondVerbalScore(secondVerbalScore);
+            return this;
+        }
+
+        /**
+         * 设置第二次总ir分
+         *
+         * @param secondIrScore 第二次总ir分
+         */
+        public Builder secondIrScore(Integer secondIrScore) {
+            obj.setSecondIrScore(secondIrScore);
+            return this;
+        }
+
         public ExaminationPaper build() {
             return this.obj;
         }

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

@@ -42,6 +42,12 @@ public class UserAskCourse implements Serializable {
     private String position;
 
     /**
+     * 提问优先回答时间
+     */
+    @Column(name = "`ask_time`")
+    private Integer askTime;
+
+    /**
      * 回答状态: 0未回答,1回答,2忽略
      */
     @Column(name = "`answer_status`")
@@ -196,6 +202,24 @@ public class UserAskCourse implements Serializable {
     }
 
     /**
+     * 获取提问优先回答时间
+     *
+     * @return ask_time - 提问优先回答时间
+     */
+    public Integer getAskTime() {
+        return askTime;
+    }
+
+    /**
+     * 设置提问优先回答时间
+     *
+     * @param askTime 提问优先回答时间
+     */
+    public void setAskTime(Integer askTime) {
+        this.askTime = askTime;
+    }
+
+    /**
      * 获取回答状态: 0未回答,1回答,2忽略
      *
      * @return answer_status - 回答状态: 0未回答,1回答,2忽略
@@ -361,6 +385,7 @@ public class UserAskCourse implements Serializable {
         sb.append(", courseNoId=").append(courseNoId);
         sb.append(", recordId=").append(recordId);
         sb.append(", position=").append(position);
+        sb.append(", askTime=").append(askTime);
         sb.append(", answerStatus=").append(answerStatus);
         sb.append(", managerId=").append(managerId);
         sb.append(", showStatus=").append(showStatus);
@@ -444,6 +469,16 @@ public class UserAskCourse implements Serializable {
         }
 
         /**
+         * 设置提问优先回答时间
+         *
+         * @param askTime 提问优先回答时间
+         */
+        public Builder askTime(Integer askTime) {
+            obj.setAskTime(askTime);
+            return this;
+        }
+
+        /**
          * 设置回答
          *
          * @param answer 回答

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

@@ -24,6 +24,12 @@ public class UserAskQuestion implements Serializable {
     private Integer userQuestionId;
 
     /**
+     * 题目板块
+     */
+    @Column(name = "`ask_module`")
+    private String askModule;
+
+    /**
      * 题目模块
      */
     @Column(name = "`question_module`")
@@ -42,16 +48,22 @@ public class UserAskQuestion implements Serializable {
     private Integer questionNoId;
 
     /**
+     * 课程对应recordid
+     */
+    @Column(name = "`record_id`")
+    private Integer recordId;
+
+    /**
      * 问题对象:question,official,qx,association
      */
     @Column(name = "`target`")
     private String target;
 
     /**
-     * 课程对应recordid
+     * 提问优先回答时间
      */
-    @Column(name = "`record_id`")
-    private Integer recordId;
+    @Column(name = "`ask_time`")
+    private Integer askTime;
 
     /**
      * 回答状态: 0未回答,1回答,2忽略
@@ -160,6 +172,24 @@ public class UserAskQuestion implements Serializable {
     }
 
     /**
+     * 获取题目板块
+     *
+     * @return ask_module - 题目板块
+     */
+    public String getAskModule() {
+        return askModule;
+    }
+
+    /**
+     * 设置题目板块
+     *
+     * @param askModule 题目板块
+     */
+    public void setAskModule(String askModule) {
+        this.askModule = askModule;
+    }
+
+    /**
      * 获取题目模块
      *
      * @return question_module - 题目模块
@@ -214,6 +244,24 @@ public class UserAskQuestion implements Serializable {
     }
 
     /**
+     * 获取课程对应recordid
+     *
+     * @return record_id - 课程对应recordid
+     */
+    public Integer getRecordId() {
+        return recordId;
+    }
+
+    /**
+     * 设置课程对应recordid
+     *
+     * @param recordId 课程对应recordid
+     */
+    public void setRecordId(Integer recordId) {
+        this.recordId = recordId;
+    }
+
+    /**
      * 获取问题对象:question,official,qx,association
      *
      * @return target - 问题对象:question,official,qx,association
@@ -232,21 +280,21 @@ public class UserAskQuestion implements Serializable {
     }
 
     /**
-     * 获取课程对应recordid
+     * 获取提问优先回答时间
      *
-     * @return record_id - 课程对应recordid
+     * @return ask_time - 提问优先回答时间
      */
-    public Integer getRecordId() {
-        return recordId;
+    public Integer getAskTime() {
+        return askTime;
     }
 
     /**
-     * 设置课程对应recordid
+     * 设置提问优先回答时间
      *
-     * @param recordId 课程对应recordid
+     * @param askTime 提问优先回答时间
      */
-    public void setRecordId(Integer recordId) {
-        this.recordId = recordId;
+    public void setAskTime(Integer askTime) {
+        this.askTime = askTime;
     }
 
     /**
@@ -430,11 +478,13 @@ public class UserAskQuestion implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", userQuestionId=").append(userQuestionId);
+        sb.append(", askModule=").append(askModule);
         sb.append(", questionModule=").append(questionModule);
         sb.append(", questionId=").append(questionId);
         sb.append(", questionNoId=").append(questionNoId);
-        sb.append(", target=").append(target);
         sb.append(", recordId=").append(recordId);
+        sb.append(", target=").append(target);
+        sb.append(", askTime=").append(askTime);
         sb.append(", answerStatus=").append(answerStatus);
         sb.append(", managerId=").append(managerId);
         sb.append(", showStatus=").append(showStatus);
@@ -489,6 +539,16 @@ public class UserAskQuestion implements Serializable {
         }
 
         /**
+         * 设置题目板块
+         *
+         * @param askModule 题目板块
+         */
+        public Builder askModule(String askModule) {
+            obj.setAskModule(askModule);
+            return this;
+        }
+
+        /**
          * 设置题目模块
          *
          * @param questionModule 题目模块
@@ -519,6 +579,16 @@ public class UserAskQuestion implements Serializable {
         }
 
         /**
+         * 设置课程对应recordid
+         *
+         * @param recordId 课程对应recordid
+         */
+        public Builder recordId(Integer recordId) {
+            obj.setRecordId(recordId);
+            return this;
+        }
+
+        /**
          * 设置问题对象:question,official,qx,association
          *
          * @param target 问题对象:question,official,qx,association
@@ -529,12 +599,12 @@ public class UserAskQuestion implements Serializable {
         }
 
         /**
-         * 设置课程对应recordid
+         * 设置提问优先回答时间
          *
-         * @param recordId 课程对应recordid
+         * @param askTime 提问优先回答时间
          */
-        public Builder recordId(Integer recordId) {
-            obj.setRecordId(recordId);
+        public Builder askTime(Integer askTime) {
+            obj.setAskTime(askTime);
             return this;
         }
 

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

@@ -61,12 +61,6 @@ public class UserCourseAppointment implements Serializable {
     private Date endTime;
 
     /**
-     * 用户作业id
-     */
-    @Column(name = "`paper_id`")
-    private Integer paperId;
-
-    /**
      * 是否完成
      */
     @Column(name = "`is_finish`")
@@ -248,24 +242,6 @@ public class UserCourseAppointment implements Serializable {
     }
 
     /**
-     * 获取用户作业id
-     *
-     * @return paper_id - 用户作业id
-     */
-    public Integer getPaperId() {
-        return paperId;
-    }
-
-    /**
-     * 设置用户作业id
-     *
-     * @param paperId 用户作业id
-     */
-    public void setPaperId(Integer paperId) {
-        this.paperId = paperId;
-    }
-
-    /**
      * 获取是否完成
      *
      * @return is_finish - 是否完成
@@ -348,7 +324,6 @@ public class UserCourseAppointment implements Serializable {
         sb.append(", cctalkChannel=").append(cctalkChannel);
         sb.append(", startTime=").append(startTime);
         sb.append(", endTime=").append(endTime);
-        sb.append(", paperId=").append(paperId);
         sb.append(", isFinish=").append(isFinish);
         sb.append(", supplyList=").append(supplyList);
         sb.append(", noteList=").append(noteList);
@@ -467,16 +442,6 @@ public class UserCourseAppointment implements Serializable {
         }
 
         /**
-         * 设置用户作业id
-         *
-         * @param paperId 用户作业id
-         */
-        public Builder paperId(Integer paperId) {
-            obj.setPaperId(paperId);
-            return this;
-        }
-
-        /**
          * 设置是否完成
          *
          * @param isFinish 是否完成

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

@@ -30,6 +30,24 @@ public class UserFeedbackError implements Serializable {
     private Integer moduleId;
 
     /**
+     * 题目类型
+     */
+    @Column(name = "`question_type`")
+    private String questionType;
+
+    /**
+     * 题目模块
+     */
+    @Column(name = "`question_module`")
+    private String questionModule;
+
+    /**
+     * 题目编号id
+     */
+    @Column(name = "`question_no_id`")
+    private Integer questionNoId;
+
+    /**
      * 处理人id
      */
     @Column(name = "`manager_id`")
@@ -145,6 +163,60 @@ public class UserFeedbackError implements Serializable {
     }
 
     /**
+     * 获取题目类型
+     *
+     * @return question_type - 题目类型
+     */
+    public String getQuestionType() {
+        return questionType;
+    }
+
+    /**
+     * 设置题目类型
+     *
+     * @param questionType 题目类型
+     */
+    public void setQuestionType(String questionType) {
+        this.questionType = questionType;
+    }
+
+    /**
+     * 获取题目模块
+     *
+     * @return question_module - 题目模块
+     */
+    public String getQuestionModule() {
+        return questionModule;
+    }
+
+    /**
+     * 设置题目模块
+     *
+     * @param questionModule 题目模块
+     */
+    public void setQuestionModule(String questionModule) {
+        this.questionModule = questionModule;
+    }
+
+    /**
+     * 获取题目编号id
+     *
+     * @return question_no_id - 题目编号id
+     */
+    public Integer getQuestionNoId() {
+        return questionNoId;
+    }
+
+    /**
+     * 设置题目编号id
+     *
+     * @param questionNoId 题目编号id
+     */
+    public void setQuestionNoId(Integer questionNoId) {
+        this.questionNoId = questionNoId;
+    }
+
+    /**
      * 获取处理人id
      *
      * @return manager_id - 处理人id
@@ -294,6 +366,9 @@ public class UserFeedbackError implements Serializable {
         sb.append(", userId=").append(userId);
         sb.append(", module=").append(module);
         sb.append(", moduleId=").append(moduleId);
+        sb.append(", questionType=").append(questionType);
+        sb.append(", questionModule=").append(questionModule);
+        sb.append(", questionNoId=").append(questionNoId);
         sb.append(", managerId=").append(managerId);
         sb.append(", title=").append(title);
         sb.append(", position=").append(position);
@@ -356,6 +431,36 @@ public class UserFeedbackError implements Serializable {
         }
 
         /**
+         * 设置题目类型
+         *
+         * @param questionType 题目类型
+         */
+        public Builder questionType(String questionType) {
+            obj.setQuestionType(questionType);
+            return this;
+        }
+
+        /**
+         * 设置题目模块
+         *
+         * @param questionModule 题目模块
+         */
+        public Builder questionModule(String questionModule) {
+            obj.setQuestionModule(questionModule);
+            return this;
+        }
+
+        /**
+         * 设置题目编号id
+         *
+         * @param questionNoId 题目编号id
+         */
+        public Builder questionNoId(Integer questionNoId) {
+            obj.setQuestionNoId(questionNoId);
+            return this;
+        }
+
+        /**
          * 设置处理人id
          *
          * @param managerId 处理人id

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

@@ -1,6 +1,7 @@
 package com.qxgmat.data.dao.entity;
 
 import java.io.Serializable;
+import java.math.BigDecimal;
 import java.util.Date;
 import javax.persistence.*;
 
@@ -170,6 +171,12 @@ public class UserOrderRecord implements Serializable {
     @Column(name = "`create_time`")
     private Date createTime;
 
+    @Column(name = "`money`")
+    private BigDecimal money;
+
+    @Column(name = "`origin_money`")
+    private BigDecimal originMoney;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -668,6 +675,34 @@ public class UserOrderRecord implements Serializable {
         this.createTime = createTime;
     }
 
+    /**
+     * @return money
+     */
+    public BigDecimal getMoney() {
+        return money;
+    }
+
+    /**
+     * @param money
+     */
+    public void setMoney(BigDecimal money) {
+        this.money = money;
+    }
+
+    /**
+     * @return origin_money
+     */
+    public BigDecimal getOriginMoney() {
+        return originMoney;
+    }
+
+    /**
+     * @param originMoney
+     */
+    public void setOriginMoney(BigDecimal originMoney) {
+        this.originMoney = originMoney;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -702,6 +737,8 @@ public class UserOrderRecord implements Serializable {
         sb.append(", suspendTime=").append(suspendTime);
         sb.append(", restoreTime=").append(restoreTime);
         sb.append(", createTime=").append(createTime);
+        sb.append(", money=").append(money);
+        sb.append(", originMoney=").append(originMoney);
         sb.append("]");
         return sb.toString();
     }
@@ -993,6 +1030,22 @@ public class UserOrderRecord implements Serializable {
             return this;
         }
 
+        /**
+         * @param money
+         */
+        public Builder money(BigDecimal money) {
+            obj.setMoney(money);
+            return this;
+        }
+
+        /**
+         * @param originMoney
+         */
+        public Builder originMoney(BigDecimal originMoney) {
+            obj.setOriginMoney(originMoney);
+            return this;
+        }
+
         public UserOrderRecord build() {
             return this.obj;
         }

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

@@ -16,12 +16,18 @@
     <result column="quant_score" jdbcType="INTEGER" property="quantScore" />
     <result column="verbal_score" jdbcType="INTEGER" property="verbalScore" />
     <result column="ir_score" jdbcType="INTEGER" property="irScore" />
+    <result column="second_total_score" jdbcType="INTEGER" property="secondTotalScore" />
+    <result column="second_total_times" jdbcType="INTEGER" property="secondTotalTimes" />
+    <result column="second_quant_score" jdbcType="INTEGER" property="secondQuantScore" />
+    <result column="second_verbal_score" jdbcType="INTEGER" property="secondVerbalScore" />
+    <result column="second_ir_score" jdbcType="INTEGER" property="secondIrScore" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
       WARNING - @mbg.generated
     -->
     `id`, `struct_two`, `struct_three`, `is_adapt`, `title`, `status`, `total_score`, 
-    `total_times`, `quant_score`, `verbal_score`, `ir_score`
+    `total_times`, `quant_score`, `verbal_score`, `ir_score`, `second_total_score`, `second_total_times`, 
+    `second_quant_score`, `second_verbal_score`, `second_ir_score`
   </sql>
 </mapper>

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

@@ -11,6 +11,7 @@
     <result column="course_no_id" jdbcType="INTEGER" property="courseNoId" />
     <result column="record_id" jdbcType="INTEGER" property="recordId" />
     <result column="position" jdbcType="VARCHAR" property="position" />
+    <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="answer_status" jdbcType="INTEGER" property="answerStatus" />
     <result column="manager_id" jdbcType="INTEGER" property="managerId" />
     <result column="show_status" jdbcType="INTEGER" property="showStatus" />
@@ -30,8 +31,9 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `course_id`, `course_no_id`, `record_id`, `position`, `answer_status`, 
-    `manager_id`, `show_status`, `answer_time`, `order`, `create_time`, `update_time`
+    `id`, `user_id`, `course_id`, `course_no_id`, `record_id`, `position`, `ask_time`, 
+    `answer_status`, `manager_id`, `show_status`, `answer_time`, `order`, `create_time`, 
+    `update_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -8,11 +8,13 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_question_id" jdbcType="INTEGER" property="userQuestionId" />
+    <result column="ask_module" jdbcType="VARCHAR" property="askModule" />
     <result column="question_module" jdbcType="VARCHAR" property="questionModule" />
     <result column="question_id" jdbcType="INTEGER" property="questionId" />
     <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
-    <result column="target" jdbcType="VARCHAR" property="target" />
     <result column="record_id" jdbcType="INTEGER" property="recordId" />
+    <result column="target" jdbcType="VARCHAR" property="target" />
+    <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="answer_status" jdbcType="INTEGER" property="answerStatus" />
     <result column="manager_id" jdbcType="INTEGER" property="managerId" />
     <result column="show_status" jdbcType="INTEGER" property="showStatus" />
@@ -33,9 +35,9 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `user_question_id`, `question_module`, `question_id`, `question_no_id`, 
-    `target`, `record_id`, `answer_status`, `manager_id`, `show_status`, `answer_time`, 
-    `order`, `create_time`, `update_time`
+    `id`, `user_id`, `user_question_id`, `ask_module`, `question_module`, `question_id`, 
+    `question_no_id`, `record_id`, `target`, `ask_time`, `answer_status`, `manager_id`, 
+    `show_status`, `answer_time`, `order`, `create_time`, `update_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -14,7 +14,6 @@
     <result column="cctalk_channel" jdbcType="VARCHAR" property="cctalkChannel" />
     <result column="start_time" jdbcType="TIMESTAMP" property="startTime" />
     <result column="end_time" jdbcType="TIMESTAMP" property="endTime" />
-    <result column="paper_id" jdbcType="INTEGER" property="paperId" />
     <result column="is_finish" jdbcType="INTEGER" property="isFinish" />
     <result column="supply_list" jdbcType="VARCHAR" property="supplyList" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler" />
     <result column="note_list" jdbcType="VARCHAR" property="noteList" typeHandler="com.nuliji.tools.mybatis.handler.JsonArrayHandler" />
@@ -25,6 +24,6 @@
       WARNING - @mbg.generated
     -->
     `id`, `user_id`, `no`, `title`, `record_id`, `course_id`, `cctalk_channel`, `start_time`, 
-    `end_time`, `paper_id`, `is_finish`, `supply_list`, `note_list`, `create_time`
+    `end_time`, `is_finish`, `supply_list`, `note_list`, `create_time`
   </sql>
 </mapper>

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

@@ -9,6 +9,9 @@
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="module" jdbcType="VARCHAR" property="module" />
     <result column="module_id" jdbcType="INTEGER" property="moduleId" />
+    <result column="question_type" jdbcType="VARCHAR" property="questionType" />
+    <result column="question_module" jdbcType="VARCHAR" property="questionModule" />
+    <result column="question_no_id" jdbcType="INTEGER" property="questionNoId" />
     <result column="manager_id" jdbcType="INTEGER" property="managerId" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="position" jdbcType="VARCHAR" property="position" />
@@ -27,8 +30,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `user_id`, `module`, `module_id`, `manager_id`, `title`, `position`, `create_time`, 
-    `status`, `handle_time`
+    `id`, `user_id`, `module`, `module_id`, `question_type`, `question_module`, `question_no_id`, 
+    `manager_id`, `title`, `position`, `create_time`, `status`, `handle_time`
   </sql>
   <sql id="Blob_Column_List">
     <!--

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

@@ -33,6 +33,8 @@
     <result column="suspend_time" jdbcType="TIMESTAMP" property="suspendTime" />
     <result column="restore_time" jdbcType="TIMESTAMP" property="restoreTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="money" jdbcType="DECIMAL" property="money" />
+    <result column="origin_money" jdbcType="DECIMAL" property="originMoney" />
   </resultMap>
   <sql id="Base_Column_List">
     <!--
@@ -42,6 +44,6 @@
     `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`
+    `create_time`, `money`, `origin_money`
   </sql>
 </mapper>

+ 24 - 0
server/data/src/main/java/com/qxgmat/data/relation/CommentRelationMapper.java

@@ -0,0 +1,24 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.Comment;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface CommentRelationMapper {
+    List<Comment> listWithUser(
+            @Param("user") Boolean user,
+            @Param("channel") String channel,
+            @Param("position") String position,
+            @Param("userId") Number userId,
+            @Param("isSpecial") Integer isSpecial,
+            @Param("isShow") Integer isShow,
+            @Param("min") Integer min,
+            @Param("max") Integer max,
+            String order,
+            String direction
+    );
+}

+ 9 - 0
server/data/src/main/java/com/qxgmat/data/relation/ExaminationPaperRelationMapper.java

@@ -10,6 +10,15 @@ import java.util.List;
  */
 public interface ExaminationPaperRelationMapper {
 
+    void accumulation(
+            @Param("id") Number paperId,
+            @Param("totalScore") Integer totalScore,
+            @Param("quantScore") Integer quantScore,
+            @Param("verbalScore") Integer verbalScore,
+            @Param("irScore") Integer irScore,
+            @Param("second") Boolean second
+    );
+
     List<ExercisePaper> listWithUser(
             @Param("structId") Number structId,
             @Param("userId") Number userId,

+ 25 - 0
server/data/src/main/java/com/qxgmat/data/relation/FaqRelationMapper.java

@@ -0,0 +1,25 @@
+package com.qxgmat.data.relation;
+
+import com.qxgmat.data.dao.entity.Faq;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * Created by gaojie on 2017/11/9.
+ */
+public interface FaqRelationMapper {
+    List<Faq> listWithUser(
+            @Param("user") Boolean user,
+            @Param("channel") String channel,
+            @Param("position") String position,
+            @Param("userId") Number userId,
+            @Param("answerStatus") Integer answerStatus,
+            @Param("isSpecial") Integer isSpecial,
+            @Param("isShow") Integer isShow,
+            @Param("min") Integer min,
+            @Param("max") Integer max,
+            String order,
+            String direction
+    );
+}

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

@@ -10,6 +10,7 @@ import java.util.List;
  */
 public interface UserAskQuestionRelationMapper {
     List<UserAskQuestion> listWithUser(
+            @Param("askModule") String askModule,
             @Param("questionType") String questionType,
             @Param("module") String module,
             @Param("userId") Number userId,

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

@@ -1,16 +1,22 @@
 package com.qxgmat.data.relation;
 
+import com.qxgmat.data.dao.entity.UserCourseRecord;
 import com.qxgmat.data.relation.entity.UserModuleRecordStatRelation;
 import com.qxgmat.data.relation.entity.UserRankStatRelation;
 import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import org.apache.ibatis.annotations.Param;
 
+import java.util.Collection;
 import java.util.List;
 
 /**
  * Created by gaojie on 2017/11/9.
  */
 public interface UserCourseRecordRelationMapper {
+    List<UserCourseRecord> listLast(
+            @Param("recordIds") Collection recordIds
+    );
+
     List<UserRecordStatRelation> stat(
             @Param("userId") Integer userId,
             @Param("startTime") String startTime,

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

@@ -12,6 +12,9 @@ public interface UserFeedbackErrorRelationMapper {
     List<UserAskQuestion> listAdmin(
             @Param("module") String module,
             @Param("status") Integer status,
+            @Param("questionType") String questionType,
+            @Param("target") String target,
+            @Param("moduleId") Integer moduleId,
             @Param("userId") Integer userId,
             @Param("keyword") String keyword,
             @Param("min") Integer min,

+ 59 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/CommentRelationMapper.xml

@@ -0,0 +1,59 @@
+<?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.CommentRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.Comment">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    f.`id`
+  </sql>
+
+  <!--用户提问列表-->
+  <select id="listWithUser" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `comment` c
+    left join `user` u on u.`id` = c.`user_id`
+      <if test="userId != null">
+        and c.`user_id` = #{userId,jdbcType=VARCHAR}
+      </if>
+      <if test="max != null">
+        and u.`total_money` &lt; ${max}
+      </if>
+      <if test="min != null">
+        and u.`total_money` &gt; ${min}
+      </if>
+    where 1
+    <if test="user != null">
+      and
+      <if test="user">
+        u.`id` &gt; 0
+      </if>
+      <if test="!user">
+        c.`user_id` = 0
+      </if>
+    </if>
+    <if test="userId != null">
+      and u.`id` &gt; 0
+    </if>
+    <if test="channel != null">
+      and c.`channel` = #{channel,jdbcType=VARCHAR}
+    </if>
+    <if test="position != null">
+      and c.`position` = #{position,jdbcType=VARCHAR}
+    </if>
+    <if test="isSpecial != null">
+      and c.`is_special` = #{isSpecial,jdbcType=INTEGER}
+    </if>
+    <if test="isShow != null">
+      and c.`is_show` =#{is_show,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+</mapper>

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

@@ -14,6 +14,28 @@
     ep.`id`
   </sql>
 
+  <!--累加做题记录-->
+  <update id="accumulation">
+    UPDATE `examination_paper`
+    <trim prefix="set" suffixOverrides=",">
+      <if test="!second">
+      `total_score`=`total_score`+#{totalScore, jdbcType=INTEGER},
+      `total_times`=`total_times`+1,
+      `quant_score`=`quant_score`+#{quantScore, jdbcType=INTEGER},
+      `verbal_score`=`verbal_score`+#{verbalScore, jdbcType=INTEGER},
+      `ir_score`=`ir_score`+#{irScore, jdbcType=INTEGER},
+      </if>
+      <if test="second">
+        `second_total_score`=`second_total_score`+#{totalScore, jdbcType=INTEGER},
+        `second_total_times`=`second_total_times`+1,
+        `second_quant_score`=`second_quant_score`+#{quantScore, jdbcType=INTEGER},
+        `second_verbal_score`=`second_verbal_score`+#{verbalScore, jdbcType=INTEGER},
+        `second_ir_score`=`second_ir_score`+#{irScore, jdbcType=INTEGER},
+      </if>
+    </trim>
+    WHERE `id` = #{id, jdbcType=VARCHAR}
+  </update>
+
   <!--
     用户练习-练习册列表: 用户端
   -->

+ 62 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/FaqRelationMapper.xml

@@ -0,0 +1,62 @@
+<?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.FaqRelationMapper">
+  <resultMap id="IdMap" type="com.qxgmat.data.dao.entity.Faq">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="id" jdbcType="INTEGER" property="id" />
+  </resultMap>
+  <sql id="Id_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    f.`id`
+  </sql>
+
+  <!--用户提问列表-->
+  <select id="listWithUser" resultMap="IdMap">
+    select
+    <include refid="Id_Column_List" />
+    from `faq` f
+    left join `user` u on u.`id` = f.`user_id`
+      <if test="userId != null">
+        and f.`user_id` = #{userId,jdbcType=VARCHAR}
+      </if>
+      <if test="max != null">
+        and u.`total_money` &lt; ${max}
+      </if>
+      <if test="min != null">
+        and u.`total_money` &gt; ${min}
+      </if>
+    where 1
+    <if test="user != null">
+      and
+      <if test="user">
+        u.`id` &gt; 0
+      </if>
+      <if test="!user">
+        f.`user_id` = 0
+      </if>
+    </if>
+    <if test="userId != null">
+      and u.`id` &gt; 0
+    </if>
+    <if test="channel != null">
+      and f.`channel` = #{channel,jdbcType=VARCHAR}
+    </if>
+    <if test="position != null">
+      and f.`position` = #{position,jdbcType=VARCHAR}
+    </if>
+    <if test="answerStatus != null">
+      and f.`answer_status` = #{answerStatus,jdbcType=INTEGER}
+    </if>
+    <if test="isSpecial != null">
+      and f.`is_special` = #{isSpecial,jdbcType=INTEGER}
+    </if>
+    <if test="isShow != null">
+      and f.`is_show` =#{is_show,jdbcType=VARCHAR}
+    </if>
+    order by ${order} ${direction}
+  </select>
+</mapper>

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

@@ -20,7 +20,7 @@
     <trim prefix="set" suffixOverrides=",">
       `order`#{flag}1
     </trim>
-    WHERE `course_id` = #{courseId,jdbcType=VARCHAR} and `order` #{direction} #{order,jdbcType=INT}
+    WHERE `course_id` = #{courseId,jdbcType=VARCHAR} and `order` #{direction} #{order,jdbcType=INTEGER}
   </update>
 
   <!--用户提问列表-->
@@ -49,10 +49,10 @@
     c.`id` &gt; 0
     and u.`id` &gt; 0
     <if test="answerStatus != null">
-      and ua.`answer_status` = #{answerStatus,jdbcType=INT}
+      and ua.`answer_status` = #{answerStatus,jdbcType=INTEGER}
     </if>
     <if test="showStatus != null">
-      and ua.`show_status` = #{showStatus,jdbcType=INT}
+      and ua.`show_status` = #{showStatus,jdbcType=INTEGER}
     </if>
     order by ${order} ${direction}
   </select>

+ 8 - 5
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml

@@ -20,7 +20,7 @@
     <trim prefix="set" suffixOverrides=",">
       `order`#{flag}1
     </trim>
-    WHERE `question_id` = #{questionId,jdbcType=VARCHAR} and `order` #{direction} #{order,jdbcType=INT}
+    WHERE `question_id` = #{questionId,jdbcType=VARCHAR} and `order` #{direction} #{order,jdbcType=INTEGER}
   </update>
 
   <!--用户提问列表-->
@@ -48,16 +48,19 @@
       and ua.`target` = #{target,jdbcType=VARCHAR}
     </if>
     <if test="answerStatus != null">
-      and ua.`answer_status` = #{answerStatus,jdbcType=INT}
+      and ua.`answer_status` = #{answerStatus,jdbcType=INTEGER}
     </if>
     <if test="showStatus != null">
-      and ua.`show_status` = #{showStatus,jdbcType=INT}
+      and ua.`show_status` = #{showStatus,jdbcType=INTEGER}
+    </if>
+    <if test="askModule != null">
+      and ua.`ask_module` =#{askModule,jdbcType=VARCHAR}
     </if>
     <if test="questionModule != null">
-      and ua.`questionModule` =#{questionModule,jdbcType=VARCHAR}
+      and ua.`question_module` =#{questionModule,jdbcType=VARCHAR}
     </if>
     <if test="questionType != null">
-      and q.`questionType` =#{questionType,jdbcType=VARCHAR}
+      and q.`question_type` =#{questionType,jdbcType=VARCHAR}
     </if>
     <if test="hasRecord != null">
       <if test="hasRecord">

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

@@ -31,10 +31,26 @@
     <!--
       WARNING - @mbg.generated
     -->
-    ur.`id`
+    ucr.`id`
   </sql>
 
   <!--
+    用户最后一次
+    https://blog.csdn.net/t_1007/article/details/52369261
+  -->
+  <select id="listLast" resultMap="IdMap">
+    select
+    SUBSTRING_INDEX(GROUP_CONCAT(ucr.`id` ORDER BY ucr.`create_time` desc),',',1) as `id`
+    from `user_course_record` ucr
+    where
+    ucr.`record_id` IN
+    <foreach collection="recordIds" item="item" index="index" open="(" close=")" separator=",">
+      #{item}
+    </foreach>
+    group by ucr.`record_id`
+  </select>
+
+  <!--
     用户听课记录统计
   -->
   <select id="stat" resultMap="studyMap">

+ 14 - 3
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserFeedbackErrorRelationMapper.xml

@@ -11,12 +11,14 @@
     <!--
       WARNING - @mbg.generated
     -->
-    ua.`id`
+    uf.`id`
   </sql>
 
   <!--用户提问列表-->
   <select id="listAdmin" resultMap="IdMap">
-    <bind name="keywordLike" value="'%' + keyword + '%'" />
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user_feedback_error` uf
@@ -38,8 +40,17 @@
     <if test="module != null">
       and uf.`module` = #{module,jdbcType=VARCHAR}
     </if>
+    <if test="questionType != null">
+      and uf.`question_type` = #{questionType,jdbcType=VARCHAR}
+    </if>
+    <if test="target != null">
+      and uf.`target` = #{target,jdbcType=VARCHAR}
+    </if>
+    <if test="moduleId != null">
+      and uf.`module_id` = #{moduleId,jdbcType=VARCHAR}
+    </if>
     <if test="status != null">
-      and uf.`status` = #{status,jdbcType=INT}
+      and uf.`status` = #{status,jdbcType=INTEGER}
     </if>
     order by ${order} ${direction}
   </select>

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

@@ -26,10 +26,10 @@
   -->
   <select id="groupByTime" resultMap="NumberMap">
     select
-    count(uor.`id`) as `number`, uor.`no` as `id`
+    count(uor.`id`) as `number`, uor.`time_id` as `id`
     from `user_order_record` uor
     where
-    uor.`no` IN
+    uor.`time_id` IN
     <foreach collection="ids" item="item" index="index" open="(" close=")" separator=",">
       #{item}
     </foreach>

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

@@ -61,7 +61,9 @@
     购买过课程的用户
   -->
   <select id="listByCourse" resultMap="IdMap">
-    <bind name="keywordLike" value="'%' + keyword + '%'" />
+    <if test="keyword != null">
+      <bind name="keywordLike" value="'%' + keyword + '%'" />
+    </if>
     select
     <include refid="Id_Column_List" />
     from `user` u

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

@@ -32,7 +32,7 @@
       and uf.`target` = #{target,jdbcType=VARCHAR}
     </if>
     <if test="status != null">
-      and uf.`status` = #{status,jdbcType=INT}
+      and uf.`status` = #{status,jdbcType=INTEGER}
     </if>
     order by ${order} ${direction}
   </select>

+ 0 - 17
server/gateway-api/src/main/java/com/qxgmat/controller/admin/AdController.java

@@ -1,26 +1,9 @@
 package com.qxgmat.controller.admin;
 
-import com.github.pagehelper.Page;
-import com.nuliji.tools.PageMessage;
-import com.nuliji.tools.Response;
-import com.nuliji.tools.ResponseHelp;
-import com.nuliji.tools.Transform;
-import com.qxgmat.data.dao.entity.Ad;
-import com.qxgmat.dto.admin.request.AdDto;
-import com.qxgmat.dto.admin.response.AdListDto;
-import com.qxgmat.service.inline.AdService;
-import com.qxgmat.service.inline.ManagerLogService;
 import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiOperation;
-import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.http.MediaType;
-import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpSession;
-import java.util.List;
-
 @RestController("AdminAdController")
 @RequestMapping("/admin/ad")
 @Api(tags = "广告接口", description = "广告相关", produces = MediaType.APPLICATION_JSON_VALUE)

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

@@ -90,6 +90,9 @@ public class CourseController {
     private UserOrderRecordService userOrderRecordService;
 
     @Autowired
+    private UserCourseRecordService userCourseRecordService;
+
+    @Autowired
     private CourseExtendService courseExtendService;
 
     @Autowired
@@ -601,7 +604,7 @@ public class CourseController {
         entity.setOrderId(0);
         entity.setProductId(dto.getCourseId());
         entity.setTeacherId(dto.getTeacherId());
-        entity.setSource("offline");
+        entity.setSource(RecordSource.BACKEND.key);
         // 预约后开通: 有效期开通后计算
         orderFlowService.addRecord(entity);
 
@@ -674,7 +677,7 @@ public class CourseController {
         if (ids != null && ids.length > 0){
             p = userOrderRecordService.select(ids);
         }else{
-            p = userOrderRecordService.listWithStudyAdmin(page, size, new String[]{courseModule}, structId, courseId, userId, teacher, order, DirectionStatus.ValueOf(direction));
+            p = userOrderRecordService.listWithStudyAdmin(page, size, courseModule != null ? new String[]{courseModule} : null, structId, courseId, userId, teacher, order, DirectionStatus.ValueOf(direction));
         }
         List<UserCourseStudyRecordInfoDto> pr = Transform.convert(p, UserCourseStudyRecordInfoDto.class);
 
@@ -696,9 +699,17 @@ public class CourseController {
         Map teacherMap = Transform.getMap(teacherList, CourseTeacher.class,"id", "realname");
         Transform.combine(pr, teacherMap, UserCourseStudyRecordInfoDto.class, "teacherId", "teacher");
 
+        // 学习记录
+        Collection recordIds = Transform.getIds(p, UserOrderRecord.class, "id");
+        List<UserCourseRecord> userCourseRecordList = userCourseRecordService.listWithLast(recordIds);
+        Map recordMap = Transform.getMap(userCourseRecordList, UserCourseRecord.class,"recordId", "createTime");
+        Transform.combine(pr, recordMap, UserCourseStudyRecordInfoDto.class, "id", "lastTime");
+
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+
+
     @RequestMapping(value = "/ask/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "修改提问信息", httpMethod = "PUT")
     public Response<Boolean> edit(@RequestBody @Validated UserAskCourseDto dto, HttpServletRequest request) {

+ 10 - 6
server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java

@@ -16,13 +16,10 @@ import com.qxgmat.dto.admin.response.QuestionDetailDto;
 import com.qxgmat.dto.admin.response.UserAskQuestionDetailDto;
 import com.qxgmat.dto.admin.response.UserAskQuestionListDto;
 import com.qxgmat.help.ShiroHelp;
-import com.qxgmat.service.inline.ExercisePaperService;
+import com.qxgmat.service.UserQuestionService;
+import com.qxgmat.service.inline.*;
 import com.qxgmat.service.ManagerService;
 import com.qxgmat.service.UsersService;
-import com.qxgmat.service.inline.ManagerLogService;
-import com.qxgmat.service.inline.QuestionNoService;
-import com.qxgmat.service.inline.QuestionService;
-import com.qxgmat.service.inline.UserAskQuestionService;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.slf4j.Logger;
@@ -67,6 +64,12 @@ public class QuestionController {
     @Autowired
     private UsersService usersService;
 
+    @Autowired
+    private UserQuestionService userQuestionService;
+
+    @Autowired
+    private UserReportService userReportService;
+
     @RequestMapping(value = "/add", method = RequestMethod.POST)
     @ApiOperation(value = "添加题目", httpMethod = "POST")
     public Response<Question> add(@RequestBody @Validated QuestionDto dto, HttpServletRequest request) {
@@ -227,6 +230,7 @@ public class QuestionController {
     public Response<PageMessage<UserAskQuestionListDto>> listAsk(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String askModule,
             @RequestParam(required = false) String questionType,
             @RequestParam(required = false) String questionModule,
             @RequestParam(required = false) Number userId,
@@ -239,7 +243,7 @@ public class QuestionController {
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserAskQuestion> p = userAskQuestionService.listWithUser(page, size, questionType, questionModule, userId, questionNoId, AskTarget.ValueOf(target), AskStatus.ValueOf(answerStatus), showStatus, MoneyRange.ValueOf(moneyRang), hasRecord, order, DirectionStatus.ValueOf(direction));
+        Page<UserAskQuestion> p = userAskQuestionService.listWithUser(page, size, askModule, questionType, questionModule, userId, questionNoId, AskTarget.ValueOf(target), AskStatus.ValueOf(answerStatus), showStatus, MoneyRange.ValueOf(moneyRang), hasRecord, order, DirectionStatus.ValueOf(direction));
         List<UserAskQuestionListDto> pr = Transform.convert(p, UserAskQuestionListDto.class);
 
         // 绑定题目

+ 58 - 11
server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java

@@ -4,13 +4,16 @@ import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.*;
 import com.qxgmat.data.constants.enums.SettingKey;
-import com.qxgmat.data.constants.enums.module.InsideModule;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.entity.*;
+import com.qxgmat.dto.admin.extend.InfoExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 import com.qxgmat.dto.admin.request.*;
-import com.qxgmat.dto.admin.response.AdListDto;
+import com.qxgmat.dto.admin.response.AdInfoDto;
+import com.qxgmat.dto.admin.response.CommentInfoDto;
+import com.qxgmat.dto.admin.response.FaqInfoDto;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.UsersService;
 import com.qxgmat.service.inline.*;
@@ -38,6 +41,7 @@ import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
+import java.util.stream.Collectors;
 
 
 @RestController("AdminSettingController")
@@ -75,6 +79,12 @@ public class SettingController {
     @Autowired
     private UsersService usersService;
 
+    @Autowired
+    private CourseService courseService;
+
+    @Autowired
+    private CourseDataService courseDataService;
+
     @RequestMapping(value = "/index", method = RequestMethod.PUT)
     @ApiOperation(value = "修改首页配置", httpMethod = "PUT")
     private Response<Boolean> editIndex(@RequestBody @Validated JSONObject dto){
@@ -424,7 +434,7 @@ public class SettingController {
 
     @RequestMapping(value = "/comment/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取评价列表", httpMethod = "GET")
-    private Response<PageMessage<CommentDto>> listComment(
+    private Response<PageMessage<CommentInfoDto>> listComment(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) Boolean user,
@@ -432,17 +442,31 @@ public class SettingController {
             @RequestParam(required = false) String position,
             @RequestParam(required = false) Integer userId,
             @RequestParam(required = false) Boolean isSpecial,
+            @RequestParam(required = false) Boolean isShow,
+            @RequestParam(required = false) Integer moneyRang,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction
     ){
-        Page<Comment> p = commentService.listAdmin(page, size, user, channel, position, userId, isSpecial);
-        List<CommentDto> pr = Transform.convert(p, CommentDto.class);
+        Page<Comment> p = commentService.listAdmin(page, size, user, channel, position, userId, isSpecial, isShow, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
+        List<CommentInfoDto> pr = Transform.convert(p, CommentInfoDto.class);
 
         // 绑定用户
-        Collection userIds = Transform.getIds(p, UserAskQuestion.class, "userId");
+        Collection userIds = Transform.getIds(p, Comment.class, "userId");
         List<User> userList = usersService.select(userIds);
         Transform.combine(pr, userList, CommentDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
 
+        // 绑定课程
+        List<CommentInfoDto> prCourse = pr.stream().filter((row)-> row.getChannel().equals("course-video")).collect(Collectors.toList());
+        Collection courseIds = Transform.getIds(prCourse, CommentInfoDto.class, "position");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(prCourse, courseList, CommentInfoDto.class, "position", "positionDetail", Course.class, "id", InfoExtendDto.class);
+
+        // 绑定资料
+        List<CommentInfoDto> prData = pr.stream().filter((row)-> row.getChannel().equals("course_data")).collect(Collectors.toList());
+        Collection dataIds = Transform.getIds(prData, CommentInfoDto.class, "position");
+        List<CourseData> dataList = courseDataService.select(dataIds);
+        Transform.combine(prData, dataList, CommentInfoDto.class, "position", "positionDetail", CourseData.class, "id", InfoExtendDto.class);
+
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
@@ -496,19 +520,42 @@ public class SettingController {
 
     @RequestMapping(value = "/faq/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取faq列表", httpMethod = "GET")
-    private Response<PageMessage<Faq>> listFaq(
+    private Response<PageMessage<FaqInfoDto>> listFaq(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) Boolean user,
             @RequestParam(required = false) String channel,
             @RequestParam(required = false) String position,
+            @RequestParam(required = false) Integer userId,
             @RequestParam(required = false) Integer answerStatus,
+            @RequestParam(required = false) Boolean isShow,
             @RequestParam(required = false) Boolean isSpecial,
+            @RequestParam(required = false) Integer moneyRang,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction
     ){
-        Page<Faq> p = faqService.listAdmin(page, size, user, channel, position, answerStatus, isSpecial);
-        return ResponseHelp.success(p, page, size, p.getTotal());
+        Page<Faq> p = faqService.listAdmin(page, size, user, channel, position, userId, answerStatus, isSpecial, isShow, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
+        List<FaqInfoDto> pr = Transform.convert(p, FaqInfoDto.class);
+
+        // 绑定用户
+        Collection userIds = Transform.getIds(p, Faq.class, "userId");
+        List<User> userList = usersService.select(userIds);
+        Transform.combine(pr, userList, CommentDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+
+        // 绑定position
+        // 绑定课程
+        List<FaqInfoDto> prCourse = pr.stream().filter((row)-> row.getChannel().equals("course-video")).collect(Collectors.toList());
+        Collection courseIds = Transform.getIds(prCourse, FaqInfoDto.class, "position");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(prCourse, courseList, FaqInfoDto.class, "position", "positionDetail", Course.class, "id", InfoExtendDto.class);
+
+        // 绑定资料
+        List<FaqInfoDto> prData = pr.stream().filter((row)-> row.getChannel().equals("course_data")).collect(Collectors.toList());
+        Collection dataIds = Transform.getIds(prData, FaqInfoDto.class, "position");
+        List<CourseData> dataList = courseDataService.select(dataIds);
+        Transform.combine(prData, dataList, FaqInfoDto.class, "position", "positionDetail", CourseData.class, "id", InfoExtendDto.class);
+
+        return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
     @RequestMapping(value = "/message/add", method = RequestMethod.POST)
@@ -624,7 +671,7 @@ public class SettingController {
 
     @RequestMapping(value = "/ad/list", method = RequestMethod.GET)
     @ApiOperation(value = "广告列表", httpMethod = "GET")
-    public Response<PageMessage<AdListDto>> list(
+    public Response<PageMessage<AdInfoDto>> list(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) String channel,
@@ -633,7 +680,7 @@ public class SettingController {
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
         Page<Ad> p = adService.list(page, size, channel, position, order, DirectionStatus.ValueOf(direction));
-        List<AdListDto> pr = Transform.convert(p, AdListDto.class);
+        List<AdInfoDto> pr = Transform.convert(p, AdInfoDto.class);
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 

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

@@ -46,6 +46,7 @@ import java.util.Collection;
 import java.util.Date;
 import java.util.List;
 import java.util.Map;
+import java.util.stream.Collectors;
 
 @RestController("AdminUserController")
 @RequestMapping("/admin/user")
@@ -59,6 +60,15 @@ public class UserController {
     private ManagerLogService managerLogService;
 
     @Autowired
+    private CourseService courseService;
+
+    @Autowired
+    private CourseNoService courseNoService;
+
+    @Autowired
+    private CourseDataService courseDataService;
+
+    @Autowired
     private QuestionService questionService;
 
     @Autowired
@@ -130,6 +140,12 @@ public class UserController {
     @Autowired
     private UserAbnormalService userAbnormalService;
 
+    @Autowired
+    private UserCourseProgressService userCourseProgressService;
+
+    @Autowired
+    private UserCourseRecordService userCourseRecordService;
+
     @RequestMapping(value = "/token", method = RequestMethod.GET)
     @ApiOperation(value = "获取用户token", httpMethod = "GET")
     public Response<String> token(@RequestParam int id, HttpSession session) {
@@ -322,13 +338,25 @@ public class UserController {
             @RequestParam(required = false) String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserOrderRecord> p = userOrderRecordService.listAdmin(page, size, userId, ProductType.ValueOf(productType), productId, ServiceKey.ValueOf(service), needMoney,needPackage, order, DirectionStatus.ValueOf(direction));
+        Page<UserOrderRecord> p = userOrderRecordService.listAdmin(page, size, orderId, userId, ProductType.ValueOf(productType), productId, ServiceKey.ValueOf(service), needMoney,needPackage, order, DirectionStatus.ValueOf(direction));
         List<UserOrderRecordListDto> pr = Transform.convert(p, UserOrderRecordListDto.class);
 
         // 绑定用户
         Collection userIds = Transform.getIds(p, UserOrderRecord.class, "userId");
         List<User> userList = usersService.select(userIds);
-        Transform.combine(pr, userList, UserServiceRecordInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+        Transform.combine(pr, userList, UserOrderRecordListDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+
+        // 绑定课程
+        List<UserOrderRecordListDto> prCourse = pr.stream().filter((row)-> row.getProductType().equals(ProductType.COURSE.key)).collect(Collectors.toList());
+        Collection courseIds = Transform.getIds(prCourse, UserOrderRecordListDto.class, "productId");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(prCourse, courseList, UserOrderRecordListDto.class, "productId", "course", Course.class, "id", CourseExtendDto.class);
+
+        // 绑定资料
+        List<UserOrderRecordListDto> prData = pr.stream().filter((row)-> row.getProductType().equals(ProductType.DATA.key)).collect(Collectors.toList());
+        Collection dataIds = Transform.getIds(prData, UserOrderRecordListDto.class, "productId");
+        List<CourseData> dataList = courseDataService.select(dataIds);
+        Transform.combine(prData, dataList, UserOrderRecordListDto.class, "productId", "data", CourseData.class, "id", CourseDataExtendDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
@@ -436,6 +464,9 @@ public class UserController {
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) String module,
+            @RequestParam(required = false) String questionType,
+            @RequestParam(required = false) String target,
+            @RequestParam(required = false) Integer moduleId,
             @RequestParam(required = false) Integer userId,
             @RequestParam(required = false) Integer status,
             @RequestParam(required = false) String keyword,
@@ -443,7 +474,7 @@ public class UserController {
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserFeedbackError> p = userFeedbackErrorService.listAdmin(page, size, FeedbackModule.ValueOf(module), FeedbackStatus.ValueOf(status), keyword, userId, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
+        Page<UserFeedbackError> p = userFeedbackErrorService.listAdmin(page, size, FeedbackModule.ValueOf(module), FeedbackStatus.ValueOf(status), questionType, target, moduleId, keyword, userId, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
         List<UserFeedbackErrorInfoDto> pr = Transform.convert(p, UserFeedbackErrorInfoDto.class);
 
         // 绑定用户
@@ -597,18 +628,68 @@ public class UserController {
         }
         List<UserCourseAppointmentInfoDto> pr = Transform.convert(p, UserCourseAppointmentInfoDto.class);
 
-        Collection paperIds = Transform.getIds(p, UserCourseAppointment.class, "paperId");
-        List<UserPaper> userPaperList = userPaperService.select(paperIds);
+        // 绑定作业记录
+        Collection appointmentIds = Transform.getIds(p, UserCourseAppointment.class, "id");
+        List<PreviewAssign> previewAssignList = previewAssignService.listWithAppointment(appointmentIds);
+        Map previewAssignMap = Transform.getMap(previewAssignList, PreviewAssign.class, "courseAppointment", "id");
+        Collection assignIds = Transform.getIds(previewAssignList, PreviewAssign.class, "id");
+        List<UserPaper> userPaperList=userPaperService.listWithAppointment(assignIds);
+        Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
+        for(UserCourseAppointmentInfoDto dto : pr){
+            dto.setPaperId((Integer)userPaperMap.get(previewAssignMap.get(dto.getId())));
+        }
         Transform.combine(pr, userPaperList, UserCourseAppointmentInfoDto.class, "paperId", "userPaper", UserPaper.class, "id", UserPaperExtendDto.class);
 
         // 获取最后一次作业结果
-        List<UserReport> reportList = userReportService.listWithLater(paperIds);
-        Map reportMap = Transform.getMap(reportList, UserReport.class, "id");
-        Transform.combine(pr, reportMap, UserCourseAppointmentInfoDto.class, "paperId", "reportId");
+        Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
+        List<UserReport> reportList = userReportService.listWithLast(paperIds);
+        Transform.combine(pr, reportList, UserCourseAppointmentInfoDto.class, "paperId", "userReport", UserReport.class, "paperId", UserReportExtendDto.class);
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/course/record/all", method = RequestMethod.GET)
+    @ApiOperation(value = "课程学习列表", httpMethod = "GET")
+    public Response<List<UserCourseProgressInfoDto>> allCourseRecord(
+            @RequestParam(required = false) Integer recordId,
+            HttpSession session) {
+        UserOrderRecord record = userOrderRecordService.get(recordId);
+        Integer courseId = record.getProductId();
+        Integer userId = record.getUserId();
+        List<UserCourseProgress> p = userCourseProgressService.listCourse(recordId, courseId);
+
+        List<UserCourseProgressInfoDto> pr = Transform.convert(p, UserCourseProgressInfoDto.class);
+
+        // 绑定课时
+        Collection courseNoIds = Transform.getIds(p, UserCourseProgress.class, "courseNoId");
+        List<CourseNo> courseNoList = courseNoService.select(courseNoIds);
+        Transform.combine(pr, courseNoList, UserCourseProgressInfoDto.class, "courseNoId", "courseNo", CourseNo.class, "id", CourseNoExtendDto.class);
+
+        // 绑定所有学习记录
+        Map<Integer, List<UserCourseRecord>> recordMap = userCourseRecordService.groupByCourse(recordId, courseNoIds);
+        for(UserCourseProgressInfoDto dto : pr){
+            dto.setRecords(recordMap.getOrDefault(dto.getCourseNoId(), null));
+        }
+
+        // 绑定预习作业
+        List<PreviewAssign> previewAssignList = previewAssignService.listByCourseNos(courseId, courseNoIds);
+        Map previewAssignMap = Transform.getMap(previewAssignList, PreviewAssign.class, "courseNo", "id");
+        Collection assignIds = Transform.getIds(previewAssignList, PreviewAssign.class, "id");
+        List<UserPaper> userPaperList = userPaperService.listWithCourse(userId, assignIds);
+        Map userPaperMap = Transform.getMap(userPaperList, UserPaper.class, "originId", "id");
+        for(UserCourseProgressInfoDto dto : pr){
+            dto.setPaperId((Integer)userPaperMap.get(previewAssignMap.get(dto.getId())));
+        }
+        Transform.combine(pr, userPaperList, UserCourseProgressInfoDto.class, "paperId", "userPaper", UserPaper.class, "id", UserPaperExtendDto.class);
+
+        // 获取最后一次作业结果
+        Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
+        List<UserReport> reportList = userReportService.listWithLast(paperIds);
+        Transform.combine(pr, reportList, UserCourseProgressInfoDto.class, "paperId", "userReport", UserReport.class, "paperId", UserReportExtendDto.class);
+
+        return ResponseHelp.success(pr);
+    }
+
     @RequestMapping(value = "/invoice/finish", method = RequestMethod.PUT)
     @ApiOperation(value = "开发票", httpMethod = "PUT")
     public Response<Boolean> finishData(

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

@@ -8,10 +8,7 @@ import com.nuliji.tools.exception.SystemException;
 import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.SettingKey;
-import com.qxgmat.data.constants.enums.module.FeedbackModule;
-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.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.dao.entity.*;
@@ -158,6 +155,12 @@ public class MyController {
     private UserPaperQuestionService userPaperQuestionService;
 
     @Autowired
+    private UserOrderService userOrderService;
+
+    @Autowired
+    private UserOrderRecordService userOrderRecordService;
+
+    @Autowired
     private QuestionFlowService questionFlowService;
 
     @Autowired
@@ -941,12 +944,16 @@ public class MyController {
 
         UserQuestion userQuestion = userQuestionService.get(dto.getUserQuestionId());
         UserReport userReport = userReportService.get(userQuestion.getReportId());
+        entity.setAskModule(AskModule.ValueOf(userReport.getPaperModule()).key);
+
         PaperOrigin origin = PaperOrigin.ValueOf(userReport.getPaperOrigin());
         Integer recordId = questionFlowService.questionRelationCourse(user.getId(), origin == PaperOrigin.PREVIEW ? userReport.getOriginId() : null, QuestionType.ValueOf(question.getQuestionType()));
 
         if (recordId != null){
             // 绑定提问权限
             entity.setRecordId(recordId);
+            UserOrderRecord record = userOrderRecordService.get(recordId);
+            entity.setAskTime(record.getAskTime());
         }else{
             // todo 判断题目是否有提问权限
         }
@@ -966,6 +973,8 @@ public class MyController {
         if (userCourse != null){
             // 绑定提问权限
             entity.setRecordId(userCourse.getRecordId());
+            UserOrderRecord record = userOrderRecordService.get(userCourse.getRecordId());
+            entity.setAskTime(record.getAskTime());
         }else{
             throw new ParameterException("课程需开通后才能提问");
         }
@@ -982,6 +991,13 @@ public class MyController {
         entity.setUserId(user.getId());
         entity.setModule(FeedbackModule.QUESTION.key);
         entity.setStatus(0);
+
+        UserQuestion userQuestion = userQuestionService.get(dto.getUserQuestionId());
+        Question question = questionService.get(userQuestion.getQuestionId());
+        entity.setQuestionType(question.getQuestionType());
+        entity.setModuleId(userQuestion.getQuestionId());
+        entity.setQuestionModule(userQuestion.getQuestionModule());
+        entity.setQuestionNoId(userQuestion.getQuestionNoId());
         userFeedbackErrorService.add(entity);
 
         return ResponseHelp.success(true);

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

@@ -202,7 +202,7 @@ public class QuestionController {
 
                     // 获取最后一次作业结果
                     Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
-                    List<UserReport> reportList = userReportService.listWithLater(paperIds);
+                    List<UserReport> reportList = userReportService.listWithLast(paperIds);
                     Transform.combine(childrenDtos, reportList, UserExerciseGroupExtendDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
                 }
                 dto.setChildren(childrenDtos);
@@ -289,7 +289,7 @@ public class QuestionController {
 
             // 获取最后一次作业结果
             Collection paperIds = Transform.getIds(paperList, UserPaper.class, "id");
-            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            List<UserReport> reportList = userReportService.listWithLast(paperIds);
             Transform.combine(pr, reportList, UserExercisePaperDto.class, "id", "report", UserReport.class, "paperId", UserReportExtendDto.class);
         }
 
@@ -393,15 +393,6 @@ public class QuestionController {
 
         List<UserExaminationPaperDto> pr = Transform.convert(p, UserExaminationPaperDto.class);
 
-        // 获取试卷统计信息
-        Map<Integer, Integer[]> questionNoIdsMap = new HashMap<>();
-        for(ExaminationPaper paper : p){
-            questionNoIdsMap.put(paper.getId(), paper.getQuestionNoIds());
-        }
-        Map statMap = questionNoService.statPaperMap(questionNoIdsMap);
-        Transform.combine(pr, statMap, UserExercisePaperDto.class, "id", "stat");
-
-
         if (user != null){
             // 获取做题记录
             Collection ids = Transform.getIds(p, ExaminationPaper.class, "id");
@@ -419,7 +410,7 @@ public class QuestionController {
 
             // 获取最后一次结果
             Collection paperIds = Transform.getIds(paperList, UserPaper.class, "id");
-            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            List<UserReport> reportList = userReportService.listWithLast(paperIds);
             Transform.combine(pr, reportList, UserExaminationPaperDto.class, "id", "report", UserReport.class, "paperId", UserReportExtendDto.class);
 
             if (serviceKey == ServiceKey.QX_CAT && user.getQxCat() > 0){
@@ -434,7 +425,7 @@ public class QuestionController {
 
                     // 获取最后一次结果
                     Collection prevPaperIds = Transform.getIds(prevPaperList, UserPaper.class, "id");
-                    List<UserReport> prevReportList = userReportService.listWithLaterNoReset(prevPaperIds);
+                    List<UserReport> prevReportList = userReportService.listWithLastNoReset(prevPaperIds);
                     Transform.combine(pr, prevReportList, UserExaminationPaperDto.class, "id", "prevReport", UserReport.class, "paperId", UserReportExtendDto.class);
                 }
             }
@@ -623,6 +614,14 @@ public class QuestionController {
     @ApiOperation(value = "开始: 模考", notes = "提交考试设置", httpMethod = "POST")
     public Response<UserReportBaseDto> startExamination(@RequestBody @Validated ExaminationStartDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
+        // 判断是否是cat模考,并且有模考权限
+        ExaminationPaper examinationPaper = examinationPaperService.get(dto.getPaperId());
+        if(examinationService.isCat(examinationPaper)){
+            UserService userService = userServiceService.getService(user.getId(), ServiceKey.QX_CAT);
+            if (userService== null){
+                throw new ParameterException("请先开通模考");
+            }
+        }
         JSONObject setting = new JSONObject();
         setting.put("disorder", dto.getDisorder());
         setting.put("order", dto.getOrder());

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

@@ -1,6 +1,5 @@
 package com.qxgmat.controller.api;
 
-import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.nuliji.tools.Response;
 import com.nuliji.tools.ResponseHelp;
@@ -10,7 +9,6 @@ import com.qxgmat.data.constants.enums.SettingKey;
 import com.qxgmat.data.constants.enums.logic.SentenceLogic;
 import com.qxgmat.data.constants.enums.module.PaperOrigin;
 import com.qxgmat.data.dao.entity.*;
-import com.qxgmat.data.relation.entity.UserSentencePaperRelation;
 import com.qxgmat.dto.extend.UserPaperBaseExtendDto;
 import com.qxgmat.dto.extend.UserReportExtendDto;
 import com.qxgmat.dto.request.*;
@@ -26,7 +24,6 @@ import com.qxgmat.service.inline.*;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.transaction.annotation.Transactional;
 import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 
@@ -224,7 +221,7 @@ public class SentenceController
 
             // 获取最后一次作业结果
             Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
-            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            List<UserReport> reportList = userReportService.listWithLast(paperIds);
             Transform.combine(pr, reportList, UserSentencePaperDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
         }
 

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

@@ -315,7 +315,7 @@ public class TextbookController
 
             // 获取最后一次作业结果
             Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
-            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            List<UserReport> reportList = userReportService.listWithLast(paperIds);
             Transform.combine(pr, reportList, UserTextbookPaperDto.class, "userPaperId", "report", UserReport.class, "paperId", UserReportExtendDto.class);
         }
 

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

@@ -0,0 +1,23 @@
+package com.qxgmat.dto.admin.extend;
+
+public class InfoExtendDto {
+    private Integer id;
+
+    private String title;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+}

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

@@ -15,6 +15,8 @@ public class UserPaperExtendDto {
 
     private Integer times;
 
+    private String paperModule;
+
     public Integer getId() {
         return id;
     }
@@ -46,4 +48,12 @@ public class UserPaperExtendDto {
     public void setUserId(Integer userId) {
         this.userId = userId;
     }
+
+    public String getPaperModule() {
+        return paperModule;
+    }
+
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
+    }
 }

+ 5 - 5
server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserReportExtendDto.java

@@ -10,7 +10,7 @@ public class UserReportExtendDto {
 
     private String title;
 
-    private Integer category;
+    private String paperModule;
 
     public Integer getId() {
         return id;
@@ -28,11 +28,11 @@ public class UserReportExtendDto {
         this.title = title;
     }
 
-    public Integer getCategory() {
-        return category;
+    public String getPaperModule() {
+        return paperModule;
     }
 
-    public void setCategory(Integer category) {
-        this.category = category;
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
     }
 }

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

@@ -16,7 +16,7 @@ public class UserCourseAppointmentDto {
 
     private Integer recordId;
 
-    private String channel;
+    private String cctalkChannel;
 
     private String title;
 
@@ -62,14 +62,6 @@ public class UserCourseAppointmentDto {
         this.recordId = recordId;
     }
 
-    public String getChannel() {
-        return channel;
-    }
-
-    public void setChannel(String channel) {
-        this.channel = channel;
-    }
-
     public String getTitle() {
         return title;
     }
@@ -117,4 +109,12 @@ public class UserCourseAppointmentDto {
     public void setIsFinish(Integer isFinish) {
         this.isFinish = isFinish;
     }
+
+    public String getCctalkChannel() {
+        return cctalkChannel;
+    }
+
+    public void setCctalkChannel(String cctalkChannel) {
+        this.cctalkChannel = cctalkChannel;
+    }
 }

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/AdListDto.java

@@ -4,7 +4,7 @@ import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.Ad;
 
 @Dto(entity = Ad.class)
-public class AdListDto {
+public class AdInfoDto {
 
     private Integer id;
 

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

@@ -1,122 +0,0 @@
-package com.qxgmat.dto.admin.response;
-
-import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.Comment;
-import com.qxgmat.data.dao.entity.UserFeedbackError;
-import com.qxgmat.dto.admin.extend.UserExtendDto;
-
-import java.util.Date;
-
-@Dto(entity = Comment.class)
-public class CommentDto {
-
-    private Integer id;
-
-    private UserExtendDto user;
-
-    private Integer userId;
-
-    private String nickname;
-
-    private String avatar;
-
-    private String channel;
-
-    private String position;
-
-    private Integer isSpecial;
-
-    private Integer isSystem;
-
-    private Date createTime;
-
-    private String content;
-
-    public Integer getId() {
-        return id;
-    }
-
-    public void setId(Integer id) {
-        this.id = id;
-    }
-
-    public UserExtendDto getUser() {
-        return user;
-    }
-
-    public void setUser(UserExtendDto user) {
-        this.user = user;
-    }
-
-    public Integer getUserId() {
-        return userId;
-    }
-
-    public void setUserId(Integer userId) {
-        this.userId = userId;
-    }
-
-    public String getNickname() {
-        return nickname;
-    }
-
-    public void setNickname(String nickname) {
-        this.nickname = nickname;
-    }
-
-    public String getAvatar() {
-        return avatar;
-    }
-
-    public void setAvatar(String avatar) {
-        this.avatar = avatar;
-    }
-
-    public String getChannel() {
-        return channel;
-    }
-
-    public void setChannel(String channel) {
-        this.channel = channel;
-    }
-
-    public String getPosition() {
-        return position;
-    }
-
-    public void setPosition(String position) {
-        this.position = position;
-    }
-
-    public Integer getIsSpecial() {
-        return isSpecial;
-    }
-
-    public void setIsSpecial(Integer isSpecial) {
-        this.isSpecial = isSpecial;
-    }
-
-    public Integer getIsSystem() {
-        return isSystem;
-    }
-
-    public void setIsSystem(Integer isSystem) {
-        this.isSystem = isSystem;
-    }
-
-    public Date getCreateTime() {
-        return createTime;
-    }
-
-    public void setCreateTime(Date createTime) {
-        this.createTime = createTime;
-    }
-
-    public String getContent() {
-        return content;
-    }
-
-    public void setContent(String content) {
-        this.content = content;
-    }
-}

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

@@ -0,0 +1,29 @@
+package com.qxgmat.dto.admin.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.Comment;
+import com.qxgmat.dto.admin.extend.InfoExtendDto;
+import com.qxgmat.dto.admin.extend.UserExtendDto;
+
+@Dto(entity = Comment.class)
+public class CommentInfoDto extends Comment {
+    private UserExtendDto user;
+
+    private InfoExtendDto positionDetail;
+
+    public InfoExtendDto getPositionDetail() {
+        return positionDetail;
+    }
+
+    public void setPositionDetail(InfoExtendDto positionDetail) {
+        this.positionDetail = positionDetail;
+    }
+
+    public UserExtendDto getUser() {
+        return user;
+    }
+
+    public void setUser(UserExtendDto user) {
+        this.user = user;
+    }
+}

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

@@ -0,0 +1,29 @@
+package com.qxgmat.dto.admin.response;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.Faq;
+import com.qxgmat.dto.admin.extend.InfoExtendDto;
+import com.qxgmat.dto.admin.extend.UserExtendDto;
+
+@Dto(entity = Faq.class)
+public class FaqInfoDto extends Faq {
+    private UserExtendDto user;
+
+    private InfoExtendDto positionDetail;
+
+    public InfoExtendDto getPositionDetail() {
+        return positionDetail;
+    }
+
+    public void setPositionDetail(InfoExtendDto positionDetail) {
+        this.positionDetail = positionDetail;
+    }
+
+    public UserExtendDto getUser() {
+        return user;
+    }
+
+    public void setUser(UserExtendDto user) {
+        this.user = user;
+    }
+}

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

@@ -28,6 +28,8 @@ public class UserAskCourseListDto {
 
     private CourseNoExtendDto courseNo;
 
+    private Integer askTime;
+
     private Integer answerStatus;
 
     private Integer showStatus;
@@ -121,4 +123,12 @@ public class UserAskCourseListDto {
     public void setCourseNo(CourseNoExtendDto courseNo) {
         this.courseNo = courseNo;
     }
+
+    public Integer getAskTime() {
+        return askTime;
+    }
+
+    public void setAskTime(Integer askTime) {
+        this.askTime = askTime;
+    }
 }

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

@@ -15,6 +15,8 @@ public class UserAskQuestionDetailDto {
 
     private String questionModule;
 
+    private String paperModule;
+
     private QuestionExtendDto question;
 
     private QuestionNoExtendDto questionNo;
@@ -138,4 +140,12 @@ public class UserAskQuestionDetailDto {
     public void setQuestionModule(String questionModule) {
         this.questionModule = questionModule;
     }
+
+    public String getPaperModule() {
+        return paperModule;
+    }
+
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
+    }
 }

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

@@ -21,6 +21,8 @@ public class UserAskQuestionListDto {
 
     private String questionModule;
 
+    private String paperModule;
+
     private QuestionExtendDto question;
 
     private QuestionNoExtendDto questionNo;
@@ -29,6 +31,8 @@ public class UserAskQuestionListDto {
 
     private ManagerExtendDto manager;
 
+    private Integer askTime;
+
     private Integer answerStatus;
 
     private Integer showStatus;
@@ -130,4 +134,20 @@ public class UserAskQuestionListDto {
     public void setQuestionModule(String questionModule) {
         this.questionModule = questionModule;
     }
+
+    public Integer getAskTime() {
+        return askTime;
+    }
+
+    public void setAskTime(Integer askTime) {
+        this.askTime = askTime;
+    }
+
+    public String getPaperModule() {
+        return paperModule;
+    }
+
+    public void setPaperModule(String paperModule) {
+        this.paperModule = paperModule;
+    }
 }

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

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

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

@@ -0,0 +1,66 @@
+package com.qxgmat.dto.admin.response;
+
+import com.alibaba.fastjson.JSONArray;
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserCourseAppointment;
+import com.qxgmat.data.dao.entity.UserCourseProgress;
+import com.qxgmat.data.dao.entity.UserCourseRecord;
+import com.qxgmat.dto.admin.extend.CourseNoExtendDto;
+import com.qxgmat.dto.admin.extend.UserPaperExtendDto;
+import com.qxgmat.dto.admin.extend.UserReportExtendDto;
+
+import java.util.Date;
+import java.util.List;
+
+@Dto(entity = UserCourseProgress.class)
+public class UserCourseProgressInfoDto extends UserCourseProgress {
+    private CourseNoExtendDto courseNo;
+
+    private List<UserCourseRecord> records;
+
+    private Integer paperId;
+
+    private UserPaperExtendDto userPaper;
+
+    private UserReportExtendDto userReport;
+
+    public List<UserCourseRecord> getRecords() {
+        return records;
+    }
+
+    public void setRecords(List<UserCourseRecord> records) {
+        this.records = records;
+    }
+
+    public CourseNoExtendDto getCourseNo() {
+        return courseNo;
+    }
+
+    public void setCourseNo(CourseNoExtendDto courseNo) {
+        this.courseNo = courseNo;
+    }
+
+    public Integer getPaperId() {
+        return paperId;
+    }
+
+    public void setPaperId(Integer paperId) {
+        this.paperId = paperId;
+    }
+
+    public UserPaperExtendDto getUserPaper() {
+        return userPaper;
+    }
+
+    public void setUserPaper(UserPaperExtendDto userPaper) {
+        this.userPaper = userPaper;
+    }
+
+    public UserReportExtendDto getUserReport() {
+        return userReport;
+    }
+
+    public void setUserReport(UserReportExtendDto userReport) {
+        this.userReport = userReport;
+    }
+}

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

@@ -19,6 +19,8 @@ public class UserCourseStudentRecordInfoDto {
 
     private CourseTeacherExtendDto teacher;
 
+    private Integer number;
+
     private String source;
 
     private Integer isUsed;
@@ -29,6 +31,8 @@ public class UserCourseStudentRecordInfoDto {
 
     private Date useEndTime;
 
+    private String cctalkName;
+
     public Integer getId() {
         return id;
     }
@@ -108,4 +112,20 @@ public class UserCourseStudentRecordInfoDto {
     public void setIsStop(Integer isStop) {
         this.isStop = isStop;
     }
+
+    public Integer getNumber() {
+        return number;
+    }
+
+    public void setNumber(Integer number) {
+        this.number = number;
+    }
+
+    public String getCctalkName() {
+        return cctalkName;
+    }
+
+    public void setCctalkName(String cctalkName) {
+        this.cctalkName = cctalkName;
+    }
 }

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

@@ -1,51 +0,0 @@
-package com.qxgmat.dto.admin.response;
-
-import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.UserPaper;
-import com.qxgmat.dto.admin.extend.PreviewPaperExtendDto;
-import com.qxgmat.dto.admin.extend.UserExtendDto;
-import com.qxgmat.dto.admin.extend.UserReportExtendDto;
-
-@Dto(entity = UserPaper.class)
-public class UserPreviewListDto {
-
-    private Integer id;
-
-    private UserExtendDto user;
-
-    private PreviewPaperExtendDto paper;
-
-    private UserReportExtendDto report;
-
-    public Integer getId() {
-        return id;
-    }
-
-    public void setId(Integer id) {
-        this.id = id;
-    }
-
-    public UserExtendDto getUser() {
-        return user;
-    }
-
-    public void setUser(UserExtendDto user) {
-        this.user = user;
-    }
-
-    public UserReportExtendDto getReport() {
-        return report;
-    }
-
-    public void setReport(UserReportExtendDto report) {
-        this.report = report;
-    }
-
-    public PreviewPaperExtendDto getPaper() {
-        return paper;
-    }
-
-    public void setPaper(PreviewPaperExtendDto paper) {
-        this.paper = paper;
-    }
-}

+ 9 - 9
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserFeedbackErrorDto.java

@@ -5,7 +5,7 @@ import com.qxgmat.data.dao.entity.UserFeedbackError;
 
 @Dto(entity = UserFeedbackError.class)
 public class UserFeedbackErrorDto {
-    private Integer moduleId;
+    private Integer userQuestionId;
 
     private String title;
 
@@ -15,14 +15,6 @@ public class UserFeedbackErrorDto {
 
     private String content;
 
-    public Integer getModuleId() {
-        return moduleId;
-    }
-
-    public void setModuleId(Integer moduleId) {
-        this.moduleId = moduleId;
-    }
-
     public String getPosition() {
         return position;
     }
@@ -54,4 +46,12 @@ public class UserFeedbackErrorDto {
     public void setTitle(String title) {
         this.title = title;
     }
+
+    public Integer getUserQuestionId() {
+        return userQuestionId;
+    }
+
+    public void setUserQuestionId(Integer userQuestionId) {
+        this.userQuestionId = userQuestionId;
+    }
 }

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

@@ -22,6 +22,16 @@ public class UserExaminationPaperDto {
 
     private Integer irScore;
 
+    private Integer secondTotalScore;
+
+    private Integer secondTotalTimes;
+
+    private Integer secondQuantScore;
+
+    private Integer secondVerbalScore;
+
+    private Integer secondIrScore;
+
     private UserPaperBaseExtendDto paper;
 
     private UserReportExtendDto report;
@@ -137,4 +147,44 @@ public class UserExaminationPaperDto {
     public void setIrScore(Integer irScore) {
         this.irScore = irScore;
     }
+
+    public Integer getSecondTotalScore() {
+        return secondTotalScore;
+    }
+
+    public void setSecondTotalScore(Integer secondTotalScore) {
+        this.secondTotalScore = secondTotalScore;
+    }
+
+    public Integer getSecondTotalTimes() {
+        return secondTotalTimes;
+    }
+
+    public void setSecondTotalTimes(Integer secondTotalTimes) {
+        this.secondTotalTimes = secondTotalTimes;
+    }
+
+    public Integer getSecondQuantScore() {
+        return secondQuantScore;
+    }
+
+    public void setSecondQuantScore(Integer secondQuantScore) {
+        this.secondQuantScore = secondQuantScore;
+    }
+
+    public Integer getSecondVerbalScore() {
+        return secondVerbalScore;
+    }
+
+    public void setSecondVerbalScore(Integer secondVerbalScore) {
+        this.secondVerbalScore = secondVerbalScore;
+    }
+
+    public Integer getSecondIrScore() {
+        return secondIrScore;
+    }
+
+    public void setSecondIrScore(Integer secondIrScore) {
+        this.secondIrScore = secondIrScore;
+    }
 }

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

@@ -63,7 +63,7 @@ public class UserPaperService extends AbstractService {
      * @return
      */
     public PageResult<UserPaper> list(int page, int size, Integer userId, PaperOrigin origin, Integer structId, String startTime, String endTime, String order, DirectionStatus direction){
-
+        // todo
         return new PageResult<>(null, 0);
     }
 
@@ -94,6 +94,39 @@ public class UserPaperService extends AbstractService {
     }
 
     /**
+     * 获取用户预约预习作业记录
+     * @param ids
+     * @return
+     */
+    public List<UserPaper> listWithAppointment(Collection ids){
+        if(ids == null || ids.size() == 0) return new ArrayList<>();
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("paperOrigin", PaperOrigin.PREVIEW.key)
+                        .andIn("originId", ids)
+        );
+        return select(userPaperMapper, example);
+    }
+
+    /**
+     * 获取用户预约预习作业记录
+     * @param ids
+     * @return
+     */
+    public List<UserPaper> listWithCourse(Integer userId, Collection ids){
+        if (ids == null || ids.size() == 0) return new ArrayList<>();
+        Example example = new Example(UserPaper.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("paperOrigin", PaperOrigin.PREVIEW.key)
+                        .andIn("originId", ids)
+        );
+        return select(userPaperMapper, example);
+    }
+
+    /**
      * 获取用户cat做题记录
      * @param userId
      * @param ids
@@ -101,6 +134,7 @@ public class UserPaperService extends AbstractService {
      * @return
      */
     public List<UserPaper> listWithCat(Integer userId, Collection ids, Integer no){
+        if (ids == null || ids.size() == 0) return new ArrayList<>();
         Example example = new Example(UserPaper.class);
         example.and(
                 example.createCriteria()
@@ -186,6 +220,7 @@ public class UserPaperService extends AbstractService {
      * @return
      */
     public Boolean reset(Collection ids, Integer userId){
+        if (ids == null || ids.size() == 0) return true;
         Example example = new Example(UserPaper.class);
         example.and(
                 example.createCriteria()
@@ -211,7 +246,7 @@ public class UserPaperService extends AbstractService {
      * @return
      */
     public Boolean removeByUsersAndPaper(Collection<Integer> userIds, PaperOrigin origin, Integer originId){
-        if(userIds.size() == 0) return false;
+        if(userIds == null || userIds.size() == 0) return false;
         Example example = new Example(UserPaper.class);
         example.and(
                 example.createCriteria()
@@ -230,7 +265,7 @@ public class UserPaperService extends AbstractService {
      * @return
      */
     public Boolean editByUsersAndPaper(UserPaper userPaper, Collection<Integer> userIds, PaperOrigin origin, Integer originId){
-        if(userIds.size() == 0) return false;
+        if(userIds == null || userIds.size() == 0) return false;
         Example example = new Example(UserPaper.class);
         example.and(
                 example.createCriteria()

+ 13 - 5
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java

@@ -7,7 +7,6 @@ import com.nuliji.tools.PageResult;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
-import com.qxgmat.data.constants.enums.QuestionDifficult;
 import com.qxgmat.data.constants.enums.QuestionSubject;
 import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.ServiceKey;
@@ -221,7 +220,7 @@ public class ExaminationService extends AbstractService {
             return false;
         }
         Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
-        List<UserReport> reportList = userReportService.listWithLater(paperIds);
+        List<UserReport> reportList = userReportService.listWithLast(paperIds);
         for(UserReport report: reportList){
             if(report.getIsFinish() == 0){
                 return false;
@@ -246,7 +245,7 @@ public class ExaminationService extends AbstractService {
         }
         Collection paperIds = Transform.getIds(userPaperList, UserPaper.class, "id");
         if(!force){
-            List<UserReport> reportList = userReportService.listWithLater(paperIds);
+            List<UserReport> reportList = userReportService.listWithLast(paperIds);
             for(UserReport report: reportList){
                 if(report.getIsFinish() == 0){
                     throw new ParameterException("未完成所有");
@@ -268,6 +267,11 @@ public class ExaminationService extends AbstractService {
         throw new SystemException("没有找到cat模考节点");
     }
 
+    public boolean isCat(ExaminationPaper paper){
+        ExaminationStruct struct = examinationStructService.get(paper.getStructTwo());
+        return struct.getExtend().equals(ServiceKey.QX_CAT.key);
+    }
+
     /**
      * 获取下一阶段难度分
      * @param currentLevel
@@ -546,10 +550,14 @@ public class ExaminationService extends AbstractService {
      */
     public List<QuestionDifficultRelation> randomList(List<QuestionDifficultRelation> all, Integer size){
         List<QuestionDifficultRelation> list = new ArrayList<>(size);
+        Set<Integer> indexSet = new HashSet<>();
         do{
             int index = rand.nextInt(all.size());
-            QuestionDifficultRelation target = all.get(index);
-            list.add(target);
+            if (!indexSet.contains(index)){
+                QuestionDifficultRelation target = all.get(index);
+                list.add(target);
+                indexSet.add(index);
+            }
         }while(list.size() == size);
         return list;
     }

+ 2 - 1
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -345,7 +345,7 @@ public class OrderFlowService {
         }));
 
         initRecordCallback.put(ProductType.COURSE, ((order, record) -> {
-            Course course = courseService.get(record.getId());
+            Course course = courseService.get(record.getProductId());
             CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
             // 小班课程不会存在记录,在线视频和1v1授课都有有效期
             Date startTime = new Date();
@@ -417,6 +417,7 @@ public class OrderFlowService {
             if(userCourse == null){
                 userCourse = UserCourse.builder()
                         .userId(record.getUserId())
+                        .courseId(course.getId())
                         .recordId(record.getId())
                         .startTime(startTime)
                         .expireTime(endTime)

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

@@ -143,7 +143,7 @@ public class PreviewService extends AbstractService {
         List<UserPreviewPaperRelation> pr = Transform.convert(list, UserPreviewPaperRelation.class);
 
         // 获取最后一次作业结果
-        List<UserReport> reportList = userReportService.listWithLater(ids);
+        List<UserReport> reportList = userReportService.listWithLast(ids);
 
         Transform.combine(pr, reportList, UserPreviewPaperRelation.class, "id", "report", UserReport.class, "paperId");
 

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

@@ -76,6 +76,9 @@ public class QuestionFlowService {
     private UserQuestionService userQuestionService;
 
     @Resource
+    private UserServiceService userServiceService;
+
+    @Resource
     private UserCourseAppointmentService userCourseAppointmentService;
 
     @Resource
@@ -1640,12 +1643,12 @@ public class QuestionFlowService {
         Integer irScore = toolsService.irScore(irInfo.getIntValue("number"), irInfo.getIntValue("userNumber"), irInfo.getInteger("difficultScore"), irInfo.getInteger("userCorrect"));
 
         Rank rank = toolsService.totalScore(quantScore, verbalScore);
-        score.put("total", rank.getTotalScore());
+        score.put("totalScore", rank.getTotalScore());
         score.put("totalRank", rank.getTotalRank());
-        score.put("quant", quantScore);
+        score.put("quantScore", quantScore);
         score.put("quantRank", rank.getQuantRank());
-        score.put("verbal", verbalScore);
-        score.put("ir", irScore);
+        score.put("verbalScore", verbalScore);
+        score.put("irScore", irScore);
         score.put("irRank", rank.getIrRank());
 
         detail.put("subject", subjectMap);
@@ -1664,5 +1667,14 @@ public class QuestionFlowService {
 
         report.setDetail(detail);
         report.setScore(score);
+
+        // 统计
+        UserService userService = null;
+        // 判断是否是cat模考:记录到第二次
+        ExaminationPaper examinationPaper = examinationPaperService.get(report.getOriginId());
+        if(examinationService.isCat(examinationPaper)){
+            userService = userServiceService.getService(report.getUserId(), ServiceKey.QX_CAT);
+        }
+        examinationPaperService.accumulation(report, userService != null && userService.getIsReset() > 0);
     }
 }

+ 22 - 28
server/gateway-api/src/main/java/com/qxgmat/service/inline/CommentService.java

@@ -2,12 +2,16 @@ 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;
 import com.qxgmat.data.constants.enums.module.ChannelModule;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.CommentMapper;
 import com.qxgmat.data.dao.entity.Comment;
+import com.qxgmat.data.relation.CommentRelationMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -23,35 +27,25 @@ public class CommentService extends AbstractService {
     @Resource
     private CommentMapper commentMapper;
 
-    public Page<Comment> listAdmin(int page, int size, Boolean user, String channel, String position, Integer userId, Boolean isSpecial){
-        Example example = new Example(Comment.class);
-        if (user != null){
-            example.and(user ? example.createCriteria().andGreaterThan("userId", 0):
-                    example.createCriteria().andEqualTo("user", 0)
-            );
-        }
-        if (channel != null){
-            example.and(
-                    example.createCriteria().andEqualTo("channel", channel)
-            );
-            if (position != null){
-                example.and(
-                        example.createCriteria().andEqualTo("position", position)
-                );
-            }
-        }
-        if (userId != null){
-            example.and(
-                    example.createCriteria().andEqualTo("userId", userId)
-            );
-        }
-        if(isSpecial != null){
-            example.and(
-                    example.createCriteria().andEqualTo("isSpecial", isSpecial ? 1 : 0)
-            );
+    @Resource
+    private CommentRelationMapper commentRelationMapper;
+
+    public Page<Comment> listAdmin(int page, int size, Boolean user, String channel, String position, Integer userId, Boolean isSpecial, Boolean isShow, MoneyRange moneyRange, String order, DirectionStatus direction){
+        Integer max = moneyRange != null ? moneyRange.max == Integer.MAX_VALUE ? null : moneyRange.max : null;
+        Integer min = moneyRange != null ? moneyRange.min : null;
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
         }
-
-        return select(commentMapper, example, page, size);
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<Comment> p = page(
+                ()-> commentRelationMapper.listWithUser(user, channel, position, userId, isSpecial != null ? (isSpecial ? 1 :0) :null,isShow != null ? (isShow ? 1 :0) :null, min, max, finalOrder, finalDirection.key)
+                , page, size);
+
+        Collection ids = Transform.getIds(p, Comment.class, "id");
+        Transform.replace(p, select(ids), Comment.class, "id");
+        return p;
     }
 
     public Page<Comment> list(int page, int size, String channel, String position){

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

@@ -1,5 +1,6 @@
 package com.qxgmat.service.inline;
 
+import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
@@ -8,6 +9,9 @@ import com.nuliji.tools.mybatis.Example;
 import com.qxgmat.data.dao.ExaminationPaperMapper;
 import com.qxgmat.data.dao.entity.ExaminationPaper;
 import com.qxgmat.data.dao.entity.UserPaper;
+import com.qxgmat.data.dao.entity.UserQuestion;
+import com.qxgmat.data.dao.entity.UserReport;
+import com.qxgmat.data.relation.ExaminationPaperRelationMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -23,6 +27,30 @@ public class ExaminationPaperService extends AbstractService {
     @Resource
     private ExaminationPaperMapper examinationPaperMapper;
 
+    @Resource
+    private ExaminationPaperRelationMapper examinationPaperRelationMapper;
+
+    /**
+     * 累加做题记录到paper
+     * @param userReport
+     */
+    public void accumulation(UserReport userReport, boolean second){
+        JSONObject score = userReport.getScore();
+        examinationPaperRelationMapper.accumulation(userReport.getOriginId(), score.getIntValue("totalScore"), score.getIntValue("quantScore"), score.getIntValue("verbalScore"), score.getIntValue("irScore"), second);
+    }
+
+    /**
+     * 改变分值:用第二次记录
+     * @param paper
+     */
+    public void changeScoreSecond(ExaminationPaper paper){
+        paper.setTotalScore(paper.getSecondTotalScore());
+        paper.setTotalTimes(paper.getSecondTotalTimes());
+        paper.setQuantScore(paper.getSecondQuantScore());
+        paper.setVerbalScore(paper.getSecondVerbalScore());
+        paper.setIrScore(paper.getIrScore());
+    }
+
     /**
      * 根据第三层获取paper
      * @param id

+ 22 - 28
server/gateway-api/src/main/java/com/qxgmat/service/inline/FaqService.java

@@ -2,12 +2,16 @@ 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;
 import com.qxgmat.data.constants.enums.module.InsideModule;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
+import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.FaqMapper;
 import com.qxgmat.data.dao.entity.Faq;
+import com.qxgmat.data.relation.FaqRelationMapper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
@@ -23,35 +27,25 @@ public class FaqService extends AbstractService {
     @Resource
     private FaqMapper faqMapper;
 
-    public Page<Faq> listAdmin(int page, int size, Boolean user, String channel, String position, Integer answerStatus, Boolean isSpecial){
-        Example example = new Example(Faq.class);
-        if (user != null){
-            example.and(user ? example.createCriteria().andGreaterThan("userId", 0):
-                        example.createCriteria().andEqualTo("user", 0)
-                    );
-        }
-        if (channel != null){
-            example.and(
-                    example.createCriteria().andEqualTo("channel", channel)
-            );
-            if (position != null){
-                example.and(
-                        example.createCriteria().andEqualTo("position", position)
-                );
-            }
-        }
-        if (answerStatus != null){
-            example.and(
-                    example.createCriteria().andEqualTo("answerStatus", answerStatus)
-            );
-        }
-        if(isSpecial != null){
-            example.and(
-                    example.createCriteria().andEqualTo("isSpecial", isSpecial ? 1 : 0)
-            );
+    @Resource
+    private FaqRelationMapper faqRelationMapper;
+
+    public Page<Faq> listAdmin(int page, int size, Boolean user, String channel, String position, Integer userId, Integer answerStatus, Boolean isSpecial, Boolean isShow, MoneyRange moneyRange, String order, DirectionStatus direction){
+        Integer max = moneyRange != null ? moneyRange.max == Integer.MAX_VALUE ? null : moneyRange.max : null;
+        Integer min = moneyRange != null ? moneyRange.min : null;
+        if(order == null || order.isEmpty()) order = "id";
+        if (direction == null){
+            direction = DirectionStatus.DESC;
         }
-
-        return select(faqMapper, example, page, size);
+        String finalOrder = order;
+        DirectionStatus finalDirection = direction;
+        Page<Faq> p = page(
+                ()-> faqRelationMapper.listWithUser(user, channel, position, userId, answerStatus, isSpecial != null ? (isSpecial ? 1 :0) :null,isShow != null ? (isShow ? 1 :0) :null, min, max, finalOrder, finalDirection.key)
+                , page, size);
+
+        Collection ids = Transform.getIds(p, Faq.class, "id");
+        Transform.replace(p, select(ids), Faq.class, "id");
+        return p;
     }
 
     public Page<Faq> list(int page, int size, String channel, String position){

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

@@ -18,6 +18,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -93,6 +94,7 @@ public class PreviewAssignService extends AbstractService {
      * @return
      */
     public List<PreviewAssign> listByCourseNos(Integer courseId, Collection ids){
+        if(ids == null || ids.size() == 0) return new ArrayList<>();
         Example example = new Example(PreviewAssign.class);
         example.and(
                 example.createCriteria()
@@ -107,6 +109,21 @@ public class PreviewAssignService extends AbstractService {
      * @param appointmentIds
      * @return
      */
+    public List<PreviewAssign> listWithAppointment(Collection appointmentIds){
+        if(appointmentIds == null || appointmentIds.size() == 0) return new ArrayList<>();
+        Example example = new Example(PreviewAssign.class);
+        example.and(
+                example.createCriteria()
+                        .andIn("courseAppointment", appointmentIds)
+        );
+        return select(previewAssignMapper, example);
+    }
+
+    /**
+     * 用户查询1v1相对的预约作业
+     * @param appointmentIds
+     * @return
+     */
     public List<PreviewAssign> listByAppointment(int page, int size, Integer courseId, Collection appointmentIds, Integer userId, String endTime, Integer times){
         Page<PreviewAssign> p = page(()->previewAssignRelationMapper.listByAppointment(courseId, appointmentIds, userId, endTime, times), page, size);
         Collection ids = Transform.getIds(p, PreviewAssign.class, "id");

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

@@ -34,7 +34,7 @@ public class UserAskQuestionService extends AbstractService {
     @Resource
     private UserAskQuestionRelationMapper userAskQuestionRelationMapper;
 
-    public Page<UserAskQuestion> listWithUser(int page, int size, String questionType, String questionModule, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, Boolean hasRecord,String order, DirectionStatus direction){
+    public Page<UserAskQuestion> listWithUser(int page, int size, String askModule, String questionType, String questionModule, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, Boolean hasRecord,String order, DirectionStatus direction){
         String tk = target != null ? target.key : "";
         Integer statusIndex = status != null ? status.index : null;
         Integer max = moneyRange != null ? moneyRange.max == Integer.MAX_VALUE ? null : moneyRange.max : null;
@@ -46,7 +46,7 @@ public class UserAskQuestionService extends AbstractService {
         String finalOrder = order;
         DirectionStatus finalDirection = direction;
         Page<UserAskQuestion> p = page(
-                ()-> userAskQuestionRelationMapper.listWithUser(questionType, questionModule, userId, questionNoId, tk, statusIndex, showStatus, min, max, hasRecord, finalOrder, finalDirection.key)
+                ()-> userAskQuestionRelationMapper.listWithUser(askModule, questionType, questionModule, userId, questionNoId, tk, statusIndex, showStatus, min, max, hasRecord, finalOrder, finalDirection.key)
         , page, size);
 
         Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");

+ 40 - 2
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserCourseRecordService.java

@@ -2,10 +2,12 @@ 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;
 import com.qxgmat.data.dao.UserCourseRecordMapper;
+import com.qxgmat.data.dao.entity.Course;
 import com.qxgmat.data.dao.entity.UserCourseRecord;
 import com.qxgmat.data.relation.UserCourseRecordRelationMapper;
 import com.qxgmat.data.relation.entity.UserModuleRecordStatRelation;
@@ -16,8 +18,8 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.List;
+import java.util.*;
+import java.util.stream.Collectors;
 
 @Service
 public class UserCourseRecordService extends AbstractService {
@@ -30,6 +32,42 @@ public class UserCourseRecordService extends AbstractService {
     private UserCourseRecordRelationMapper userCourseRecordRelationMapper;
 
     /**
+     * 获取最后一次学习记录
+     * @param recordIds
+     * @return
+     */
+    public List<UserCourseRecord> listWithLast(Collection recordIds){
+        if(recordIds == null || recordIds.size() == 0) return new ArrayList<>();
+        List<UserCourseRecord> list = userCourseRecordRelationMapper.listLast(recordIds);
+
+        Collection reportIds = Transform.getIds(list, UserCourseRecord.class, "id");
+        Transform.replace(list, select(reportIds), UserCourseRecord.class, "id");
+        return list;
+    }
+
+    public Map<Integer, List<UserCourseRecord>> groupByCourse(Integer recordId, Collection courseNoIds){
+        Map<Integer, List<UserCourseRecord>> relationMap = new HashMap<>();
+        Example example = new Example(UserCourseRecord.class);
+        example.and(
+                example.createCriteria()
+                .andEqualTo("recordId", recordId)
+                .andIn("courseNoId", courseNoIds)
+        );
+        List<UserCourseRecord> recordList = select(userCourseRecordMapper, example);
+        List<UserCourseRecord> list = null;
+        for (UserCourseRecord record : recordList){
+            if(!relationMap.containsKey(record.getCourseNoId())){
+                list = new ArrayList<>();
+                relationMap.put(record.getCourseNoId(), list);
+            }else{
+                list = relationMap.get(record.getCourseNoId());
+            }
+            list.add(record);
+        }
+        return relationMap;
+    }
+
+    /**
      * 获取指定时间内的听课记录
      * @param userId
      * @param startTime

+ 2 - 2
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserFeedbackErrorService.java

@@ -32,13 +32,13 @@ public class UserFeedbackErrorService extends AbstractService {
     private UserFeedbackErrorRelationMapper userFeedbackErrorRelationMapper;
 
 
-    public Page<UserFeedbackError> listAdmin(int page, int size, FeedbackModule module, FeedbackStatus status, String keyword, Integer userId, MoneyRange moneyRange, String order, DirectionStatus direction){
+    public Page<UserFeedbackError> listAdmin(int page, int size, FeedbackModule module, FeedbackStatus status, String questionType, String target, Integer moduleId, String keyword, Integer userId, MoneyRange moneyRange, String order, DirectionStatus direction){
         String moduleKey = module == null ? null : module.key;
         Integer statusIndex = status == null ? null : status.index;
         Integer max = moneyRange != null ? moneyRange.max == Integer.MAX_VALUE ? null : moneyRange.max : null;
         Integer min = moneyRange != null ? moneyRange.min : null;
         Page<UserFeedbackError> p = page(
-                ()-> userFeedbackErrorRelationMapper.listAdmin(moduleKey, statusIndex, userId, keyword, min, max, order, direction.key)
+                ()-> userFeedbackErrorRelationMapper.listAdmin(moduleKey, statusIndex, questionType, target, moduleId, userId, keyword, min, max, order, direction.key)
         , page, size);
 
         Collection ids = Transform.getIds(p, UserFeedbackError.class, "id");

+ 8 - 1
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java

@@ -63,6 +63,7 @@ public class UserOrderRecordService extends AbstractService {
     }
 
     public List<CourseStudentNumberRelation> groupByCourse(Collection ids){
+        if (ids == null || ids.size() == 0) return new ArrayList<>();
         return userOrderRecordRelationMapper.groupByTime(ids);
     }
 
@@ -107,8 +108,14 @@ public class UserOrderRecordService extends AbstractService {
         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){
+    public Page<UserOrderRecord> listAdmin(int page, int size, Integer orderId, Integer userId, ProductType productType, Integer productId, ServiceKey service, Boolean needMoney, Boolean needPackage, String order, DirectionStatus direction){
         Example example = new Example(UserOrderRecord.class);
+        if(orderId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("orderId", orderId)
+            );
+        }
         if(userId != null){
             example.and(
                     example.createCriteria()

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

@@ -37,7 +37,7 @@ public class UserReportService extends AbstractService {
      * 查找userPaper最后一次做题记录
      * @param paperIds
      */
-    public List<UserReport> listWithLater(Collection paperIds){
+    public List<UserReport> listWithLast(Collection paperIds){
         if(paperIds == null || paperIds.size() == 0) return new ArrayList<>();
         List<UserReport> list = userReportRelationMapper.listLast(paperIds);
 
@@ -50,7 +50,7 @@ public class UserReportService extends AbstractService {
      * 查找userPaper最后一次做题记录: 不在意reset标志
      * @param paperIds
      */
-    public List<UserReport> listWithLaterNoReset(Collection paperIds){
+    public List<UserReport> listWithLastNoReset(Collection paperIds){
         if(paperIds == null || paperIds.size() == 0) return new ArrayList<>();
         List<UserReport> list = userReportRelationMapper.listLastNoReset(paperIds);