浏览代码

feat(server): 套餐

Go 5 年之前
父节点
当前提交
3758041d5f
共有 55 个文件被更改,包括 1456 次插入369 次删除
  1. 3 1
      front/project/Constant.js
  2. 62 75
      front/project/admin/routes/course/ask/page.js
  3. 3 3
      front/project/admin/routes/course/askDetail/index.js
  4. 1 1
      front/project/admin/routes/course/askDetail/index.less
  5. 18 20
      front/project/admin/routes/course/askDetail/page.js
  6. 1 2
      front/project/admin/routes/course/index.js
  7. 1 0
      front/project/admin/routes/course/invoice/index.js
  8. 1 0
      front/project/admin/routes/course/list/index.js
  9. 1 0
      front/project/admin/routes/course/package/index.js
  10. 180 1
      front/project/admin/routes/course/package/page.js
  11. 0 15
      front/project/admin/routes/course/packageDetail/index.js
  12. 0 3
      front/project/admin/routes/course/packageDetail/index.less
  13. 0 12
      front/project/admin/routes/course/packageDetail/page.js
  14. 2 1
      front/project/admin/routes/index.js
  15. 4 14
      front/project/admin/routes/setting/faq/page.js
  16. 2 2
      front/project/admin/routes/setting/service/page.js
  17. 8 3
      front/project/admin/routes/user/ask/page.js
  18. 3 3
      front/project/admin/routes/user/askDetail/page.js
  19. 7 6
      front/project/admin/routes/user/feedback/page.js
  20. 43 52
      front/project/admin/routes/user/service/page.js
  21. 16 0
      front/project/admin/stores/course.js
  22. 6 0
      front/project/admin/stores/exercise.js
  23. 18 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/module/CourseModule.java
  24. 1 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/user/ServiceSource.java
  25. 7 0
      server/data/src/main/java/com/qxgmat/data/dao/UserInvoiceMapper.java
  26. 335 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/CoursePackage.java
  27. 35 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/ExerciseStruct.java
  28. 125 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserInvoice.java
  29. 28 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/CoursePackageMapper.xml
  30. 3 2
      server/data/src/main/java/com/qxgmat/data/dao/mapping/ExerciseStructMapper.xml
  31. 18 0
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserInvoiceMapper.xml
  32. 4 9
      server/data/src/main/java/com/qxgmat/data/relation/UserAskCourseRelationMapper.java
  33. 2 3
      server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java
  34. 9 22
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskCourseRelationMapper.xml
  35. 4 4
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserAskQuestionRelationMapper.xml
  36. 5 0
      server/data/src/main/resources/mybatis-generator.xml
  37. 71 13
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  38. 3 4
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java
  39. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SentenceController.java
  40. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  41. 6 5
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  42. 2 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  43. 20 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseExtendDto.java
  44. 37 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/CourseNoExtendDto.java
  45. 0 47
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/QuestionNoExtendDto.java
  46. 89 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/CoursePackageDto.java
  47. 5 15
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/FaqDto.java
  48. 20 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskCourseDetailDto.java
  49. 83 9
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskCourseListDto.java
  50. 62 10
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserAskQuestionListDto.java
  51. 20 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserFeedbackErrorInfoDto.java
  52. 70 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/CoursePackageService.java
  53. 6 7
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskCourseService.java
  54. 3 2
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskQuestionService.java
  55. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserFeedbackErrorService.java

文件差异内容过多而无法显示
+ 3 - 1
front/project/Constant.js


+ 62 - 75
front/project/admin/routes/course/ask/page.js

@@ -4,91 +4,74 @@ 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, formatDate, formatTreeData, formatSeconds } from '@src/services/Tools';
 import { asyncSMessage, asyncDelConfirm } from '@src/services/AsyncTools';
-import { QuestionType, AskStatus, MoneyRange, SwitchSelect, AskTarget } from '../../../../Constant';
+import { AskStatus, SwitchSelect } from '../../../../Constant';
 import { User } from '../../../stores/user';
+import { Exercise } from '../../../stores/exercise';
 import { Course } from '../../../stores/course';
+import user from '../../user';
 
-const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
 const AskStatusMap = getMap(AskStatus, 'value', 'label');
 const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
 export default class extends Page {
   init() {
-    this.actionList = [{
-      key: 'ignore',
-      type: 'danger',
-      name: '批量忽略',
-      needSelect: 1,
-    }];
+    // this.actionList = [{
+    //   key: 'ignore',
+    //   type: 'danger',
+    //   name: '批量忽略',
+    //   needSelect: 1,
+    // }];
+    this.exerciseMap = {};
     this.filterForm = [{
-      key: 'type',
-      type: 'select',
+      key: 'structId',
+      type: 'tree',
       allowClear: true,
-      name: '题型',
-      select: QuestionType,
+      name: '学科',
+      select: [],
       placeholder: '请选择',
       number: true,
     }, {
-      key: 'status',
+      key: 'courseId',
       type: 'select',
       allowClear: true,
-      name: '状态',
-      select: AskStatus,
+      name: '课程',
+      select: [],
+      placeholder: '请选择',
+      number: true,
     }, {
-      key: 'money',
+      key: 'answerStatus',
       type: 'select',
       allowClear: true,
-      name: '消费金额',
-      select: MoneyRange,
+      name: '回答状态',
+      select: AskStatus,
+      number: true,
     }, {
       key: 'showStatus',
       type: 'select',
       allowClear: true,
       name: '展示状态',
       select: SwitchSelect,
-    }, {
-      key: 'target',
-      type: 'select',
-      allowClear: true,
-      name: '提问内容',
-      select: AskTarget,
-    }, {
-      key: 'questionNoId',
-      type: 'select',
-      allowClear: true,
-      name: '题目ID',
-      select: [],
-      number: true,
-      placeholder: '请输入',
-    }, {
-      key: 'userId',
-      type: 'select',
-      name: '用户',
-      allowClear: true,
-      select: [],
-      number: true,
-      placeholder: '请输入',
     }];
     this.columns = [
       {
-        title: '题型',
-        dataIndex: 'type',
+        title: '学科',
+        dataIndex: 'course.structId',
         render: (text, record) => {
-          return QuestionTypeMap[record.question.type];
+          return `${record.course.parentStructId ? `${this.exerciseMap[record.course.parentStructId]}-` : ''}${this.exerciseMap[record.course.structId]}`;
         },
       },
       {
-        title: '题目id',
-        dataIndex: 'questionNo.no',
+        title: '课程',
+        dataIndex: 'course.title',
       },
       {
-        title: '提问时间',
-        dataIndex: 'createTime',
-        render: (text) => {
-          return formatDate(text);
+        title: '位置',
+        dataIndex: 'position',
+        render: (text, record) => {
+          return `P${record.courseNo.no}:${text}`;
         },
       },
       {
@@ -98,6 +81,13 @@ export default class extends Page {
         title: '提问者',
         dataIndex: 'user.nickname',
       }, {
+        title: '承诺时间',
+        dataIndex: 'user.askTime',
+        render: (text, record) => {
+          const cost = (new Date().getTime() - new Date(record.createTime).getTime()) / 1000;
+          return user.askTime ? formatSeconds(user.askTime - cost) : '-';
+        },
+      }, {
         title: '回答状态',
         dataIndex: 'answerStatus',
         render: (text) => {
@@ -109,6 +99,9 @@ export default class extends Page {
       }, {
         title: '回答时间',
         dataIndex: 'answerTime',
+        render: (text) => {
+          return text ? formatDate(text) : '';
+        },
       }, {
         title: '展示状态',
         dataIndex: 'showStatus',
@@ -121,28 +114,24 @@ export default class extends Page {
         render: (text, record) => {
           return <div className="table-button">
             {(
-              <Link to={`/user/ask/detail/${record.id}`}>编辑</Link>
+              <Link to={`/course/ask/detail/${record.id}`}>编辑</Link>
             )}
           </div>;
         },
       },
     ];
-    bindSearch(this.filterForm, 'userId', this, (search) => {
-      return User.list(search);
-    }, (row) => {
-      return {
-        title: `${row.nickname}(${row.mobile})`,
-        value: row.id,
-      };
-    }, this.state.search.userId ? Number(this.state.search.userId) : [], null);
-    bindSearch(this.filterForm, 'questionNoId', this, (search) => {
-      return Question.searchNo(search);
-    }, (row) => {
-      return {
-        title: row.title,
-        value: row.id,
-      };
-    }, this.state.search.questionNoId ? Number(this.state.search.questionNoId) : [], null);
+    Exercise.courseStruct().then((result) => {
+      const list = result.map(row => { row.title = `${row.titleZh}/${row.titleEn}`; row.value = row.id; return row; });
+      this.filterForm[0].tree = formatTreeData(list, 'id', 'title', 'parentId');
+      console.log(this.filterForm[0].tree);
+      this.exerciseMap = getMap(result.map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      }), 'id', 'title');
+
+      this.setState({ exercise: result });
+    });
   }
 
   initData() {
@@ -162,22 +151,20 @@ export default class extends Page {
   }
 
   renderView() {
+    const { exercise } = this.state;
     return <Block flex>
-      <FilterLayout
+      {exercise && <FilterLayout
         show
         itemList={this.filterForm}
         data={this.state.search}
         onChange={data => {
-          if (data.time.length > 0) {
-            data.time = [data.time[0].format('YYYY-MM-DD HH:mm:ss'), data.time[1].format('YYYY-MM-DD HH:mm:ss')];
-          }
           this.search(data);
-        }} />
-      <ActionLayout
+        }} />}
+      {/* <ActionLayout
         itemList={this.actionList}
         selectedKeys={this.state.selectedKeys}
         onAction={key => this.onAction(key)}
-      />
+      /> */}
       <TableLayout
         select
         columns={this.columns}

+ 3 - 3
front/project/admin/routes/course/askDetail/index.js

@@ -2,13 +2,13 @@ import module from '../../module';
 import group from '../group';
 
 export default {
-  path: '/user/ask/detail/:id?',
-  key: 'user-ask-detail',
+  path: '/course/ask/detail/:id?',
+  key: 'course-ask-detail',
   title: '问答详情',
   needLogin: true,
   module,
   group,
-  showKey: 'user-ask',
+  showKey: 'course-ask',
   component() {
     return import('./page');
   },

+ 1 - 1
front/project/admin/routes/course/askDetail/index.less

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

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

@@ -1,19 +1,17 @@
 import React from 'react';
-import { Form, Button, Row, Col, List, Icon, Switch, Typography } from 'antd';
+import { Form, Button, Row, Col, List, Icon, Switch, Typography, Input } from 'antd';
 import './index.less';
-import Editor from '@src/components/Editor';
+// import Editor from '@src/components/Editor';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import DragList from '@src/components/DragList';
 // import FileUpload from '@src/components/FileUpload';
-import { formatFormError, formatDate, getMap } from '@src/services/Tools';
+import { formatFormError, formatDate } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { AskTarget, QuestionType } from '../../../../Constant';
+// import { AskTarget } from '../../../../Constant';
 // import { User } from '../../../stores/user';
-import { Question } from '../../../stores/question';
+import { Course } from '../../../stores/course';
 
-const QuestionTypeMap = getMap(QuestionType, 'value', 'label');
-const AskTargetMap = getMap(AskTarget, 'value', 'label');
 export default class extends Page {
   init() {
     // Exercise.allStruct().then(result => {
@@ -26,7 +24,7 @@ export default class extends Page {
     const { id } = this.params;
     let handler;
     if (id) {
-      handler = Question.getAsk({ id });
+      handler = Course.getAsk({ id });
     } else {
       handler = Promise.resolve({ others: [{ content: 123123123, answer: 123123 }, {}] });
     }
@@ -70,7 +68,7 @@ export default class extends Page {
       if (!err) {
         const data = form.getFieldsValue();
         data.other = this.state.data.others.map(row => row.id);
-        Question.editAsk(data).then(() => {
+        Course.editAsk(data).then(() => {
           asyncSMessage('保存成功');
         }).catch((e) => {
           if (e.result) form.setFields(formatFormError(data, e.result));
@@ -81,15 +79,15 @@ export default class extends Page {
 
   renderBase() {
     const { data } = this.state;
-    const { question = {}, questionNo = {} } = data;
+    const { course = {} } = data;
     return <Block>
-      <h1>题目信息</h1>
+      <h1>提问信息</h1>
       <Form>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题型'>
-          {QuestionTypeMap[question.type]}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学科'>
+          {/* {QuestionTypeMap[question.type]} */}
         </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='题目id'>
-          <a href='' target='_blank'>{questionNo.no}</a>
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程'>
+          <a href='' target='_blank'>{course.title}</a>
         </Form.Item>
       </Form>
     </Block>;
@@ -97,7 +95,7 @@ export default class extends Page {
 
   renderAsk() {
     const { data } = this.state;
-    const { user = {}, createTime, target, originContent, content } = data;
+    const { user = {}, createTime, courseNo, position, originContent, content } = data;
     return <Block>
       <h1>提问信息</h1>
       <Form>
@@ -107,8 +105,8 @@ export default class extends Page {
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问时间'>
           {formatDate(createTime)}
         </Form.Item>
-        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问模块'>
-          {AskTargetMap[target]}
+        <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问位置'>
+          {`P${courseNo.no}:${position}`}
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问内容'>
           {originContent}
@@ -122,7 +120,7 @@ export default class extends Page {
 
   renderQuestionList() {
     return <Block>
-      <h1>该题目的展示中问题</h1>
+      <h1>该时段的展示中问题</h1>
       <DragList
         loading={this.props.core.loading}
         dataSource={this.state.data.others || []}
@@ -149,7 +147,7 @@ export default class extends Page {
         <Form.Item label='教师回复'>
           {getFieldDecorator('answer', {
           })(
-            <Editor placeholder='输入内容' />,
+            <Input.TextArea placeholder='输入内容' />,
           )}
         </Form.Item>
         <Row type="flex" justify="center">

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

@@ -3,6 +3,5 @@ import askDetail from './askDetail';
 import invoice from './invoice';
 import list from './list';
 import Package from './package';
-import packageDetail from './packageDetail';
 
-export default [ask, askDetail, invoice, list, Package, packageDetail];
+export default [ask, askDetail, invoice, list, Package];

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

@@ -8,6 +8,7 @@ export default {
   needLogin: true,
   module,
   group,
+  index: true,
   component() {
     return import('./page');
   },

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

@@ -8,6 +8,7 @@ export default {
   needLogin: true,
   module,
   group,
+  index: true,
   component() {
     return import('./page');
   },

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

@@ -8,6 +8,7 @@ export default {
   needLogin: true,
   module,
   group,
+  index: true,
   component() {
     return import('./page');
   },

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

@@ -1,12 +1,191 @@
 import React from 'react';
 import './index.less';
 import Page from '@src/containers/Page';
+import Block from '@src/components/Block';
+// import FilterLayout from '@src/layouts/FilterLayout';
+import ActionLayout from '@src/layouts/ActionLayout';
+import TableLayout from '@src/layouts/TableLayout';
+import { getMap, formatTreeData } from '@src/services/Tools';
+import { asyncSMessage, asyncForm } from '@src/services/AsyncTools';
+import { ServiceKey, ServiceParamMap, SwitchSelect } from '../../../../Constant';
+import { Course } from '../../../stores/course';
+import { Exercise } from '../../../stores/exercise';
+
+const SwitchSelectMap = getMap(SwitchSelect, 'value', 'label');
 
 export default class extends Page {
+  constructor(props) {
+    super(props);
+    this.exerciseMap = {};
+    this.actionList = [{
+      key: 'add',
+      type: 'primary',
+      name: '创建',
+    }];
+
+    this.itemList = [{
+      key: 'id',
+      type: 'hidden',
+    }, {
+      key: 'title',
+      type: 'input',
+      name: '套餐名称',
+    }, {
+      key: 'structId',
+      type: 'select',
+      select: [],
+      name: '套餐学科',
+    }, {
+      key: 'description',
+      type: 'input',
+      name: '套餐描述',
+    }, {
+      key: 'price',
+      type: 'number',
+      name: '套餐价格',
+    }, {
+      key: 'courseIds',
+      type: 'multiple',
+      name: '包含课程',
+    }];
+    ServiceKey.forEach((row) => {
+      const list = ServiceParamMap[row.value];
+      const item = {
+        key: `gift.${row.value}`,
+        type: 'number',
+        name: `赠送${row.label}`,
+      };
+      if (list) {
+        item.select = list;
+        item.type = 'select';
+      }
+      this.itemList.push(item);
+    });
+
+    this.columns = [{
+      title: '套餐名称',
+      dataIndex: 'title',
+    }, {
+      title: '套餐学科',
+      dataIndex: 'structId',
+      render: (text) => {
+        return this.exerciseMap[text];
+      },
+    }, {
+      title: '套餐价格',
+      dataIndex: 'price',
+    }, {
+      title: '销售数量',
+      dataIndex: 'totalNumber',
+    }, {
+      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>;
+      },
+    }];
+  }
+
   init() {
+    Exercise.courseStruct().then((result) => {
+      const list = result.filter(row => row.level === 1).map(row => {
+        row.title = `${row.titleZh}/${row.titleEn}`;
+        row.value = row.id;
+        return row;
+      });
+      this.itemList[2].select = list;
+      this.exerciseMap = getMap(list, 'id', 'title');
+      this.setState({ exercise: formatTreeData(list, 'id', 'title', 'parentId') });
+    });
+    Course.list().then((result) => {
+      this.itemList[4].select = result.list.map(row => {
+        row.value = row.id;
+        return row;
+      });
+    });
+  }
+
+  initData() {
+    Course.listPackage(this.state.search).then(result => {
+      this.setTableData(result.list, result.total);
+    });
+  }
+
+  detailAction(row) {
+    this.setState({ detail: row });
+  }
+
+  addAction() {
+    asyncForm('创建', this.itemList, {}, data => {
+      return Course.addPackage(data).then(() => {
+        asyncSMessage('添加成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  editAction(row) {
+    asyncForm('编辑', this.itemList, row, data => {
+      return Course.editPackage(data).then(() => {
+        asyncSMessage('编辑成功!');
+        this.refresh();
+      });
+    });
+  }
+
+  special(row, isSpecial) {
+    Course.editPackage({ id: row.id, isSpecial }).then(() => {
+      asyncSMessage('编辑成功!');
+      this.refresh();
+    });
   }
 
   renderView() {
-    return <div />;
+    return <Block flex>
+      {/* <FilterLayout
+        show
+        itemList={this.filterForm}
+        data={this.state.search}
+        onChange={data => {
+          this.search(data);
+        }} /> */}
+      <ActionLayout
+        itemList={this.actionList}
+        selectedKeys={this.state.selectedKeys}
+        onAction={key => this.onAction(key)}
+      />
+      <TableLayout
+        select
+        columns={this.columns}
+        list={this.state.list}
+        pagination={this.state.page}
+        loading={this.props.core.loading}
+        onChange={(pagination, filters, sorter) => this.tableChange(pagination, filters, sorter)}
+        onSelect={(keys, rows) => this.tableSelect(keys, rows)}
+        selectedKeys={this.state.selectedKeys}
+      />
+    </Block>;
   }
 }

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

@@ -1,15 +0,0 @@
-import module from '../../module';
-import group from '../group';
-
-export default {
-  path: '/course/package/detail/:id',
-  key: 'course-package-detail',
-  title: '套餐管理',
-  needLogin: true,
-  module,
-  group,
-  showKey: 'course-package',
-  component() {
-    return import('./page');
-  },
-};

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

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

+ 0 - 12
front/project/admin/routes/course/packageDetail/page.js

@@ -1,12 +0,0 @@
-import React from 'react';
-import './index.less';
-import Page from '@src/containers/Page';
-
-export default class extends Page {
-  init() {
-  }
-
-  renderView() {
-    return <div />;
-  }
-}

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

@@ -3,7 +3,8 @@
 import Page from './page';
 import subject from './subject';
 import user from './user';
+import course from './course';
 import setting from './setting';
 import System from './system';
 
-export default [...Page, ...subject, ...user, ...setting, ...System];
+export default [...Page, ...subject, ...user, ...course, ...setting, ...System];

+ 4 - 14
front/project/admin/routes/setting/faq/page.js

@@ -54,21 +54,12 @@ export default class extends Page {
     }, {
       key: 'content',
       type: 'textarea',
+      disabled: true,
       name: '用户留言',
     }, {
       key: 'answer',
       type: 'textarea',
       name: '编辑回复',
-    }, {
-      key: 'isSpecial',
-      type: 'switch',
-      name: '是否精选',
-      select: SwitchSelect,
-    }, {
-      key: 'sendMail',
-      type: 'switch',
-      name: '发送邮件',
-      select: SwitchSelect,
     }];
     this.filterForm = [{
       key: 'channel',
@@ -155,7 +146,7 @@ export default class extends Page {
         dataIndex: 'handler',
         render: (text, record) => {
           return <div className="table-button">
-            {!!record.isSystem && (
+            {(
               <a onClick={() => {
                 this.editAction(record);
               }}>编辑</a>
@@ -196,7 +187,7 @@ export default class extends Page {
   }
 
   addAction() {
-    asyncForm('创建评价', this.itemList, {}, data => {
+    asyncForm('创建', this.itemList, {}, data => {
       return System.addFAQ(data).then(() => {
         asyncSMessage('添加成功!');
         this.refresh();
@@ -219,8 +210,7 @@ export default class extends Page {
 
   answerAction(row) {
     asyncForm('回复', this.answerList, row, data => {
-      data.isSpecial = data.isSpecial ? 1 : 0;
-      data.sendMail = data.sendMail ? 1 : 0;
+      data.sendUser = true;
       return System.editFAQ(data).then(() => {
         asyncSMessage('回复成功!');
         this.refresh();

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

@@ -5,14 +5,14 @@ import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import { flattenObject } from '@src/services/Tools';
 import { asyncSMessage } from '@src/services/AsyncTools';
-import { SercieParamMap } from '../../../../Constant';
+import { ServiceParamMap } from '../../../../Constant';
 import { System } from '../../../stores/system';
 
 export default class extends Page {
   constructor(props) {
     super(props);
     this.state.tab = 'qx_cat';
-    this.vipList = SercieParamMap.vip;
+    this.vipList = ServiceParamMap.vip;
   }
 
   initData() {

+ 8 - 3
front/project/admin/routes/user/ask/page.js

@@ -24,31 +24,33 @@ export default class extends Page {
       needSelect: 1,
     }];
     this.filterForm = [{
-      key: 'type',
+      key: 'questionType',
       type: 'select',
       allowClear: true,
       name: '题型',
       select: QuestionType,
       placeholder: '请选择',
-      number: true,
     }, {
-      key: 'status',
+      key: 'answerStatus',
       type: 'select',
       allowClear: true,
       name: '状态',
       select: AskStatus,
+      number: true,
     }, {
       key: 'money',
       type: 'select',
       allowClear: true,
       name: '消费金额',
       select: MoneyRange,
+      number: true,
     }, {
       key: 'showStatus',
       type: 'select',
       allowClear: true,
       name: '展示状态',
       select: SwitchSelect,
+      number: true,
     }, {
       key: 'target',
       type: 'select',
@@ -109,6 +111,9 @@ export default class extends Page {
       }, {
         title: '回答时间',
         dataIndex: 'answerTime',
+        render: (text) => {
+          return text ? formatDate(text) : '';
+        },
       }, {
         title: '展示状态',
         dataIndex: 'showStatus',

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

@@ -1,7 +1,7 @@
 import React from 'react';
-import { Form, Button, Row, Col, List, Icon, Switch, Typography } from 'antd';
+import { Form, Button, Row, Col, List, Icon, Switch, Typography, Input } from 'antd';
 import './index.less';
-import Editor from '@src/components/Editor';
+// import Editor from '@src/components/Editor';
 import Page from '@src/containers/Page';
 import Block from '@src/components/Block';
 import DragList from '@src/components/DragList';
@@ -149,7 +149,7 @@ export default class extends Page {
         <Form.Item label='教师回复'>
           {getFieldDecorator('answer', {
           })(
-            <Editor placeholder='输入内容' />,
+            <Input.TextArea placeholder='输入内容' />,
           )}
         </Form.Item>
         <Row type="flex" justify="center">

+ 7 - 6
front/project/admin/routes/user/feedback/page.js

@@ -38,6 +38,7 @@ export default class extends Page {
       type: 'select',
       allowClear: true,
       name: '处理状态',
+      number: true,
       select: FeedbackStatus,
     }, {
       key: 'title',
@@ -58,11 +59,11 @@ export default class extends Page {
         title: '提交时间',
         dataIndex: 'createTime',
         render: (text) => {
-          return formatDate(text);
+          return text ? formatDate(text) : '-';
         },
       },
       {
-        title: '提问者',
+        title: '提交人',
         dataIndex: 'user.nickname',
       },
       {
@@ -82,7 +83,7 @@ export default class extends Page {
             {(
               <a onClick={() => {
                 this.detailAction(record);
-              }}>编辑</a>
+              }}>查看</a>
             )}
           </div>;
         },
@@ -175,14 +176,14 @@ export default class extends Page {
       }}>
         <p>类型:{FeedbackModuleMap[this.state.detail.module]}</p>
         <p>材料名称:{this.state.detail.title}</p>
-        {this.state.detail.position.length > 0 && <p>错误位置:{this.state.detail.position[0]}页,{this.state.detail.position[1]}行</p>}
+        {this.state.detail.position.length > 1 && <p>错误位置:{this.state.detail.position[0]}页,{this.state.detail.position[1]}行</p>}
         <p>错误内容:{this.state.detail.originContent}</p>
         <p>应修改为:{this.state.detail.content}</p>
-        <p><Button type="primary" onClick={() => {
+        {!this.state.detail.status && <p><Button type="primary" onClick={() => {
           this.handleDetail();
         }}>已处理</Button><Button type="ghost" onClick={() => {
           this.ignoreDetail();
-        }}>忽略</Button></p>
+        }}>忽略</Button></p>}
       </Modal>}
     </Block>;
   }

+ 43 - 52
front/project/admin/routes/user/service/page.js

@@ -27,6 +27,7 @@ export default class extends Page {
       type: 'primary',
       name: '创建',
     }];
+
     this.formF = null;
     this.itemList = [{
       key: 'id',
@@ -100,62 +101,52 @@ export default class extends Page {
       allowClear: true,
       notFound: null,
     }];
-    this.columns = [
-      {
-        title: '用户ID',
-        dataIndex: 'userId',
+    this.columns = [{
+      title: '用户ID',
+      dataIndex: 'userId',
+    }, {
+      title: '用户手机',
+      dataIndex: 'user.mobile',
+    }, {
+      title: '用户姓名',
+      dataIndex: 'user.nickname',
+    }, {
+      title: '开通服务',
+      dataIndex: 'service',
+      render: (text, record) => {
+        return `${ServiceKeyMap[text]}${(ServiceParamRelation[record.service] || {})[text] || ''}`;
       },
-      {
-        title: '用户手机',
-        dataIndex: 'user.mobile',
+    }, {
+      title: '开通时间',
+      dataIndex: 'time',
+      render: (text, record) => {
+        return `${record.startTime ? formatDate(record.startTime) : ''} - ${record.endTime ? formatDate(record.endTime) : ''}`;
       },
-      {
-        title: '用户姓名',
-        dataIndex: 'user.nickname',
+    }, {
+      title: '开通方式',
+      dataIndex: 'source',
+      render: (text) => {
+        return ServiceSourceMap[text] || '';
       },
-      {
-        title: '开通服务',
-        dataIndex: 'service',
-        render: (text) => {
-          return ServiceKeyMap[text];
-        },
-      }, {
-        title: '服务参数',
-        dataIndex: 'param',
-        render: (text, record) => {
-          return (ServiceParamRelation[record.service] || {})[text] || '';
-        },
-      }, {
-        title: '开通时间',
-        dataIndex: 'time',
-        render: (text, record) => {
-          return `${record.startTime ? formatDate(record.startTime) : ''} - ${record.endTime ? formatDate(record.endTime) : ''}`;
-        },
-      }, {
-        title: '开通方式',
-        dataIndex: 'source',
-        render: (text) => {
-          return ServiceSourceMap[text] || '';
-        },
-      }, {
-        title: '累计消费金额',
-        dataIndex: 'user.totalMoney',
-        render: (text) => {
-          return formatMoney(text);
-        },
-      }, {
-        title: '操作',
-        dataIndex: 'handler',
-        render: (text, record) => {
-          return <div className="table-button">
-            {!record.isUsed && (
-              <a onClick={() => {
-                this.editAction(record);
-              }}>编辑</a>
-            )}
-          </div>;
-        },
+    }, {
+      title: '累计消费金额',
+      dataIndex: 'user.totalMoney',
+      render: (text) => {
+        return formatMoney(text);
+      },
+    }, {
+      title: '操作',
+      dataIndex: 'handler',
+      render: (text, record) => {
+        return <div className="table-button">
+          {!record.isUsed && (
+            <a onClick={() => {
+              this.editAction(record);
+            }}>编辑</a>
+          )}
+        </div>;
       },
+    },
     ];
     bindSearch(this.filterForm, 'userId', this, (search) => {
       return User.list(search);

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

@@ -16,6 +16,22 @@ export default class CourseStore extends BaseStore {
   getAsk(params) {
     return this.apiGet('/course/ask/detail', params);
   }
+
+  listPackage(params) {
+    return this.apiGet('/course/package/list', params);
+  }
+
+  addPackage(params) {
+    return this.apiPost('/course/package/add', params);
+  }
+
+  editPackage(params) {
+    return this.apiPut('/course/package/edit', params);
+  }
+
+  delPackage(params) {
+    return this.apiGet('/course/package/detail', params);
+  }
 }
 
 export const Course = new CourseStore({ key: 'course' });

+ 6 - 0
front/project/admin/stores/exercise.js

@@ -1,6 +1,12 @@
 import BaseStore from '@src/stores/base';
 
 export default class ExerciseStore extends BaseStore {
+  courseStruct() {
+    return this.allStruct().then((result) => {
+      return result.filter(row => row.isCourse);
+    });
+  }
+
   allStruct() {
     return this.apiGet('/exercise/struct/all');
   }

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

@@ -0,0 +1,18 @@
+package com.qxgmat.data.constants.enums.module;
+
+// 课程模块
+public enum CourseModule {
+    VIDEO("video"),
+    ONLINE("online"),
+    IVSI("1vs1"),
+    ;
+    public String key;
+    private CourseModule(String key){
+        this.key = key;
+    }
+
+    public static CourseModule ValueOf(String name){
+        if (name == null) return null;
+        return CourseModule.valueOf(name.toUpperCase());
+    }
+}

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

@@ -6,6 +6,7 @@ public enum ServiceSource {
     ONLINE("online"),
     REAL("real"),
     INVITE("invite"),
+    GIFT("gift"),
 
     ;
     public String key;

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

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

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

@@ -1,6 +1,9 @@
 package com.qxgmat.data.dao.entity;
 
+import com.alibaba.fastjson.JSONObject;
 import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
 import javax.persistence.*;
 
 @Table(name = "course_package")
@@ -10,6 +13,60 @@ public class CoursePackage implements Serializable {
     @GeneratedValue(strategy = GenerationType.IDENTITY)
     private Integer id;
 
+    /**
+     * 学科
+     */
+    @Column(name = "`struct_id`")
+    private Integer structId;
+
+    /**
+     * 套餐名称
+     */
+    @Column(name = "`title`")
+    private String title;
+
+    /**
+     * 套餐价格
+     */
+    @Column(name = "`price`")
+    private BigDecimal price;
+
+    /**
+     * 包含课程
+     */
+    @Column(name = "`course_ids`")
+    private Integer[] courseIds;
+
+    /**
+     * 是否精选:首页推荐
+     */
+    @Column(name = "`is_special`")
+    private Integer isSpecial;
+
+    /**
+     * 赠品:json
+     */
+    @Column(name = "`gift`")
+    private JSONObject gift;
+
+    /**
+     * 销售数量
+     */
+    @Column(name = "`total_number`")
+    private Integer totalNumber;
+
+    @Column(name = "`create_time`")
+    private Date createTime;
+
+    @Column(name = "`update_time`")
+    private Date updateTime;
+
+    /**
+     * 套餐简介
+     */
+    @Column(name = "`description`")
+    private String description;
+
     private static final long serialVersionUID = 1L;
 
     /**
@@ -26,6 +83,178 @@ public class CoursePackage implements Serializable {
         this.id = id;
     }
 
+    /**
+     * 获取学科
+     *
+     * @return struct_id - 学科
+     */
+    public Integer getStructId() {
+        return structId;
+    }
+
+    /**
+     * 设置学科
+     *
+     * @param structId 学科
+     */
+    public void setStructId(Integer structId) {
+        this.structId = structId;
+    }
+
+    /**
+     * 获取套餐名称
+     *
+     * @return title - 套餐名称
+     */
+    public String getTitle() {
+        return title;
+    }
+
+    /**
+     * 设置套餐名称
+     *
+     * @param title 套餐名称
+     */
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    /**
+     * 获取套餐价格
+     *
+     * @return price - 套餐价格
+     */
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    /**
+     * 设置套餐价格
+     *
+     * @param price 套餐价格
+     */
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    /**
+     * 获取包含课程
+     *
+     * @return course_ids - 包含课程
+     */
+    public Integer[] getCourseIds() {
+        return courseIds;
+    }
+
+    /**
+     * 设置包含课程
+     *
+     * @param courseIds 包含课程
+     */
+    public void setCourseIds(Integer[] courseIds) {
+        this.courseIds = courseIds;
+    }
+
+    /**
+     * 获取是否精选:首页推荐
+     *
+     * @return is_special - 是否精选:首页推荐
+     */
+    public Integer getIsSpecial() {
+        return isSpecial;
+    }
+
+    /**
+     * 设置是否精选:首页推荐
+     *
+     * @param isSpecial 是否精选:首页推荐
+     */
+    public void setIsSpecial(Integer isSpecial) {
+        this.isSpecial = isSpecial;
+    }
+
+    /**
+     * 获取赠品:json
+     *
+     * @return gift - 赠品:json
+     */
+    public JSONObject getGift() {
+        return gift;
+    }
+
+    /**
+     * 设置赠品:json
+     *
+     * @param gift 赠品:json
+     */
+    public void setGift(JSONObject gift) {
+        this.gift = gift;
+    }
+
+    /**
+     * 获取销售数量
+     *
+     * @return total_number - 销售数量
+     */
+    public Integer getTotalNumber() {
+        return totalNumber;
+    }
+
+    /**
+     * 设置销售数量
+     *
+     * @param totalNumber 销售数量
+     */
+    public void setTotalNumber(Integer totalNumber) {
+        this.totalNumber = totalNumber;
+    }
+
+    /**
+     * @return create_time
+     */
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    /**
+     * @param createTime
+     */
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    /**
+     * @return update_time
+     */
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    /**
+     * @param updateTime
+     */
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+
+    /**
+     * 获取套餐简介
+     *
+     * @return description - 套餐简介
+     */
+    public String getDescription() {
+        return description;
+    }
+
+    /**
+     * 设置套餐简介
+     *
+     * @param description 套餐简介
+     */
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
     @Override
     public String toString() {
         StringBuilder sb = new StringBuilder();
@@ -33,6 +262,16 @@ public class CoursePackage implements Serializable {
         sb.append(" [");
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
+        sb.append(", structId=").append(structId);
+        sb.append(", title=").append(title);
+        sb.append(", price=").append(price);
+        sb.append(", courseIds=").append(courseIds);
+        sb.append(", isSpecial=").append(isSpecial);
+        sb.append(", gift=").append(gift);
+        sb.append(", totalNumber=").append(totalNumber);
+        sb.append(", createTime=").append(createTime);
+        sb.append(", updateTime=").append(updateTime);
+        sb.append(", description=").append(description);
         sb.append("]");
         return sb.toString();
     }
@@ -56,6 +295,102 @@ public class CoursePackage implements Serializable {
             return this;
         }
 
+        /**
+         * 设置学科
+         *
+         * @param structId 学科
+         */
+        public Builder structId(Integer structId) {
+            obj.setStructId(structId);
+            return this;
+        }
+
+        /**
+         * 设置套餐名称
+         *
+         * @param title 套餐名称
+         */
+        public Builder title(String title) {
+            obj.setTitle(title);
+            return this;
+        }
+
+        /**
+         * 设置套餐价格
+         *
+         * @param price 套餐价格
+         */
+        public Builder price(BigDecimal price) {
+            obj.setPrice(price);
+            return this;
+        }
+
+        /**
+         * 设置包含课程
+         *
+         * @param courseIds 包含课程
+         */
+        public Builder courseIds(Integer[] courseIds) {
+            obj.setCourseIds(courseIds);
+            return this;
+        }
+
+        /**
+         * 设置是否精选:首页推荐
+         *
+         * @param isSpecial 是否精选:首页推荐
+         */
+        public Builder isSpecial(Integer isSpecial) {
+            obj.setIsSpecial(isSpecial);
+            return this;
+        }
+
+        /**
+         * 设置赠品:json
+         *
+         * @param gift 赠品:json
+         */
+        public Builder gift(JSONObject gift) {
+            obj.setGift(gift);
+            return this;
+        }
+
+        /**
+         * 设置销售数量
+         *
+         * @param totalNumber 销售数量
+         */
+        public Builder totalNumber(Integer totalNumber) {
+            obj.setTotalNumber(totalNumber);
+            return this;
+        }
+
+        /**
+         * @param createTime
+         */
+        public Builder createTime(Date createTime) {
+            obj.setCreateTime(createTime);
+            return this;
+        }
+
+        /**
+         * @param updateTime
+         */
+        public Builder updateTime(Date updateTime) {
+            obj.setUpdateTime(updateTime);
+            return this;
+        }
+
+        /**
+         * 设置套餐简介
+         *
+         * @param description 套餐简介
+         */
+        public Builder description(String description) {
+            obj.setDescription(description);
+            return this;
+        }
+
         public CoursePackage build() {
             return this.obj;
         }

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

@@ -47,6 +47,12 @@ public class ExerciseStruct implements Serializable {
     private Integer questionStatus;
 
     /**
+     * 是否是课程
+     */
+    @Column(name = "`is_course`")
+    private Integer isCourse;
+
+    /**
      * 是否是长难句:每一层都继承
      */
     @Column(name = "`is_sentence`")
@@ -192,6 +198,24 @@ public class ExerciseStruct implements Serializable {
     }
 
     /**
+     * 获取是否是课程
+     *
+     * @return is_course - 是否是课程
+     */
+    public Integer getIsCourse() {
+        return isCourse;
+    }
+
+    /**
+     * 设置是否是课程
+     *
+     * @param isCourse 是否是课程
+     */
+    public void setIsCourse(Integer isCourse) {
+        this.isCourse = isCourse;
+    }
+
+    /**
      * 获取是否是长难句:每一层都继承
      *
      * @return is_sentence - 是否是长难句:每一层都继承
@@ -272,6 +296,7 @@ public class ExerciseStruct implements Serializable {
         sb.append(", order=").append(order);
         sb.append(", level=").append(level);
         sb.append(", questionStatus=").append(questionStatus);
+        sb.append(", isCourse=").append(isCourse);
         sb.append(", isSentence=").append(isSentence);
         sb.append(", isExamination=").append(isExamination);
         sb.append(", extend=").append(extend);
@@ -360,6 +385,16 @@ public class ExerciseStruct implements Serializable {
         }
 
         /**
+         * 设置是否是课程
+         *
+         * @param isCourse 是否是课程
+         */
+        public Builder isCourse(Integer isCourse) {
+            obj.setIsCourse(isCourse);
+            return this;
+        }
+
+        /**
          * 设置是否是长难句:每一层都继承
          *
          * @param isSentence 是否是长难句:每一层都继承

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

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

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

@@ -6,5 +6,33 @@
       WARNING - @mbg.generated
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
+    <result column="struct_id" jdbcType="INTEGER" property="structId" />
+    <result column="title" jdbcType="VARCHAR" property="title" />
+    <result column="price" jdbcType="DECIMAL" property="price" />
+    <result column="course_ids" jdbcType="VARCHAR" property="courseIds" typeHandler="com.nuliji.tools.mybatis.handler.IntegerArrayWithJsonHandler" />
+    <result column="is_special" jdbcType="INTEGER" property="isSpecial" />
+    <result column="gift" jdbcType="VARCHAR" property="gift" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
+    <result column="total_number" jdbcType="INTEGER" property="totalNumber" />
+    <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
+    <result column="update_time" jdbcType="TIMESTAMP" property="updateTime" />
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.CoursePackage">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="description" jdbcType="LONGVARCHAR" property="description" />
+  </resultMap>
+  <sql id="Base_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `id`, `struct_id`, `title`, `price`, `course_ids`, `is_special`, `gift`, `total_number`, 
+    `create_time`, `update_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `description`
+  </sql>
 </mapper>

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

@@ -12,6 +12,7 @@
     <result column="order" jdbcType="INTEGER" property="order" />
     <result column="level" jdbcType="INTEGER" property="level" />
     <result column="question_status" jdbcType="INTEGER" property="questionStatus" />
+    <result column="is_course" jdbcType="INTEGER" property="isCourse" />
     <result column="is_sentence" jdbcType="INTEGER" property="isSentence" />
     <result column="is_examination" jdbcType="INTEGER" property="isExamination" />
     <result column="extend" jdbcType="VARCHAR" property="extend" />
@@ -26,8 +27,8 @@
     <!--
       WARNING - @mbg.generated
     -->
-    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `question_status`, `is_sentence`, 
-    `is_examination`, `extend`
+    `id`, `title_zh`, `title_en`, `parent_id`, `order`, `level`, `question_status`, `is_course`, 
+    `is_sentence`, `is_examination`, `extend`
   </sql>
   <sql id="Blob_Column_List">
     <!--

+ 18 - 0
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserInvoiceMapper.xml

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

+ 4 - 9
server/data/src/main/java/com/qxgmat/data/relation/UserAskCourseRelationMapper.java

@@ -10,16 +10,11 @@ import java.util.List;
  * Created by gaojie on 2017/11/9.
  */
 public interface UserAskCourseRelationMapper {
-    List<UserAskCourse> listWithUser(
-            @Param("type") String type,
-            @Param("category") Number category,
-            @Param("userId") Number userId,
-            @Param("questionNoId") Number questionNoId,
-            @Param("target") String target,
-            @Param("status") Integer status,
+    List<UserAskCourse> listWithCourse(
+            @Param("structId") Integer structId,
+            @Param("courseId") Number courseId,
+            @Param("answerStatus") Integer answerStatus,
             @Param("showStatus") Integer showStatus,
-            @Param("min") Integer min,
-            @Param("max") Integer max,
             String order,
             String direction
     );

+ 2 - 3
server/data/src/main/java/com/qxgmat/data/relation/UserAskQuestionRelationMapper.java

@@ -10,12 +10,11 @@ import java.util.List;
  */
 public interface UserAskQuestionRelationMapper {
     List<UserAskQuestion> listWithUser(
-            @Param("type") String type,
-            @Param("category") Number category,
+            @Param("questionType") String questionType,
             @Param("userId") Number userId,
             @Param("questionNoId") Number questionNoId,
             @Param("target") String target,
-            @Param("status") Integer status,
+            @Param("answerStatus") Integer answerStatus,
             @Param("showStatus") Integer showStatus,
             @Param("min") Integer min,
             @Param("max") Integer max,

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

@@ -24,38 +24,25 @@
   </update>
 
   <!--用户提问列表-->
-  <select id="listWithUser" resultMap="IdMap">
+  <select id="listWithCourse" resultMap="IdMap">
     select
     <include refid="Id_Column_List" />
     from `user_ask_course` ua
-    left join `user` u on u.`id` = ua.`user_id`
-      <if test="userId != null">
-        and ua.`user_id` = #{userId,jdbcType=VARCHAR}
+    left join `course` c on c.`id` = ua.`course_id`
+      <if test="courseId != null">
+        and c.`id` = #{courseId,jdbcType=VARCHAR}
       </if>
-      <if test="max != null">
-        and u.`total_money` &lt; ${max}
+      <if test="structId != null">
+        and (c.`struct_id` = #{structId,jdbcType=VARCHAR} or c.`parent_struct_id` = #{structId,jdbcType=VARCHAR})
       </if>
-      <if test="min != null">
-        and u.`total_money` &gt; ${min}
-      </if>
-    left join `question` q on q.`id` = ua.`question_id`
     where
-    u.`id` &gt; 0
-    <if test="questionNoId != null">
-      and ua.`question_no_id` = #{questionNoId,jdbcType=VARCHAR}
-    </if>
-    <if test="target != null">
-      and ua.`target` = #{target,jdbcType=VARCHAR}
-    </if>
-    <if test="status != null">
-      and ua.`status` = #{status,jdbcType=INT}
+    c.`id` &gt; 0
+    <if test="answerStatus != null">
+      and ua.`answer_status` = #{answerStatus,jdbcType=INT}
     </if>
     <if test="showStatus != null">
       and ua.`show_status` = #{showStatus,jdbcType=INT}
     </if>
-    <if test="type != null">
-      and q.`type` =#{type,jdbcType=VARCHAR}
-    </if>
     order by ${order} ${direction}
   </select>
 </mapper>

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

@@ -47,14 +47,14 @@
     <if test="target != null">
       and ua.`target` = #{target,jdbcType=VARCHAR}
     </if>
-    <if test="status != null">
-      and ua.`status` = #{status,jdbcType=INT}
+    <if test="answerStatus != null">
+      and ua.`answer_status` = #{answerStatus,jdbcType=INT}
     </if>
     <if test="showStatus != null">
       and ua.`show_status` = #{showStatus,jdbcType=INT}
     </if>
-    <if test="type != null">
-      and q.`type` =#{type,jdbcType=VARCHAR}
+    <if test="questionType != null">
+      and q.`questionType` =#{questionType,jdbcType=VARCHAR}
     </if>
     order by ${order} ${direction}
   </select>

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

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

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

@@ -11,14 +11,13 @@ import com.qxgmat.data.constants.enums.user.AskTarget;
 import com.qxgmat.data.constants.enums.user.MoneyRange;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.dto.admin.extend.*;
+import com.qxgmat.dto.admin.request.CoursePackageDto;
 import com.qxgmat.dto.admin.request.UserAskCourseDto;
 import com.qxgmat.dto.admin.response.*;
 import com.qxgmat.help.ShiroHelp;
 import com.qxgmat.service.ManagerService;
 import com.qxgmat.service.UsersService;
-import com.qxgmat.service.inline.CourseService;
-import com.qxgmat.service.inline.ManagerLogService;
-import com.qxgmat.service.inline.UserAskCourseService;
+import com.qxgmat.service.inline.*;
 import io.swagger.annotations.ApiOperation;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.validation.annotation.Validated;
@@ -40,6 +39,12 @@ public class CourseController {
     private CourseService courseService;
 
     @Autowired
+    private CourseNoService courseNoService;
+
+    @Autowired
+    private CoursePackageService coursePackageService;
+
+    @Autowired
     private UserAskCourseService userAskCourseService;
 
     @Autowired
@@ -51,7 +56,7 @@ public class CourseController {
     @Autowired
     private UsersService usersService;
 
-    @RequestMapping(value = "/course/list", method = RequestMethod.GET)
+    @RequestMapping(value = "/list", method = RequestMethod.GET)
     @ApiOperation(value = "课程列表", httpMethod = "GET")
     public Response<PageMessage<CourseListDto>> list(
             @RequestParam(required = false, defaultValue = "1") int page,
@@ -63,6 +68,47 @@ public class CourseController {
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
+    @RequestMapping(value = "/package/add", method = RequestMethod.POST)
+    @ApiOperation(value = "添加套餐", httpMethod = "POST")
+    public Response<SentenceArticle> addPackage(@RequestBody @Validated CoursePackageDto dto, HttpServletRequest request) {
+        CoursePackage entity = Transform.dtoToEntity(dto);
+        entity = coursePackageService.add(entity);
+        managerLogService.log(request);
+        return ResponseHelp.success(Transform.convert(entity, SentenceArticle.class));
+    }
+    @RequestMapping(value = "/package/edit", method = RequestMethod.PUT)
+    @ApiOperation(value = "编辑套餐", httpMethod = "PUT")
+    public Response<Boolean> editPackage(@RequestBody @Validated CoursePackageDto dto, HttpServletRequest request) {
+        CoursePackage entity = Transform.dtoToEntity(dto);
+        entity = coursePackageService.edit(entity);
+        managerLogService.log(request);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/package/delete", method = RequestMethod.DELETE)
+    @ApiOperation(value = "删除套餐", httpMethod = "DELETE")
+    public Response<Boolean> deletePackage(@RequestParam int id, HttpServletRequest request) {
+        coursePackageService.delete(id);
+        managerLogService.log(request);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/package/detail", method = RequestMethod.GET)
+    @ApiOperation(value = "获取套餐", httpMethod = "GET")
+    public Response<CoursePackage> detailPackage(@RequestParam int id,HttpSession session) {
+        CoursePackage entity = coursePackageService.get(id);
+        return ResponseHelp.success(Transform.convert(entity, CoursePackage.class));
+    }
+    @RequestMapping(value = "/package/list", method = RequestMethod.GET)
+    @ApiOperation(value = "套餐列表", httpMethod = "GET")
+    public Response<PageMessage<CoursePackage>> listPackage(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            HttpSession session) {
+        Page<CoursePackage> p = coursePackageService.select(page, size);
+        List<CoursePackage> pr = Transform.convert(p, CoursePackage.class);
+        return ResponseHelp.success(pr, page, size, p.getTotal());
+    }
 
     @RequestMapping(value = "/ask/edit", method = RequestMethod.PUT)
     @ApiOperation(value = "修改提问信息", httpMethod = "PUT")
@@ -103,8 +149,14 @@ public class CourseController {
         User user = usersService.get(entity.getUserId());
         dto.setUser(Transform.convert(user, UserExtendDto.class));
 
+        Course course = courseService.get(entity.getCourseId());
+        dto.setCourse(Transform.convert(course, CourseExtendDto.class));
+
+        CourseNo courseNo = courseNoService.get(entity.getCourseNoId());
+        dto.setCourseNo(Transform.convert(courseNo, CourseNoExtendDto.class));
+
         // 所有回答
-        List<UserAskCourse> userAskList = userAskCourseService.listByCourse(entity.getCourseId(), true);
+        List<UserAskCourse> userAskList = userAskCourseService.listByCoursePosition(entity.getCourseNoId(), entity.getPosition(), true);
         dto.setOthers(Transform.convert(userAskList, UserAskCourseExtendDto.class));
         return ResponseHelp.success(dto);
     }
@@ -114,18 +166,14 @@ public class CourseController {
     public Response<PageMessage<UserAskCourseListDto>> list(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
-            @RequestParam(required = false) String type,
-            @RequestParam(required = false) Integer category,
-            @RequestParam(required = false) Number userId,
-            @RequestParam(required = false) Number questionNoId,
-            @RequestParam(required = false) String target,
-            @RequestParam(required = false) Integer status,
+            @RequestParam(required = false) Integer structId,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) Integer answerStatus,
             @RequestParam(required = false) Integer showStatus,
-            @RequestParam(required = false) Integer moneyRang,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserAskCourse> p = userAskCourseService.listWithUser(page, size, type, category, userId, questionNoId, AskTarget.ValueOf(target), AskStatus.ValueOf(status), showStatus, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
+        Page<UserAskCourse> p = userAskCourseService.listWithUser(page, size, structId, courseId, AskStatus.ValueOf(answerStatus), showStatus, order, DirectionStatus.ValueOf(direction));
         List<UserAskCourseListDto> pr = Transform.convert(p, UserAskCourseListDto.class);
 
         // 绑定用户
@@ -138,6 +186,16 @@ public class CourseController {
         List<Manager> managerList = managerService.select(managerIds);
         Transform.combine(pr, managerList, UserAskQuestionListDto.class, "managerId", "manager", Manager.class, "id", ManagerExtendDto.class);
 
+        // 绑定课程
+        Collection courseIds = Transform.getIds(p, UserAskCourse.class, "courseId");
+        List<Course> courseList = courseService.select(courseIds);
+        Transform.combine(pr, courseList, UserAskCourseListDto.class, "courseId", "course", Course.class, "id", CourseExtendDto.class);
+
+        // 绑定课时
+        Collection courseNoIds = Transform.getIds(p, UserAskCourse.class, "courseNoId");
+        List<CourseNo> courseNoList = courseNoService.select(courseNoIds);
+        Transform.combine(pr, courseNoList, UserAskCourseListDto.class, "courseNoId", "courseNo", CourseNo.class, "id", CourseNoExtendDto.class);
+
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 }

+ 3 - 4
server/gateway-api/src/main/java/com/qxgmat/controller/admin/QuestionController.java

@@ -223,18 +223,17 @@ 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 type,
-            @RequestParam(required = false) Integer category,
+            @RequestParam(required = false) String questionType,
             @RequestParam(required = false) Number userId,
             @RequestParam(required = false) Number questionNoId,
             @RequestParam(required = false) String target,
-            @RequestParam(required = false) Integer status,
+            @RequestParam(required = false) Integer answerStatus,
             @RequestParam(required = false) Integer showStatus,
             @RequestParam(required = false) Integer moneyRang,
             @RequestParam(required = false, defaultValue = "id") String order,
             @RequestParam(required = false, defaultValue = "desc") String direction,
             HttpSession session) {
-        Page<UserAskQuestion> p = userAskQuestionService.listWithUser(page, size, type, category, userId, questionNoId, AskTarget.ValueOf(target), AskStatus.ValueOf(status), showStatus, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
+        Page<UserAskQuestion> p = userAskQuestionService.listWithUser(page, size, questionType, userId, questionNoId, AskTarget.ValueOf(target), AskStatus.ValueOf(answerStatus), showStatus, MoneyRange.ValueOf(moneyRang), order, DirectionStatus.ValueOf(direction));
         List<UserAskQuestionListDto> pr = Transform.convert(p, UserAskQuestionListDto.class);
 
         // 绑定题目

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

@@ -77,7 +77,7 @@ public class SentenceController {
     public Response<Boolean> deleteArticle(@RequestParam int id, HttpServletRequest request) {
         sentenceArticleService.delete(id);
         managerLogService.log(request);
-        return ResponseHelp.success(sentenceArticleService.delete(id));
+        return ResponseHelp.success(true);
     }
 
     @RequestMapping(value = "/article/detail", method = RequestMethod.GET)

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

@@ -409,7 +409,7 @@ public class SettingController {
             Manager manager = shiroHelp.getLoginManager();
             entity.setManagerId(manager.getId());
         }
-        if(in.getIsSystem() == 0 && dto.getSendMail() != null && dto.getSendMail()){
+        if(in.getIsSystem() == 0 && dto.getSendUser() != null && dto.getSendUser()){
             // 回复邮箱
             if (in.getEmail() != null && !in.getEmail().isEmpty()){
                 //

+ 6 - 5
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java

@@ -253,7 +253,7 @@ public class UserController {
 
     @RequestMapping(value = "/feedback_error/list", method = RequestMethod.GET)
     @ApiOperation(value = "勘误列表", httpMethod = "GET")
-    public Response<PageMessage<UserFeedbackError>> listFeedbackError(
+    public Response<PageMessage<UserFeedbackErrorInfoDto>> listFeedbackError(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false) String module,
@@ -261,13 +261,14 @@ public class UserController {
             @RequestParam(required = false) String keyword,
             HttpSession session) {
         Page<UserFeedbackError> p = userFeedbackErrorService.listAdmin(page, size, FeedbackModule.ValueOf(module), FeedbackStatus.ValueOf(status), keyword);
+        List<UserFeedbackErrorInfoDto> pr = Transform.convert(p, UserFeedbackErrorInfoDto.class);
 
         // 绑定用户
-        Collection userIds = Transform.getIds(p, UserAskQuestion.class, "userId");
+        Collection userIds = Transform.getIds(p, UserFeedbackError.class, "userId");
         List<User> userList = usersService.select(userIds);
-        Transform.combine(p, userList, UserAskQuestionListDto.class, "userId", "user", UserExtendDto.class, "id", UserExtendDto.class);
+        Transform.combine(pr, userList, UserFeedbackErrorInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
 
-        return ResponseHelp.success(p, page, size, p.getTotal());
+        return ResponseHelp.success(pr, page, size, p.getTotal());
     }
 
     @RequestMapping(value = "/service/add", method = RequestMethod.POST)
@@ -303,7 +304,7 @@ public class UserController {
     }
 
     @RequestMapping(value = "/service/list", method = RequestMethod.GET)
-    @ApiOperation(value = "获取faq列表", httpMethod = "GET")
+    @ApiOperation(value = "获取服务列表", httpMethod = "GET")
     private Response<PageMessage<UserServiceRecordInfoDto>> listService(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,

+ 2 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -269,6 +269,7 @@ public class MyController {
     public Response<UserStudyDayDto> studyTime(
             @RequestParam(required = false) String date
     )  {
+        // todo 数学统一统计
         User user = (User) shiroHelp.getLoginUser();
         Date day;
         try {
@@ -369,6 +370,7 @@ public class MyController {
     @RequestMapping(value = "/study/total", method = RequestMethod.GET)
     @ApiOperation(value = "获取总学习记录", notes = "获取总学习记录", httpMethod = "GET")
     public Response<UserStudyDetailDto> studyTotalTime()  {
+        // todo 数学统一统计
         User user = (User) shiroHelp.getLoginUser();
         UserStudyDetailDto dto = new UserStudyDetailDto();
         dto.setCreateTime(user.getCreateTime());

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

@@ -7,6 +7,10 @@ import com.qxgmat.data.dao.entity.Course;
 public class CourseExtendDto {
     private Integer id;
 
+    private Integer structId;
+
+    private Integer parentStructId;
+
     private String title;
 
     public Integer getId() {
@@ -24,4 +28,20 @@ public class CourseExtendDto {
     public void setTitle(String title) {
         this.title = title;
     }
+
+    public Integer getStructId() {
+        return structId;
+    }
+
+    public void setStructId(Integer structId) {
+        this.structId = structId;
+    }
+
+    public Integer getParentStructId() {
+        return parentStructId;
+    }
+
+    public void setParentStructId(Integer parentStructId) {
+        this.parentStructId = parentStructId;
+    }
 }

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

@@ -0,0 +1,37 @@
+package com.qxgmat.dto.admin.extend;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.CourseNo;
+
+@Dto(entity = CourseNo.class)
+public class CourseNoExtendDto {
+    private Integer id;
+
+    private Integer no;
+
+    private String title;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    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;
+    }
+}

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

@@ -1,48 +1,17 @@
 package com.qxgmat.dto.admin.extend;
 
-import com.nuliji.tools.annotation.Dto;
-import com.qxgmat.data.dao.entity.QuestionNo;
 
-import javax.validation.constraints.NotEmpty;
-
-@Dto(entity = QuestionNo.class)
 public class QuestionNoExtendDto {
     private Integer id;
 
     private String title;
 
-    /**
-     * 模块:examination, exercise, sentence
-     */
-    @NotEmpty(message = "题目所属模块!")
-    private String module;
-
-    /**
-     * 人工id
-     */
-    @NotEmpty(message = "题目ID!")
     private String no;
 
-    /**
-     * 对应模块结构信息,逗号分隔
-     */
-    @NotEmpty(message = "对应模块层级!")
-    private Integer[] moduleStruct;
-
     private Integer questionId;
 
-    private Integer[] relationQuestion;
-
     private QuestionExtendDto question;
 
-    public String getModule() {
-        return module;
-    }
-
-    public void setModule(String module) {
-        this.module = module;
-    }
-
     public String getNo() {
         return no;
     }
@@ -51,14 +20,6 @@ public class QuestionNoExtendDto {
         this.no = no;
     }
 
-    public Integer[] getModuleStruct() {
-        return moduleStruct;
-    }
-
-    public void setModuleStruct(Integer[] moduleStruct) {
-        this.moduleStruct = moduleStruct;
-    }
-
     public QuestionExtendDto getQuestion() {
         return question;
     }
@@ -83,14 +44,6 @@ public class QuestionNoExtendDto {
         this.questionId = questionId;
     }
 
-    public Integer[] getRelationQuestion() {
-        return relationQuestion;
-    }
-
-    public void setRelationQuestion(Integer[] relationQuestion) {
-        this.relationQuestion = relationQuestion;
-    }
-
     public String getTitle() {
         return title;
     }

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

@@ -0,0 +1,89 @@
+package com.qxgmat.dto.admin.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.CoursePackage;
+
+import java.math.BigDecimal;
+
+@Dto(entity = CoursePackage.class)
+public class CoursePackageDto {
+    private Integer id;
+
+    private Integer structId;
+
+    private String title;
+
+    private BigDecimal price;
+
+    private Integer[] courseIds;
+
+    private Integer isSpecial;
+
+    private Object gift;
+
+    private String description;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public BigDecimal getPrice() {
+        return price;
+    }
+
+    public void setPrice(BigDecimal price) {
+        this.price = price;
+    }
+
+    public Integer[] getCourseIds() {
+        return courseIds;
+    }
+
+    public void setCourseIds(Integer[] courseIds) {
+        this.courseIds = courseIds;
+    }
+
+    public Integer getIsSpecial() {
+        return isSpecial;
+    }
+
+    public void setIsSpecial(Integer isSpecial) {
+        this.isSpecial = isSpecial;
+    }
+
+    public Object getGift() {
+        return gift;
+    }
+
+    public void setGift(Object gift) {
+        this.gift = gift;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public Integer getStructId() {
+        return structId;
+    }
+
+    public void setStructId(Integer structId) {
+        this.structId = structId;
+    }
+}

+ 5 - 15
server/gateway-api/src/main/java/com/qxgmat/dto/admin/request/FaqDto.java

@@ -11,8 +11,6 @@ public class FaqDto {
 
     private Integer userId;
 
-    private String email;
-
     private String channel;
 
     private String position;
@@ -23,7 +21,7 @@ public class FaqDto {
 
     private Integer isSpecial;
 
-    private Boolean sendMail;
+    private Boolean sendUser;
 
     private Integer status;
 
@@ -45,14 +43,6 @@ public class FaqDto {
         this.userId = userId;
     }
 
-    public String getEmail() {
-        return email;
-    }
-
-    public void setEmail(String email) {
-        this.email = email;
-    }
-
     public String getChannel() {
         return channel;
     }
@@ -109,11 +99,11 @@ public class FaqDto {
         this.answer = answer;
     }
 
-    public Boolean getSendMail() {
-        return sendMail;
+    public Boolean getSendUser() {
+        return sendUser;
     }
 
-    public void setSendMail(Boolean sendMail) {
-        this.sendMail = sendMail;
+    public void setSendUser(Boolean sendUser) {
+        this.sendUser = sendUser;
     }
 }

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

@@ -17,6 +17,10 @@ public class UserAskCourseDetailDto {
 
     private ManagerExtendDto manager;
 
+    private CourseExtendDto course;
+
+    private CourseNoExtendDto courseNo;
+
     private String target;
 
     private String content;
@@ -78,4 +82,20 @@ public class UserAskCourseDetailDto {
     public void setTarget(String target) {
         this.target = target;
     }
+
+    public CourseExtendDto getCourse() {
+        return course;
+    }
+
+    public void setCourse(CourseExtendDto course) {
+        this.course = course;
+    }
+
+    public CourseNoExtendDto getCourseNo() {
+        return courseNo;
+    }
+
+    public void setCourseNo(CourseNoExtendDto courseNo) {
+        this.courseNo = courseNo;
+    }
 }

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

@@ -2,20 +2,38 @@ package com.qxgmat.dto.admin.response;
 
 import com.nuliji.tools.annotation.Dto;
 import com.qxgmat.data.dao.entity.UserAskCourse;
+import com.qxgmat.dto.admin.extend.CourseExtendDto;
+import com.qxgmat.dto.admin.extend.CourseNoExtendDto;
 import com.qxgmat.dto.admin.extend.ManagerExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 
+import java.util.Date;
+
 @Dto(entity = UserAskCourse.class)
 public class UserAskCourseListDto {
 
     private Integer id;
 
-    private String title;
+    private String content;
+
+    private String originContent;
+
+    private String position;
 
     private UserExtendDto user;
 
     private ManagerExtendDto manager;
 
+    private CourseExtendDto course;
+
+    private CourseNoExtendDto courseNo;
+
+    private Integer answerStatus;
+
+    private Integer showStatus;
+
+    private Date answerTime;
+
     public Integer getId() {
         return id;
     }
@@ -24,14 +42,6 @@ public class UserAskCourseListDto {
         this.id = id;
     }
 
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
     public UserExtendDto getUser() {
         return user;
     }
@@ -47,4 +57,68 @@ public class UserAskCourseListDto {
     public void setManager(ManagerExtendDto manager) {
         this.manager = manager;
     }
+
+    public CourseExtendDto getCourse() {
+        return course;
+    }
+
+    public void setCourse(CourseExtendDto course) {
+        this.course = course;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getOriginContent() {
+        return originContent;
+    }
+
+    public void setOriginContent(String originContent) {
+        this.originContent = originContent;
+    }
+
+    public String getPosition() {
+        return position;
+    }
+
+    public void setPosition(String position) {
+        this.position = position;
+    }
+
+    public Integer getAnswerStatus() {
+        return answerStatus;
+    }
+
+    public void setAnswerStatus(Integer answerStatus) {
+        this.answerStatus = answerStatus;
+    }
+
+    public Integer getShowStatus() {
+        return showStatus;
+    }
+
+    public void setShowStatus(Integer showStatus) {
+        this.showStatus = showStatus;
+    }
+
+    public Date getAnswerTime() {
+        return answerTime;
+    }
+
+    public void setAnswerTime(Date answerTime) {
+        this.answerTime = answerTime;
+    }
+
+    public CourseNoExtendDto getCourseNo() {
+        return courseNo;
+    }
+
+    public void setCourseNo(CourseNoExtendDto courseNo) {
+        this.courseNo = courseNo;
+    }
 }

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

@@ -7,20 +7,32 @@ import com.qxgmat.dto.admin.extend.QuestionExtendDto;
 import com.qxgmat.dto.admin.extend.QuestionNoExtendDto;
 import com.qxgmat.dto.admin.extend.UserExtendDto;
 
+import java.util.Date;
+
 @Dto(entity = UserAskQuestion.class)
 public class UserAskQuestionListDto {
-
     private Integer id;
 
-    private String title;
+    private String content;
+
+    private String originContent;
+
+    private String target;
 
     private QuestionExtendDto question;
+
     private QuestionNoExtendDto questionNo;
 
     private UserExtendDto user;
 
     private ManagerExtendDto manager;
 
+    private Integer answerStatus;
+
+    private Integer showStatus;
+
+    private Date answerTime;
+
     public Integer getId() {
         return id;
     }
@@ -29,14 +41,6 @@ public class UserAskQuestionListDto {
         this.id = id;
     }
 
-    public String getTitle() {
-        return title;
-    }
-
-    public void setTitle(String title) {
-        this.title = title;
-    }
-
     public QuestionExtendDto getQuestion() {
         return question;
     }
@@ -68,4 +72,52 @@ public class UserAskQuestionListDto {
     public void setQuestionNo(QuestionNoExtendDto questionNo) {
         this.questionNo = questionNo;
     }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getOriginContent() {
+        return originContent;
+    }
+
+    public void setOriginContent(String originContent) {
+        this.originContent = originContent;
+    }
+
+    public String getTarget() {
+        return target;
+    }
+
+    public void setTarget(String target) {
+        this.target = target;
+    }
+
+    public Integer getAnswerStatus() {
+        return answerStatus;
+    }
+
+    public void setAnswerStatus(Integer answerStatus) {
+        this.answerStatus = answerStatus;
+    }
+
+    public Integer getShowStatus() {
+        return showStatus;
+    }
+
+    public void setShowStatus(Integer showStatus) {
+        this.showStatus = showStatus;
+    }
+
+    public Date getAnswerTime() {
+        return answerTime;
+    }
+
+    public void setAnswerTime(Date answerTime) {
+        this.answerTime = answerTime;
+    }
 }

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

@@ -9,10 +9,14 @@ public class UserFeedbackErrorInfoDto {
 
     private Integer id;
 
+    private Integer userId;
+
     private UserExtendDto user;
 
     private String module;
 
+    private String title;
+
     private Integer status;
 
     private String position;
@@ -76,4 +80,20 @@ public class UserFeedbackErrorInfoDto {
     public void setContent(String content) {
         this.content = content;
     }
+
+    public Integer getUserId() {
+        return userId;
+    }
+
+    public void setUserId(Integer userId) {
+        this.userId = userId;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
 }

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

@@ -0,0 +1,70 @@
+package com.qxgmat.service.inline;
+
+import com.github.pagehelper.Page;
+import com.nuliji.tools.AbstractService;
+import com.nuliji.tools.exception.ParameterException;
+import com.nuliji.tools.exception.SystemException;
+import com.qxgmat.data.dao.CourseNoMapper;
+import com.qxgmat.data.dao.CoursePackageMapper;
+import com.qxgmat.data.dao.entity.CourseNo;
+import com.qxgmat.data.dao.entity.CoursePackage;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.Collection;
+import java.util.List;
+
+@Service
+public class CoursePackageService extends AbstractService {
+    private static final Logger logger = LoggerFactory.getLogger(CoursePackageService.class);
+
+    @Resource
+    private CoursePackageMapper coursePackageMapper;
+
+    public CoursePackage add(CoursePackage coursePackage){
+        int result = insert(coursePackageMapper, coursePackage);
+        coursePackage = one(coursePackageMapper, coursePackage.getId());
+        if(coursePackage == null){
+            throw new SystemException("套餐添加失败");
+        }
+        return coursePackage;
+    }
+
+    public CoursePackage edit(CoursePackage coursePackage){
+        CoursePackage in = one(coursePackageMapper, coursePackage.getId());
+        if(in == null){
+            throw new ParameterException("套餐不存在");
+        }
+        int result = update(coursePackageMapper, coursePackage);
+        return coursePackage;
+    }
+
+    public boolean delete(Number id){
+        CoursePackage in = one(coursePackageMapper, id);
+        if(in == null){
+            throw new ParameterException("套餐不存在");
+        }
+        int result = delete(coursePackageMapper, id);
+        return result > 0;
+    }
+
+    public CoursePackage get(Number id){
+        CoursePackage in = one(coursePackageMapper, id);
+
+        if(in == null){
+            throw new ParameterException("套餐不存在");
+        }
+        return in;
+    }
+
+    public Page<CoursePackage> select(int page, int pageSize){
+        return select(coursePackageMapper, page, pageSize);
+    }
+
+    public List<CoursePackage> select(Collection ids){
+        return select(coursePackageMapper, ids);
+    }
+
+}

+ 6 - 7
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskCourseService.java

@@ -36,11 +36,8 @@ public class UserAskCourseService extends AbstractService {
     @Resource
     private UserAskCourseRelationMapper userAskCourseRelationMapper;
 
-    public Page<UserAskCourse> listWithUser(int page, int size, String type, Number category, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, String order, DirectionStatus direction){
-        String tk = target != null ? target.key : "";
+    public Page<UserAskCourse> listWithUser(int page, int size, Integer structId, Number courseId, AskStatus status, Integer showStatus, String order, DirectionStatus direction){
         Integer statusIndex = status != null ? status.index : null;
-        Integer max = moneyRange != null ? moneyRange.max == Integer.MAX_VALUE ? null : moneyRange.max : null;
-        Integer min = moneyRange != null ? moneyRange.min : null;
         if(order.isEmpty()) order = "id";
         if (direction == null){
             direction = DirectionStatus.DESC;
@@ -48,7 +45,7 @@ public class UserAskCourseService extends AbstractService {
         String finalOrder = order;
         DirectionStatus finalDirection = direction;
         Page<UserAskCourse> p = page(
-                ()-> userAskCourseRelationMapper.listWithUser(type, category, userId, questionNoId, tk, statusIndex, showStatus, min, max, finalOrder, finalDirection.key)
+                ()-> userAskCourseRelationMapper.listWithCourse(structId, courseId, statusIndex, showStatus, finalOrder, finalDirection.key)
         , page, size);
 
         Collection ids = Transform.getIds(p, UserAskCourse.class, "id");
@@ -56,11 +53,12 @@ public class UserAskCourseService extends AbstractService {
         return p;
     }
 
-    public List<UserAskCourse> listByCourse(Number courseId, Boolean showStatus){
+    public List<UserAskCourse> listByCoursePosition(Number courseNoId, String position, Boolean showStatus){
         Example example = new Example(UserAskCourse.class);
         example.and(
                 example.createCriteria()
-                        .andEqualTo("courseId", courseId)
+                        .andEqualTo("courseNoId", courseNoId)
+                        .andEqualTo("position", position)
 
         );
         if (showStatus != null)
@@ -90,6 +88,7 @@ public class UserAskCourseService extends AbstractService {
             update(userAskCourseMapper, UserAskCourse.builder()
                     .id(id)
                     .order(order)
+                    .showStatus(1)
                     .build()
             );
             order -= 1;

+ 3 - 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 type, Number category, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, String order, DirectionStatus direction){
+    public Page<UserAskQuestion> listWithUser(int page, int size, String questionType, Number userId, Number questionNoId, AskTarget target, AskStatus status, Integer showStatus, MoneyRange moneyRange, 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(type, category, userId, questionNoId, tk, statusIndex, showStatus, min, max, finalOrder, finalDirection.key)
+                ()-> userAskQuestionRelationMapper.listWithUser(questionType, userId, questionNoId, tk, statusIndex, showStatus, min, max, finalOrder, finalDirection.key)
         , page, size);
 
         Collection ids = Transform.getIds(p, UserAskQuestion.class, "id");
@@ -88,6 +88,7 @@ public class UserAskQuestionService extends AbstractService {
             update(userAskQuestionMapper, UserAskQuestion.builder()
                     .id(id)
                     .order(order)
+                    .showStatus(1)
                     .build()
             );
             order -= 1;

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

@@ -45,7 +45,7 @@ public class UserFeedbackErrorService extends AbstractService {
                     example.createCriteria()
                             .andLike("title", "%"+keyword+"%")
             );
-        return select(userFeedbackErrorMapper, page, pageSize);
+        return select(userFeedbackErrorMapper, example, page, pageSize);
     }
 
     public UserFeedbackError add(UserFeedbackError feedbackError){