Browse Source

feat(server): 课程接口

Go 5 years ago
parent
commit
ea29df6ede
33 changed files with 603 additions and 448 deletions
  1. 77 51
      front/project/admin/routes/setting/index/page.js
  2. 1 1
      front/project/admin/routes/student/askCourseDetail/page.js
  3. 8 0
      front/project/admin/stores/system.js
  4. 7 0
      front/project/h5/stores/main.js
  5. 7 3
      front/project/www/components/OtherModal/index.js
  6. 2 2
      front/project/www/routes/my/answer/page.js
  7. 4 0
      front/project/www/stores/course.js
  8. 7 0
      front/project/www/stores/main.js
  9. 22 2
      front/project/www/stores/my.js
  10. 21 5
      front/project/www/stores/order.js
  11. 2 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/MessageCategory.java
  12. 1 0
      server/data/src/main/java/com/qxgmat/data/constants/enums/SettingKey.java
  13. 4 4
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserAskCourse.java
  14. 52 0
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserExport.java
  15. 42 7
      server/data/src/main/java/com/qxgmat/data/dao/entity/UserMessage.java
  16. 1 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserAskCourseMapper.xml
  17. 14 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserExportMapper.xml
  18. 2 1
      server/data/src/main/java/com/qxgmat/data/dao/mapping/UserMessageMapper.xml
  19. 18 12
      server/data/src/main/resources/db/migration/V1__init_table.sql
  20. 17 0
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/SettingController.java
  21. 7 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java
  22. 21 0
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  23. 60 24
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  24. 3 3
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskCourseDto.java
  25. 13 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserCourseNoIdsDto.java
  26. 0 10
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserExportDto.java
  27. 1 1
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserQuestionIdsDto.java
  28. 47 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteCourseService.java
  29. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/UserNoteQuestionService.java
  30. 14 14
      server/gateway-api/src/main/java/com/qxgmat/service/UsersService.java
  31. 37 303
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExportService.java
  32. 12 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java
  33. 78 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserAskCourseService.java

+ 77 - 51
front/project/admin/routes/setting/index/page.js

@@ -12,41 +12,67 @@ export default class extends Page {
   initData() {
   initData() {
     System.getIndex().then(result => {
     System.getIndex().then(result => {
       const { form } = this.props;
       const { form } = this.props;
-      form.setFieldsValue(flattenObject(result));
+      form.setFieldsValue(flattenObject(result, 'index'));
-      this.setState({ load: true, data: result });
+      this.setState({ load: true, index: result });
+    });
+    System.getBase().then(result => {
+      const { form } = this.props;
+      form.setFieldsValue(flattenObject(result, 'base'));
+      this.setState({ load: true, base: result });
     });
     });
   }
   }
 
 
   addLength(field, info) {
   addLength(field, info) {
-    let { data } = this.state;
+    let { index } = this.state;
-    data = data || {};
+    index = index || {};
-    data[field] = data[field] || [];
+    index[field] = index[field] || [];
-    data[field].push(info);
+    index[field].push(info);
-    this.setState({ data });
+    this.setState({ index });
   }
   }
 
 
   deleteLength(field, start, length) {
   deleteLength(field, start, length) {
-    let { data } = this.state;
+    let { index } = this.state;
-    data = data || {};
+    index = index || {};
-    data[field] = data[field] || [];
+    index[field] = index[field] || [];
-    data[field].splice(start, length);
+    index[field].splice(start, length);
-    this.setState({ data });
+    this.setState({ index });
   }
   }
 
 
   submit() {
   submit() {
+    this.submitIndex();
+    this.submitBase();
+  }
+
+  submitIndex() {
+    const { form } = this.props;
+    form.validateFields(['index'], (err) => {
+      if (!err) {
+        const { index } = form.getFieldsValue();
+        index.class = Object.keys(index.class || {}).map((key) => index.class[key]);
+        index.activity = Object.keys(index.activity || {}).map((key) => index.activity[key]);
+        index.evaluation = Object.keys(index.evaluation || {}).map((key) => index.evaluation[key]);
+        System.setIndex(index)
+          .then(() => {
+            this.setState({ index });
+            asyncSMessage('保存成功');
+          }).catch((e) => {
+            form.setFields(formatFormError(index, e.result));
+          });
+      }
+    });
+  }
+
+  submitBase() {
     const { form } = this.props;
     const { form } = this.props;
-    form.validateFields((err) => {
+    form.validateFields(['base'], (err) => {
       if (!err) {
       if (!err) {
-        const data = form.getFieldsValue();
+        const { base } = form.getFieldsValue();
-        data.class = Object.keys(data.class || {}).map((key) => data.class[key]);
+        System.setBase(base)
-        data.activity = Object.keys(data.activity || {}).map((key) => data.activity[key]);
-        data.evaluation = Object.keys(data.evaluation || {}).map((key) => data.evaluation[key]);
-        System.setIndex(data)
           .then(() => {
           .then(() => {
-            this.setState(data);
+            this.setState({ base });
             asyncSMessage('保存成功');
             asyncSMessage('保存成功');
           }).catch((e) => {
           }).catch((e) => {
-            form.setFields(formatFormError(data, e.result));
+            form.setFields(formatFormError(base, e.result));
           });
           });
       }
       }
     });
     });
@@ -58,7 +84,7 @@ export default class extends Page {
       <h1>备考攻略</h1>
       <h1>备考攻略</h1>
       <Form>
       <Form>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='自学-从零开始'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='自学-从零开始'>
-          {getFieldDecorator('prepare.first', {
+          {getFieldDecorator('index.prepare.first', {
             rules: [
             rules: [
               { required: false, message: '请输入跳转地址' },
               { required: false, message: '请输入跳转地址' },
             ],
             ],
@@ -67,7 +93,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='自学-继续练习'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='自学-继续练习'>
-          {getFieldDecorator('prepare.continue', {
+          {getFieldDecorator('index.prepare.continue', {
             rules: [
             rules: [
               { required: false, message: '请输入跳转地址' },
               { required: false, message: '请输入跳转地址' },
             ],
             ],
@@ -76,7 +102,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-初学'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-初学'>
-          {getFieldDecorator('prepare.classJunior', {
+          {getFieldDecorator('index.prepare.classJunior', {
             rules: [
             rules: [
               { required: false, message: '请输入跳转地址' },
               { required: false, message: '请输入跳转地址' },
             ],
             ],
@@ -85,7 +111,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-中级'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-中级'>
-          {getFieldDecorator('prepare.classMiddle', {
+          {getFieldDecorator('index.prepare.classMiddle', {
             rules: [
             rules: [
               { required: false, message: '请输入跳转地址' },
               { required: false, message: '请输入跳转地址' },
             ],
             ],
@@ -94,7 +120,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-高级'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='课程-高级'>
-          {getFieldDecorator('prepare.classSenior', {
+          {getFieldDecorator('index.prepare.classSenior', {
             rules: [
             rules: [
               { required: false, message: '请输入跳转地址' },
               { required: false, message: '请输入跳转地址' },
             ],
             ],
@@ -112,7 +138,7 @@ export default class extends Page {
       <h1>用户数据</h1>
       <h1>用户数据</h1>
       <Form>
       <Form>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='线下用户量'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='线下用户量'>
-          {getFieldDecorator('user.numberOffline', {
+          {getFieldDecorator('index.user.numberOffline', {
             rules: [
             rules: [
               { required: false, message: '' },
               { required: false, message: '' },
             ],
             ],
@@ -122,7 +148,7 @@ export default class extends Page {
         </Form.Item>
         </Form.Item>
 
 
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='700+学员数'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='700+学员数'>
-          {getFieldDecorator('user.number700', {
+          {getFieldDecorator('index.user.number700', {
             rules: [
             rules: [
               { required: false, message: '' },
               { required: false, message: '' },
             ],
             ],
@@ -132,7 +158,7 @@ export default class extends Page {
         </Form.Item>
         </Form.Item>
 
 
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学员平均分'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='学员平均分'>
-          {getFieldDecorator('user.numberScore', {
+          {getFieldDecorator('index.user.numberScore', {
             rules: [
             rules: [
               { required: false, message: '' },
               { required: false, message: '' },
             ],
             ],
@@ -153,7 +179,7 @@ export default class extends Page {
       <Form>
       <Form>
         <Row>
         <Row>
           {course.map((row, index) => {
           {course.map((row, index) => {
-            const image = getFieldValue(`course.${index}.image`) || null;
+            const image = getFieldValue(`index.course.${index}.image`) || null;
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
               <Button className="delete-button" size="small" onClick={() => {
               <Button className="delete-button" size="small" onClick={() => {
                 this.deleteLength('course', index, 1);
                 this.deleteLength('course', index, 1);
@@ -161,7 +187,7 @@ export default class extends Page {
                 <Icon type="delete" />
                 <Icon type="delete" />
               </Button>
               </Button>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='课程名称'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='课程名称'>
-                {getFieldDecorator(`course.${index}.title`, {
+                {getFieldDecorator(`index.course.${index}.title`, {
                   rules: [
                   rules: [
                     { required: true, message: '输入课程名称' },
                     { required: true, message: '输入课程名称' },
                   ],
                   ],
@@ -171,7 +197,7 @@ export default class extends Page {
                 )}
                 )}
               </Form.Item>
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='跳转链接'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='跳转链接'>
-                {getFieldDecorator(`course.${index}.link`, {
+                {getFieldDecorator(`index.course.${index}.link`, {
                   rules: [
                   rules: [
                     { required: true, message: '输入跳转链接' },
                     { required: true, message: '输入跳转链接' },
                   ],
                   ],
@@ -181,7 +207,7 @@ export default class extends Page {
                 )}
                 )}
               </Form.Item>
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='背景图片'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='背景图片'>
-                {getFieldDecorator(`course.${index}.image`, {
+                {getFieldDecorator(`index.course.${index}.image`, {
                   rules: [
                   rules: [
                     { required: true, message: '上传图片' },
                     { required: true, message: '上传图片' },
                   ],
                   ],
@@ -190,7 +216,7 @@ export default class extends Page {
                     listType="picture-card"
                     listType="picture-card"
                     showUploadList={false}
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`course.${index}.image`]: result.url });
+                      setFieldsValue({ [`index.course.${index}.image`]: result.url });
                       return Promise.reject();
                       return Promise.reject();
                     })}
                     })}
                   >
                   >
@@ -224,7 +250,7 @@ export default class extends Page {
       <Form>
       <Form>
         <Row>
         <Row>
           {activity.map((row, index) => {
           {activity.map((row, index) => {
-            const image = getFieldValue(`activity.${index}.image`) || null;
+            const image = getFieldValue(`index.activity.${index}.image`) || null;
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
               <Button className="delete-button" size="small" onClick={() => {
               <Button className="delete-button" size="small" onClick={() => {
                 this.deleteLength('activity', index, 1);
                 this.deleteLength('activity', index, 1);
@@ -232,7 +258,7 @@ export default class extends Page {
                 <Icon type="delete" />
                 <Icon type="delete" />
               </Button>
               </Button>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='跳转链接'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='跳转链接'>
-                {getFieldDecorator(`activity.${index}.link`, {
+                {getFieldDecorator(`index.activity.${index}.link`, {
                   rules: [
                   rules: [
                     { required: true, message: '输入跳转链接' },
                     { required: true, message: '输入跳转链接' },
                   ],
                   ],
@@ -242,7 +268,7 @@ export default class extends Page {
                 )}
                 )}
               </Form.Item>
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='活动图片'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='活动图片'>
-                {getFieldDecorator(`activity.${index}.image`, {
+                {getFieldDecorator(`index.activity.${index}.image`, {
                   rules: [
                   rules: [
                     { required: true, message: '上传图片' },
                     { required: true, message: '上传图片' },
                   ],
                   ],
@@ -251,7 +277,7 @@ export default class extends Page {
                     listType="picture-card"
                     listType="picture-card"
                     showUploadList={false}
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`claactivityss.${index}.image`]: result.url });
+                      setFieldsValue({ [`index.activity.${index}.image`]: result.url });
                       return Promise.reject();
                       return Promise.reject();
                     })}
                     })}
                   >
                   >
@@ -285,7 +311,7 @@ export default class extends Page {
       <Form>
       <Form>
         <Row>
         <Row>
           {evaluation.map((row, index) => {
           {evaluation.map((row, index) => {
-            const avatar = getFieldValue(`evaluation.${index}.avatar`) || null;
+            const avatar = getFieldValue(`index.evaluation.${index}.avatar`) || null;
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
             return <Col span={7} offset={index % 3 ? 1 : 0}><Card>
               <Button className="delete-button" size="small" onClick={() => {
               <Button className="delete-button" size="small" onClick={() => {
                 this.deleteLength('evaluation', index, 1);
                 this.deleteLength('evaluation', index, 1);
@@ -293,7 +319,7 @@ export default class extends Page {
                 <Icon type="delete" />
                 <Icon type="delete" />
               </Button>
               </Button>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='学员昵称'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='学员昵称'>
-                {getFieldDecorator(`evaluation.${index}.nickname`, {
+                {getFieldDecorator(`index.evaluation.${index}.nickname`, {
                   rules: [
                   rules: [
                     { required: true, message: '输入学员昵称' },
                     { required: true, message: '输入学员昵称' },
                   ],
                   ],
@@ -303,7 +329,7 @@ export default class extends Page {
                 )}
                 )}
               </Form.Item>
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='学员头像'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='学员头像'>
-                {getFieldDecorator(`evaluation.${index}.avatar`, {
+                {getFieldDecorator(`index.evaluation.${index}.avatar`, {
                   rules: [
                   rules: [
                     { required: true, message: '上传图片' },
                     { required: true, message: '上传图片' },
                   ],
                   ],
@@ -312,7 +338,7 @@ export default class extends Page {
                     listType="picture-card"
                     listType="picture-card"
                     showUploadList={false}
                     showUploadList={false}
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
                     beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                      setFieldsValue({ [`evaluation.${index}.avatar`]: result.url });
+                      setFieldsValue({ [`index.evaluation.${index}.avatar`]: result.url });
                       return Promise.reject();
                       return Promise.reject();
                     })}
                     })}
                   >
                   >
@@ -324,7 +350,7 @@ export default class extends Page {
                 )}
                 )}
               </Form.Item>
               </Form.Item>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='评价内容'>
               <Form.Item labelCol={{ span: 7 }} wrapperCol={{ span: 15 }} label='评价内容'>
-                {getFieldDecorator(`evaluation.${index}.content`, {
+                {getFieldDecorator(`index.evaluation.${index}.content`, {
                   rules: [
                   rules: [
                     { required: true, message: '输入评价内容' },
                     { required: true, message: '输入评价内容' },
                   ],
                   ],
@@ -349,13 +375,13 @@ export default class extends Page {
 
 
   renderContact() {
   renderContact() {
     const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
     const { getFieldDecorator, setFieldsValue, getFieldValue } = this.props.form;
-    const wechatImage = getFieldValue('contact.wechatImage');
+    const wechatImage = getFieldValue('base.contact.wechatImage');
-    const weiboImage = getFieldValue('contacct.weiboImage');
+    const weiboImage = getFieldValue('base.contacct.weiboImage');
     return <Block>
     return <Block>
       <Form>
       <Form>
         <h1>联系方式</h1>
         <h1>联系方式</h1>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='电话'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='电话'>
-          {getFieldDecorator('contact.phone', {
+          {getFieldDecorator('base.contact.phone', {
             rules: [
             rules: [
               { required: false, message: '请输入电话' },
               { required: false, message: '请输入电话' },
             ],
             ],
@@ -364,7 +390,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='邮箱'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='邮箱'>
-          {getFieldDecorator('contact.email', {
+          {getFieldDecorator('base.contact.email', {
             rules: [
             rules: [
               { required: false, message: '请输入邮箱' },
               { required: false, message: '请输入邮箱' },
             ],
             ],
@@ -373,7 +399,7 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='微信号'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='微信号'>
-          {getFieldDecorator('contact.wechat', {
+          {getFieldDecorator('base.contact.wechat', {
             rules: [
             rules: [
               { required: false, message: '请输入微信号' },
               { required: false, message: '请输入微信号' },
             ],
             ],
@@ -383,13 +409,13 @@ export default class extends Page {
         </Form.Item>
         </Form.Item>
 
 
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='公众号二维码'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='公众号二维码'>
-          {getFieldDecorator('contact.wechatImage')(
+          {getFieldDecorator('base.contact.wechatImage')(
             <Upload
             <Upload
               listType="picture-card"
               listType="picture-card"
               showUploadList={false}
               showUploadList={false}
               beforeUpload={(file) => {
               beforeUpload={(file) => {
                 System.uploadImage(file).then((result) => {
                 System.uploadImage(file).then((result) => {
-                  setFieldsValue({ 'contact.wechatImage': result.url });
+                  setFieldsValue({ 'base.contact.wechatImage': result.url });
                   return Promise.reject();
                   return Promise.reject();
                 });
                 });
               }
               }
@@ -403,12 +429,12 @@ export default class extends Page {
           )}
           )}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='微博二维码'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='微博二维码'>
-          {getFieldDecorator('contact.weiboImage')(
+          {getFieldDecorator('base.contact.weiboImage')(
             <Upload
             <Upload
               listType="picture-card"
               listType="picture-card"
               showUploadList={false}
               showUploadList={false}
               beforeUpload={(file) => System.uploadImage(file).then((result) => {
               beforeUpload={(file) => System.uploadImage(file).then((result) => {
-                setFieldsValue({ 'contact.weiboImage': result.url });
+                setFieldsValue({ 'base.contact.weiboImage': result.url });
                 return Promise.reject();
                 return Promise.reject();
               })}
               })}
             >
             >

+ 1 - 1
front/project/admin/routes/student/askCourseDetail/page.js

@@ -127,7 +127,7 @@ export default class extends Page {
           {formatDate(createTime)}
           {formatDate(createTime)}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问位置'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问位置'>
-          {`P${courseNo.no}:${position}`}
+          {`P${courseNo.no}:${position}-${position + 5}min`}
         </Form.Item>
         </Form.Item>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问内容'>
         <Form.Item labelCol={{ span: 5 }} wrapperCol={{ span: 16 }} label='提问内容'>
           {originContent}
           {originContent}

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

@@ -29,6 +29,14 @@ export default class SystemStore extends BaseStore {
     return this.apiPut('/setting/index', params);
     return this.apiPut('/setting/index', params);
   }
   }
 
 
+  getBase() {
+    return this.apiGet('/setting/base');
+  }
+
+  setBase(params) {
+    return this.apiPut('/setting/base', params);
+  }
+
   getPlace() {
   getPlace() {
     return this.apiGet('/setting/place');
     return this.apiGet('/setting/place');
   }
   }

+ 7 - 0
front/project/h5/stores/main.js

@@ -21,6 +21,13 @@ export default class MainStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取基础配置
+   */
+  getBase() {
+    return this.apiGet('/base/base');
+  }
+
+  /**
    * 获取广告列表
    * 获取广告列表
    */
    */
   getAd(channel) {
   getAd(channel) {

+ 7 - 3
front/project/www/components/OtherModal/index.js

@@ -679,7 +679,6 @@ export class FeedbackErrorDataModal extends Component {
   onConfirm() {
   onConfirm() {
     const { onConfirm } = this.props;
     const { onConfirm } = this.props;
     const { data } = this.state;
     const { data } = this.state;
-    console.log(data, this.props);
     if (!data.content || !data.originContent) return;
     if (!data.content || !data.originContent) return;
     My.addFeedbackErrorData(
     My.addFeedbackErrorData(
       data.dataId,
       data.dataId,
@@ -819,7 +818,7 @@ export class AskCourseModal extends Component {
         onCancel={() => this.onCancel()}
         onCancel={() => this.onCancel()}
       >
       >
         <div className="t-2 m-b-1 t-s-16">
         <div className="t-2 m-b-1 t-s-16">
-          针对<span className="t-4">课时{courseNo.no}</span>的 <Select theme="white" list={selectList} />
+          针对<span className="t-4">课时{courseNo.no}</span>的 <Select value={data.position} theme="white" list={selectList} />
           进行提问.
           进行提问.
         </div>
         </div>
         <div className="t-2 t-s-16">老师讲解的内容是:</div>
         <div className="t-2 t-s-16">老师讲解的内容是:</div>
@@ -896,7 +895,12 @@ export class CourseNoteModal extends Component {
       >
       >
         <div className="t-2 m-b-1 t-s-16">
         <div className="t-2 m-b-1 t-s-16">
           {course.title}
           {course.title}
-          <Select theme="white" value={data.courseNoId} list={courseNos} onChange={(item) => {
+          <Select theme="white" value={data.courseNoId} list={courseNos.map(row => {
+            return {
+              title: `课时${row.no}`,
+              key: row.id,
+            };
+          })} onChange={(item) => {
             data.courseNoId = item.id;
             data.courseNoId = item.id;
             this.setState({ data });
             this.setState({ data });
           }} />
           }} />

+ 2 - 2
front/project/www/routes/my/answer/page.js

@@ -158,7 +158,7 @@ export default class extends Page {
     this.initData();
     this.initData();
   }
   }
 
 
-  onAction() {}
+  onAction() { }
 
 
   onSelect(selectList) {
   onSelect(selectList) {
     this.setState({ selectList });
     this.setState({ selectList });
@@ -295,7 +295,7 @@ export default class extends Page {
                 )}
                 )}
                 {item.answerStatus > 0 && (
                 {item.answerStatus > 0 && (
                   <div className="desc">
                   <div className="desc">
-                    <OpenText>{item.answer}</OpenText>
+                    <OpenText>{item.answerStatus === 2 ? '与题目内容无关,老师无法作出回答,敬请谅解。' : item.answer}</OpenText>
                   </div>
                   </div>
                 )}
                 )}
               </div>
               </div>

+ 4 - 0
front/project/www/stores/course.js

@@ -16,6 +16,10 @@ export default class CourseStore extends BaseStore {
     return this.apiGet('/course/simple', { courseId });
     return this.apiGet('/course/simple', { courseId });
   }
   }
 
 
+  listAsk({ keyword, courseId, courseNoId, position, order, direction }) {
+    return this.apiGet('/course/ask/list', { keyword, courseId, courseNoId, position, order, direction });
+  }
+
   noProgress(courseId, courseNoId, progress, time, currentCourseNoId) {
   noProgress(courseId, courseNoId, progress, time, currentCourseNoId) {
     return this.apiPut('/course/no/progress', { courseId, courseNoId, progress, time, currentCourseNoId });
     return this.apiPut('/course/no/progress', { courseId, courseNoId, progress, time, currentCourseNoId });
   }
   }

+ 7 - 0
front/project/www/stores/main.js

@@ -17,6 +17,13 @@ export default class MainStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取基础配置
+   */
+  getBase() {
+    return this.apiGet('/base/base');
+  }
+
+  /**
    * 获取广告列表
    * 获取广告列表
    */
    */
   getAd(channel) {
   getAd(channel) {

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

@@ -257,6 +257,18 @@ export default class MyStore extends BaseStore {
   }
   }
 
 
   /**
   /**
+   * 获取笔记列表
+   * @param {*} page
+   * @param {*} size
+   * @param {*} startTime
+   * @param {*} endTime
+   * @param {*} order
+   */
+  listQuestionNote({ keyword, module, questionTypes, structIds, latest, year, page, size, startTime, endTime, order }) {
+    return this.apiGet('/my/note/question/list', { keyword, module, questionTypes, structIds, latest, year, page, size, startTime, endTime, order });
+  }
+
+  /**
    * 更新课程笔记
    * 更新课程笔记
    * @param {*} courseId
    * @param {*} courseId
    * @param {*} courseNoId
    * @param {*} courseNoId
@@ -266,6 +278,10 @@ export default class MyStore extends BaseStore {
     return this.apiPut('/my/note/course', { courseId, courseNoId, content });
     return this.apiPut('/my/note/course', { courseId, courseNoId, content });
   }
   }
 
 
+  clearCourseNote(courseNoIds) {
+    return this.apiPost('/my/note/course/clear', { courseNoIds });
+  }
+
   /**
   /**
    * 获取笔记列表
    * 获取笔记列表
    * @param {*} page
    * @param {*} page
@@ -274,8 +290,8 @@ export default class MyStore extends BaseStore {
    * @param {*} endTime
    * @param {*} endTime
    * @param {*} order
    * @param {*} order
    */
    */
-  listQuestionNote({ keyword, module, questionTypes, structIds, latest, year, page, size, startTime, endTime, order }) {
+  listCourseNote({ keyword, courseId, page, size, order, direction }) {
-    return this.apiGet('/my/note/question/list', { keyword, module, questionTypes, structIds, latest, year, page, size, startTime, endTime, order });
+    return this.apiGet('/my/note/course/list', { keyword, courseId, page, size, order, direction });
   }
   }
 
 
   /**
   /**
@@ -327,6 +343,10 @@ export default class MyStore extends BaseStore {
     return this.apiPost('/my/ask/course', { courseId, courseNoId, position, originContent, content });
     return this.apiPost('/my/ask/course', { courseId, courseNoId, position, originContent, content });
   }
   }
 
 
+  listCourseAsk({ keyword, courseId, courseNoId, order, direction }) {
+    return this.apiGet('/my/ask/course/list', { keyword, courseId, courseNoId, order, direction });
+  }
+
   /**
   /**
    * 添加题目勘误
    * 添加题目勘误
    * @param {*} questionNoId
    * @param {*} questionNoId

+ 21 - 5
front/project/www/stores/order.js

@@ -2,19 +2,35 @@ import BaseStore from '@src/stores/base';
 
 
 export default class OrderStore extends BaseStore {
 export default class OrderStore extends BaseStore {
   allCheckout() {
   allCheckout() {
-    return this.apiGet('/order/checkout/all');
+    return this.apiGet('/order/checkout/all')
+      .then(result => {
+        this.setState({ number: result.checkouts.length });
+        return result;
+      });
   }
   }
 
 
   addCheckout({ productType, productId, service, param, number }) {
   addCheckout({ productType, productId, service, param, number }) {
-    return this.apiPost('/order/checkout/add', { productType, productId, service, param, number });
+    return this.apiPost('/order/checkout/add', { productType, productId, service, param, number })
+      .then(result => {
+        this.setState({ number: result });
+        return result;
+      });
   }
   }
 
 
   changeCheckout(id, number) {
   changeCheckout(id, number) {
-    return this.apiPut('/order/checkout/number', { id, number });
+    return this.apiPut('/order/checkout/number', { id, number })
+      .then(result => {
+        this.setState({ number: result });
+        return result;
+      });
   }
   }
 
 
   removeCheckout(id) {
   removeCheckout(id) {
-    return this.apiDel('/order/checkout/delete', { id });
+    return this.apiDel('/order/checkout/delete', { id })
+      .then(result => {
+        this.setState({ number: result });
+        return result;
+      });
   }
   }
 
 
   confirmPay(courseId) {
   confirmPay(courseId) {
@@ -78,4 +94,4 @@ export default class OrderStore extends BaseStore {
   }
   }
 }
 }
 
 
-export const Order = new OrderStore({ key: 'order' });
+export const Order = new OrderStore({ key: 'order', local: true });

+ 2 - 0
server/data/src/main/java/com/qxgmat/data/constants/enums/MessageCategory.java

@@ -17,6 +17,8 @@ public enum MessageCategory {
 
 
     INVITED("invited", "邀请好友注册"),
     INVITED("invited", "邀请好友注册"),
     EMAIL_CHANGE("email_change", "邮箱变更"),
     EMAIL_CHANGE("email_change", "邮箱变更"),
+    EMAIL_UNNBIND("email_unbind", "邮箱解绑"),
+    EMAIL_BIND("email_bind", "邮箱绑定"),
 
 
     CUSTOM("custom", "自定义消息")
     CUSTOM("custom", "自定义消息")
     ;
     ;

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

@@ -32,6 +32,7 @@ public enum SettingKey {
     WECHAT_INFO("wechat_info"), // 微信公众号信息
     WECHAT_INFO("wechat_info"), // 微信公众号信息
     READY_READ("ready_read"), // 推荐阅读设置
     READY_READ("ready_read"), // 推荐阅读设置
 
 
+    BASE("base"), // 基础设置
     TIPS("tips"); // 页面提示信息
     TIPS("tips"); // 页面提示信息
 
 
     final static public String message = "设置key";
     final static public String message = "设置key";

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

@@ -39,7 +39,7 @@ public class UserAskCourse implements Serializable {
      * 位置
      * 位置
      */
      */
     @Column(name = "`position`")
     @Column(name = "`position`")
-    private String position;
+    private Integer position;
 
 
     /**
     /**
      * 提问优先回答时间
      * 提问优先回答时间
@@ -200,7 +200,7 @@ public class UserAskCourse implements Serializable {
      *
      *
      * @return position - 位置
      * @return position - 位置
      */
      */
-    public String getPosition() {
+    public Integer getPosition() {
         return position;
         return position;
     }
     }
 
 
@@ -209,7 +209,7 @@ public class UserAskCourse implements Serializable {
      *
      *
      * @param position 位置
      * @param position 位置
      */
      */
-    public void setPosition(String position) {
+    public void setPosition(Integer position) {
         this.position = position;
         this.position = position;
     }
     }
 
 
@@ -513,7 +513,7 @@ public class UserAskCourse implements Serializable {
          *
          *
          * @param position 位置
          * @param position 位置
          */
          */
-        public Builder position(String position) {
+        public Builder position(Integer position) {
             obj.setPosition(position);
             obj.setPosition(position);
             return this;
             return this;
         }
         }

+ 52 - 0
server/data/src/main/java/com/qxgmat/data/dao/entity/UserExport.java

@@ -15,6 +15,9 @@ public class UserExport implements Serializable {
     @Column(name = "`user_id`")
     @Column(name = "`user_id`")
     private Integer userId;
     private Integer userId;
 
 
+    @Column(name = "`no`")
+    private Integer no;
+
     /**
     /**
      * 导出类型
      * 导出类型
      */
      */
@@ -30,6 +33,9 @@ public class UserExport implements Serializable {
     @Column(name = "`create_time`")
     @Column(name = "`create_time`")
     private Date createTime;
     private Date createTime;
 
 
+    @Column(name = "`content`")
+    private String content;
+
     private static final long serialVersionUID = 1L;
     private static final long serialVersionUID = 1L;
 
 
     /**
     /**
@@ -61,6 +67,20 @@ public class UserExport implements Serializable {
     }
     }
 
 
     /**
     /**
+     * @return no
+     */
+    public Integer getNo() {
+        return no;
+    }
+
+    /**
+     * @param no
+     */
+    public void setNo(Integer no) {
+        this.no = no;
+    }
+
+    /**
      * 获取导出类型
      * 获取导出类型
      *
      *
      * @return type - 导出类型
      * @return type - 导出类型
@@ -110,6 +130,20 @@ public class UserExport implements Serializable {
         this.createTime = createTime;
         this.createTime = createTime;
     }
     }
 
 
+    /**
+     * @return content
+     */
+    public String getContent() {
+        return content;
+    }
+
+    /**
+     * @param content
+     */
+    public void setContent(String content) {
+        this.content = content;
+    }
+
     @Override
     @Override
     public String toString() {
     public String toString() {
         StringBuilder sb = new StringBuilder();
         StringBuilder sb = new StringBuilder();
@@ -118,9 +152,11 @@ public class UserExport implements Serializable {
         sb.append("Hash = ").append(hashCode());
         sb.append("Hash = ").append(hashCode());
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", userId=").append(userId);
+        sb.append(", no=").append(no);
         sb.append(", type=").append(type);
         sb.append(", type=").append(type);
         sb.append(", setting=").append(setting);
         sb.append(", setting=").append(setting);
         sb.append(", createTime=").append(createTime);
         sb.append(", createTime=").append(createTime);
+        sb.append(", content=").append(content);
         sb.append("]");
         sb.append("]");
         return sb.toString();
         return sb.toString();
     }
     }
@@ -153,6 +189,14 @@ public class UserExport implements Serializable {
         }
         }
 
 
         /**
         /**
+         * @param no
+         */
+        public Builder no(Integer no) {
+            obj.setNo(no);
+            return this;
+        }
+
+        /**
          * 设置导出类型
          * 设置导出类型
          *
          *
          * @param type 导出类型
          * @param type 导出类型
@@ -180,6 +224,14 @@ public class UserExport implements Serializable {
             return this;
             return this;
         }
         }
 
 
+        /**
+         * @param content
+         */
+        public Builder content(String content) {
+            obj.setContent(content);
+            return this;
+        }
+
         public UserExport build() {
         public UserExport build() {
             return this.obj;
             return this.obj;
         }
         }

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

@@ -18,12 +18,18 @@ public class UserMessage implements Serializable {
     private Integer userId;
     private Integer userId;
 
 
     /**
     /**
-     * 消息类型
+     * 消息
      */
      */
     @Column(name = "`type`")
     @Column(name = "`type`")
     private String type;
     private String type;
 
 
     /**
     /**
+     * 消息类型
+     */
+    @Column(name = "`message_category`")
+    private String messageCategory;
+
+    /**
      * 标题
      * 标题
      */
      */
     @Column(name = "`title`")
     @Column(name = "`title`")
@@ -85,24 +91,42 @@ public class UserMessage implements Serializable {
     }
     }
 
 
     /**
     /**
-     * 获取消息类型
+     * 获取消息
      *
      *
-     * @return type - 消息类型
+     * @return type - 消息
      */
      */
     public String getType() {
     public String getType() {
         return type;
         return type;
     }
     }
 
 
     /**
     /**
-     * 设置消息类型
+     * 设置消息
      *
      *
-     * @param type 消息类型
+     * @param type 消息
      */
      */
     public void setType(String type) {
     public void setType(String type) {
         this.type = type;
         this.type = type;
     }
     }
 
 
     /**
     /**
+     * 获取消息类型
+     *
+     * @return message_category - 消息类型
+     */
+    public String getMessageCategory() {
+        return messageCategory;
+    }
+
+    /**
+     * 设置消息类型
+     *
+     * @param messageCategory 消息类型
+     */
+    public void setMessageCategory(String messageCategory) {
+        this.messageCategory = messageCategory;
+    }
+
+    /**
      * 获取标题
      * 获取标题
      *
      *
      * @return title - 标题
      * @return title - 标题
@@ -197,6 +221,7 @@ public class UserMessage implements Serializable {
         sb.append(", id=").append(id);
         sb.append(", id=").append(id);
         sb.append(", userId=").append(userId);
         sb.append(", userId=").append(userId);
         sb.append(", type=").append(type);
         sb.append(", type=").append(type);
+        sb.append(", messageCategory=").append(messageCategory);
         sb.append(", title=").append(title);
         sb.append(", title=").append(title);
         sb.append(", link=").append(link);
         sb.append(", link=").append(link);
         sb.append(", isRead=").append(isRead);
         sb.append(", isRead=").append(isRead);
@@ -236,9 +261,9 @@ public class UserMessage implements Serializable {
         }
         }
 
 
         /**
         /**
-         * 设置消息类型
+         * 设置消息
          *
          *
-         * @param type 消息类型
+         * @param type 消息
          */
          */
         public Builder type(String type) {
         public Builder type(String type) {
             obj.setType(type);
             obj.setType(type);
@@ -246,6 +271,16 @@ public class UserMessage implements Serializable {
         }
         }
 
 
         /**
         /**
+         * 设置消息类型
+         *
+         * @param messageCategory 消息类型
+         */
+        public Builder messageCategory(String messageCategory) {
+            obj.setMessageCategory(messageCategory);
+            return this;
+        }
+
+        /**
          * 设置标题
          * 设置标题
          *
          *
          * @param title 标题
          * @param title 标题

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

@@ -10,7 +10,7 @@
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
     <result column="course_id" jdbcType="INTEGER" property="courseId" />
     <result column="course_no_id" jdbcType="INTEGER" property="courseNoId" />
     <result column="course_no_id" jdbcType="INTEGER" property="courseNoId" />
     <result column="record_id" jdbcType="INTEGER" property="recordId" />
     <result column="record_id" jdbcType="INTEGER" property="recordId" />
-    <result column="position" jdbcType="VARCHAR" property="position" />
+    <result column="position" jdbcType="INTEGER" property="position" />
     <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="ask_time" jdbcType="INTEGER" property="askTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
     <result column="expire_time" jdbcType="TIMESTAMP" property="expireTime" />
     <result column="answer_status" jdbcType="INTEGER" property="answerStatus" />
     <result column="answer_status" jdbcType="INTEGER" property="answerStatus" />

+ 14 - 1
server/data/src/main/java/com/qxgmat/data/dao/mapping/UserExportMapper.xml

@@ -7,14 +7,27 @@
     -->
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
+    <result column="no" jdbcType="INTEGER" property="no" />
     <result column="type" jdbcType="VARCHAR" property="type" />
     <result column="type" jdbcType="VARCHAR" property="type" />
     <result column="setting" jdbcType="VARCHAR" property="setting" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="setting" jdbcType="VARCHAR" property="setting" typeHandler="com.nuliji.tools.mybatis.handler.JsonObjectHandler" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
     <result column="create_time" jdbcType="TIMESTAMP" property="createTime" />
   </resultMap>
   </resultMap>
+  <resultMap extends="BaseResultMap" id="ResultMapWithBLOBs" type="com.qxgmat.data.dao.entity.UserExport">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <result column="content" jdbcType="LONGVARCHAR" property="content" />
+  </resultMap>
   <sql id="Base_Column_List">
   <sql id="Base_Column_List">
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `type`, `setting`, `create_time`
+    `id`, `user_id`, `no`, `type`, `setting`, `create_time`
+  </sql>
+  <sql id="Blob_Column_List">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    `content`
   </sql>
   </sql>
 </mapper>
 </mapper>

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

@@ -8,6 +8,7 @@
     <id column="id" jdbcType="INTEGER" property="id" />
     <id column="id" jdbcType="INTEGER" property="id" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="user_id" jdbcType="INTEGER" property="userId" />
     <result column="type" jdbcType="VARCHAR" property="type" />
     <result column="type" jdbcType="VARCHAR" property="type" />
+    <result column="message_category" jdbcType="VARCHAR" property="messageCategory" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="title" jdbcType="VARCHAR" property="title" />
     <result column="link" jdbcType="VARCHAR" property="link" />
     <result column="link" jdbcType="VARCHAR" property="link" />
     <result column="is_read" jdbcType="INTEGER" property="isRead" />
     <result column="is_read" jdbcType="INTEGER" property="isRead" />
@@ -23,7 +24,7 @@
     <!--
     <!--
       WARNING - @mbg.generated
       WARNING - @mbg.generated
     -->
     -->
-    `id`, `user_id`, `type`, `title`, `link`, `is_read`, `create_time`
+    `id`, `user_id`, `type`, `message_category`, `title`, `link`, `is_read`, `create_time`
   </sql>
   </sql>
   <sql id="Blob_Column_List">
   <sql id="Blob_Column_List">
     <!--
     <!--

+ 18 - 12
server/data/src/main/resources/db/migration/V1__init_table.sql

@@ -730,7 +730,8 @@ VALUES
 	(21,'experience_info','{}'),
 	(21,'experience_info','{}'),
 	(22,'sentence_info','{}'),
 	(22,'sentence_info','{}'),
 	(23,'wechat_info','{}'),
 	(23,'wechat_info','{}'),
-	(24,'ready_read','{}');
+	(24,'ready_read','{}'),
+	(25,'base','{}');
 
 
 CREATE TABLE textbook_library (
 CREATE TABLE textbook_library (
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
@@ -973,7 +974,7 @@ CREATE TABLE user_ask_course (
   course_id int(11) unsigned NOT NULL COMMENT '课程id',
   course_id int(11) unsigned NOT NULL COMMENT '课程id',
   course_no_id int(11) unsigned NOT NULL COMMENT '课时id',
   course_no_id int(11) unsigned NOT NULL COMMENT '课时id',
   record_id int(11) unsigned NOT NULL COMMENT '记录id',
   record_id int(11) unsigned NOT NULL COMMENT '记录id',
-  position varchar(20) NOT NULL DEFAULT '' COMMENT '位置',
+  position int(11) unsigned NOT NULL DEFAULT '0' COMMENT '位置',
   origin_content text COMMENT '老师讲解内容',
   origin_content text COMMENT '老师讲解内容',
   content text COMMENT '提问',
   content text COMMENT '提问',
   ask_time int(11) unsigned NOT NULL DEFAULT '0' COMMENT '提问优先回答时间',
   ask_time int(11) unsigned NOT NULL DEFAULT '0' COMMENT '提问优先回答时间',
@@ -1084,7 +1085,9 @@ CREATE TABLE user_course_appointment_comment (
   name varchar(255) DEFAULT NULL,
   name varchar(255) DEFAULT NULL,
   create_time datetime DEFAULT NULL,
   create_time datetime DEFAULT NULL,
   delete_time datetime DEFAULT NULL,
   delete_time datetime DEFAULT NULL,
-  PRIMARY KEY (`id`)
+  PRIMARY KEY (`id`),
+  KEY record_id (record_id),
+  KEY appointment_id (appointment_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-预约-聊天';
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-预约-聊天';
 
 
 CREATE TABLE user_course_progress (
 CREATE TABLE user_course_progress (
@@ -1111,14 +1114,16 @@ CREATE TABLE user_course_record (
   KEY user_id (user_id,course_id,record_id)
   KEY user_id (user_id,course_id,record_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-课程-访问记录';
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-课程-访问记录';
 
 
-CREATE TABLE `user_export` (
+CREATE TABLE user_export (
-  `id` int(11) unsigned NOT NULL AUTO_INCREMENT,
+  id int(11) unsigned NOT NULL AUTO_INCREMENT,
-  `user_id` int(11) unsigned NOT NULL DEFAULT '0',
+  user_id int(11) unsigned NOT NULL DEFAULT '0',
-  `type` varchar(20) NOT NULL DEFAULT '' COMMENT '导出类型',
+  no int(11) unsigned NOT NULL DEFAULT '0',
-  `setting` text COMMENT '导出设置',
+  type varchar(20) NOT NULL DEFAULT '' COMMENT '导出类型',
-  `content` longtext,
+  setting text COMMENT '导出设置',
-  `create_time` datetime DEFAULT NULL,
+  content longtext,
-  PRIMARY KEY (`id`)
+  create_time datetime DEFAULT NULL,
+  PRIMARY KEY (id),
+  KEY user_id (user_id)
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-导出-记录';
 ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='用户-导出-记录';
 
 
 CREATE TABLE user_feedback_error (
 CREATE TABLE user_feedback_error (
@@ -1163,7 +1168,8 @@ CREATE TABLE user_invoice (
 CREATE TABLE user_message (
 CREATE TABLE user_message (
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   id int(11) unsigned NOT NULL AUTO_INCREMENT,
   user_id int(11) NOT NULL DEFAULT '0' COMMENT '用户id',
   user_id int(11) NOT NULL DEFAULT '0' COMMENT '用户id',
-  type varchar(50) NOT NULL DEFAULT '' COMMENT '消息类型',
+  type varchar(50) NOT NULL DEFAULT '' COMMENT '消息',
+  message_category varchar(50) NOT NULL DEFAULT '' COMMENT '消息类型',
   title varchar(50) NOT NULL DEFAULT '' COMMENT '标题',
   title varchar(50) NOT NULL DEFAULT '' COMMENT '标题',
   content text COMMENT '内容',
   content text COMMENT '内容',
   link varchar(255) NOT NULL DEFAULT '' COMMENT '链接',
   link varchar(255) NOT NULL DEFAULT '' COMMENT '链接',

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

@@ -114,6 +114,23 @@ public class SettingController {
         return ResponseHelp.success(entity.getValue());
         return ResponseHelp.success(entity.getValue());
     }
     }
 
 
+    @RequestMapping(value = "/base", method = RequestMethod.PUT)
+    @ApiOperation(value = "修改基础配置", httpMethod = "PUT")
+    private Response<Boolean> editBase(@RequestBody @Validated JSONObject dto){
+        Setting entity = settingService.getByKey(SettingKey.BASE);
+        entity.setValue(dto);
+        settingService.edit(entity);
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/base", method = RequestMethod.GET)
+    @ApiOperation(value = "获取基础配置", httpMethod = "GET")
+    private Response<JSONObject> getBase(){
+        Setting entity = settingService.getByKey(SettingKey.BASE);
+        logger.debug("{}", entity);
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/place", method = RequestMethod.PUT)
     @RequestMapping(value = "/place", method = RequestMethod.PUT)
     @ApiOperation(value = "修改考点设置", httpMethod = "PUT")
     @ApiOperation(value = "修改考点设置", httpMethod = "PUT")
     private Response<Boolean> editPlace(@RequestBody @Validated JSONObject dto){
     private Response<Boolean> editPlace(@RequestBody @Validated JSONObject dto){

+ 7 - 0
server/gateway-api/src/main/java/com/qxgmat/controller/api/BaseController.java

@@ -86,6 +86,13 @@ public class BaseController {
         return ResponseHelp.success(entity.getValue());
         return ResponseHelp.success(entity.getValue());
     }
     }
 
 
+    @RequestMapping(value = "/base", method = RequestMethod.GET)
+    @ApiOperation(value = "获取基础配置", httpMethod = "GET")
+    private Response<JSONObject> base(){
+        Setting entity = settingService.getByKey(SettingKey.BASE);
+        return ResponseHelp.success(entity.getValue());
+    }
+
     @RequestMapping(value = "/ad", method = RequestMethod.GET)
     @RequestMapping(value = "/ad", method = RequestMethod.GET)
     @ApiOperation(value = "获取广告", notes = "获取广告列表", httpMethod = "GET")
     @ApiOperation(value = "获取广告", notes = "获取广告列表", httpMethod = "GET")
     public Response<List<Ad>> ad(
     public Response<List<Ad>> ad(

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

@@ -94,6 +94,9 @@ public class CourseController {
     private UserCourseRecordService userCourseRecordService;
     private UserCourseRecordService userCourseRecordService;
 
 
     @Autowired
     @Autowired
+    private UserAskCourseService userAskCourseService;
+
+    @Autowired
     private UserOrderRecordService userOrderRecordService;
     private UserOrderRecordService userOrderRecordService;
 
 
     @Autowired
     @Autowired
@@ -157,6 +160,24 @@ public class CourseController {
         return ResponseHelp.success(dto);
         return ResponseHelp.success(dto);
     }
     }
 
 
+    @RequestMapping(value = "/ask/list", method = RequestMethod.GET)
+    @ApiOperation(value = "精选问答", httpMethod = "GET")
+    public Response<PageMessage<UserAskCourse>> listAsk(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) Integer courseNoId,
+            @RequestParam(required = false) Integer position,
+            @RequestParam(required = false) String order, // create_time, answer_time
+            @RequestParam(required = false) String direction
+    ) {
+        User user = (User) shiroHelp.getLoginUser();
+        Page<UserAskCourse> pr = userAskCourseService.listByCourse(page, size, keyword, courseId, courseNoId, position, true, order, DirectionStatus.ValueOf(direction));
+
+        return ResponseHelp.success(pr, page, size, pr.getTotal());
+    }
+
     @RequestMapping(value = "/simple", method = RequestMethod.GET)
     @RequestMapping(value = "/simple", method = RequestMethod.GET)
     @ApiOperation(value = "课程基本信息", httpMethod = "GET")
     @ApiOperation(value = "课程基本信息", httpMethod = "GET")
     public Response<Course> simple(
     public Response<Course> simple(

+ 60 - 24
server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java

@@ -12,7 +12,6 @@ import com.qxgmat.data.constants.enums.module.*;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.AskStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.constants.enums.user.DataType;
-import com.qxgmat.data.constants.enums.user.ExportType;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.inline.PaperStat;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.inline.UserQuestionStat;
@@ -223,11 +222,12 @@ public class MyController {
     @ApiOperation(value = "绑定邮箱", httpMethod = "POST")
     @ApiOperation(value = "绑定邮箱", httpMethod = "POST")
     public Response<Boolean> email(@RequestBody @Validated UserEmailDto dto, HttpSession session, HttpServletRequest request) {
     public Response<Boolean> email(@RequestBody @Validated UserEmailDto dto, HttpSession session, HttpServletRequest request) {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
+        User in = usersService.get(user.getId());
         usersService.edit(User.builder()
         usersService.edit(User.builder()
                 .id(user.getId())
                 .id(user.getId())
                 .email(dto.getEmail())
                 .email(dto.getEmail())
                 .build());
                 .build());
-        messageExtendService.sendEmailChange(user);
+        messageExtendService.sendEmailChange(user, in.getEmail());
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
@@ -874,7 +874,7 @@ public class MyController {
 
 
     @RequestMapping(value = "/collect/question/clear", method = RequestMethod.DELETE)
     @RequestMapping(value = "/collect/question/clear", method = RequestMethod.DELETE)
     @ApiOperation(value = "移除题目收藏", notes = "移除题目收藏", httpMethod = "DELETE")
     @ApiOperation(value = "移除题目收藏", notes = "移除题目收藏", httpMethod = "DELETE")
-    public Response<Boolean> deleteQuestionCollect(@RequestBody @Validated UserQuestionIdsDto dto)  {
+    public Response<Boolean> clearQuestionCollect(@RequestBody @Validated UserQuestionNoIdsDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
         for(QuestionNo questionNo : questionNoList){
         for(QuestionNo questionNo : questionNoList){
@@ -1077,7 +1077,7 @@ public class MyController {
 
 
     @RequestMapping(value = "/error/clear", method = RequestMethod.POST)
     @RequestMapping(value = "/error/clear", method = RequestMethod.POST)
     @ApiOperation(value = "错题移除", notes = "错题移除", httpMethod = "POST")
     @ApiOperation(value = "错题移除", notes = "错题移除", httpMethod = "POST")
-    public Response<Boolean> clearError(@RequestBody @Validated UserQuestionIdsDto dto)  {
+    public Response<Boolean> clearError(@RequestBody @Validated UserQuestionNoIdsDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
 
 
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
@@ -1127,7 +1127,7 @@ public class MyController {
 
 
     @RequestMapping(value = "/note/question/clear", method = RequestMethod.POST)
     @RequestMapping(value = "/note/question/clear", method = RequestMethod.POST)
     @ApiOperation(value = "笔记移除", notes = "笔记移除", httpMethod = "POST")
     @ApiOperation(value = "笔记移除", notes = "笔记移除", httpMethod = "POST")
-    public Response<Boolean> clearNoteQuestion(@RequestBody @Validated UserQuestionIdsDto dto)  {
+    public Response<Boolean> clearNoteQuestion(@RequestBody @Validated UserQuestionNoIdsDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
         List<QuestionNo> questionNoList = questionNoService.select(dto.getQuestionNoIds());
         for(QuestionNo questionNo : questionNoList){
         for(QuestionNo questionNo : questionNoList){
@@ -1196,6 +1196,33 @@ public class MyController {
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
+    @RequestMapping(value = "/note/course/clear", method = RequestMethod.POST)
+    @ApiOperation(value = "笔记移除", notes = "笔记移除", httpMethod = "POST")
+    public Response<Boolean> clearNoteCourse(@RequestBody @Validated UserCourseNoIdsDto dto)  {
+        User user = (User) shiroHelp.getLoginUser();
+        List<CourseNo> courseNoList = courseNoService.select(dto.getCourseNoIds());
+        for(CourseNo courseNo : courseNoList){
+            userNoteCourseService.deleteNote(user.getId(), courseNo.getId());
+        }
+        return ResponseHelp.success(true);
+    }
+
+    @RequestMapping(value = "/note/course/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取课程笔记列表", notes = "获取笔记列表", httpMethod = "GET")
+    public Response<PageMessage<UserNoteCourse>> listNoteCourse(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) String order, // update_time, no
+            @RequestParam(required = false) String direction,
+            HttpSession session)  {
+        User user = (User) shiroHelp.getLoginUser();
+        Page<UserNoteCourse> p = userNoteCourseService.listByCourse(page, size, keyword, user.getId(), courseId, order, DirectionStatus.ValueOf(direction));
+
+        return ResponseHelp.success(p, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/report/list", method = RequestMethod.GET)
     @RequestMapping(value = "/report/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取报告列表", notes = "获取报告列表", httpMethod = "GET")
     @ApiOperation(value = "获取报告列表", notes = "获取报告列表", httpMethod = "GET")
     public Response<PageMessage<UserPaperDto>> listReport(
     public Response<PageMessage<UserPaperDto>> listReport(
@@ -1405,6 +1432,24 @@ public class MyController {
         return ResponseHelp.success(true);
         return ResponseHelp.success(true);
     }
     }
 
 
+    @RequestMapping(value = "/ask/course/list", method = RequestMethod.GET)
+    @ApiOperation(value = "获取课程提问列表", notes = "获取课程提问列表", httpMethod = "GET")
+    public Response<PageMessage<UserAskCourse>> listAskCourse(
+            @RequestParam(required = false, defaultValue = "1") int page,
+            @RequestParam(required = false, defaultValue = "100") int size,
+            @RequestParam(required = false) String keyword,
+            @RequestParam(required = false) Integer courseId,
+            @RequestParam(required = false) Integer courseNoId,
+            @RequestParam(required = false) Integer askStatus,
+            @RequestParam(required = false) String order, // create_time, answer_time
+            @RequestParam(required = false) String direction,
+            HttpSession session)  {
+        User user = (User) shiroHelp.getLoginUser();
+        Page<UserAskCourse> p = userAskCourseService.listByUser(page, size, keyword, user.getId(), courseId, courseNoId, AskStatus.ValueOf(askStatus), order, DirectionStatus.ValueOf(direction));
+
+        return ResponseHelp.success(p, page, size, p.getTotal());
+    }
+
     @RequestMapping(value = "/feedback/error/question", method = RequestMethod.POST)
     @RequestMapping(value = "/feedback/error/question", method = RequestMethod.POST)
     @ApiOperation(value = "添加题目勘误", notes = "添加勘误", httpMethod = "POST")
     @ApiOperation(value = "添加题目勘误", notes = "添加勘误", httpMethod = "POST")
     public Response<Boolean> addFeedbackErrorQuestion(@RequestBody @Validated UserFeedbackErrorQuestionDto dto)  {
     public Response<Boolean> addFeedbackErrorQuestion(@RequestBody @Validated UserFeedbackErrorQuestionDto dto)  {
@@ -1894,38 +1939,29 @@ public class MyController {
 
 
     @RequestMapping(value = "/export/question", method = RequestMethod.POST)
     @RequestMapping(value = "/export/question", method = RequestMethod.POST)
     @ApiOperation(value = "导出题目", notes = "导出题目", httpMethod = "POST")
     @ApiOperation(value = "导出题目", notes = "导出题目", httpMethod = "POST")
-    public Response<UserExport> exportQuestion(@RequestBody @Validated UserExportDto dto)  {
+    public Response<Integer> exportQuestion(@RequestBody @Validated UserExportDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
-        UserExport entity = Transform.dtoToEntity(dto);
+        UserExport entity = exportService.addQuestion(user.getId(), JSONObject.parseObject(JSONObject.toJSONString(dto.getSetting())));
-        entity.setUserId(user.getId());
+        return ResponseHelp.success(entity.getId());
-        entity.setType(ExportType.QUESTION.key);
-        entity = userExportService.add(entity);
-        return ResponseHelp.success(entity);
     }
     }
 
 
     @RequestMapping(value = "/export/note/question", method = RequestMethod.POST)
     @RequestMapping(value = "/export/note/question", method = RequestMethod.POST)
     @ApiOperation(value = "导出题目笔记", notes = "导出题目笔记", httpMethod = "POST")
     @ApiOperation(value = "导出题目笔记", notes = "导出题目笔记", httpMethod = "POST")
-    public Response<UserExport> exportNoteQuestion(@RequestBody @Validated UserExportDto dto)  {
+    public Response<Integer> exportNoteQuestion(@RequestBody @Validated UserExportDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
-        UserExport entity = Transform.dtoToEntity(dto);
+        UserExport entity = exportService.addQuestionNote(user.getId(), JSONObject.parseObject(JSONObject.toJSONString(dto.getSetting())));
-        entity.setUserId(user.getId());
+        return ResponseHelp.success(entity.getId());
-        entity.setType(ExportType.NOTE_QUESTION.key);
-        entity = userExportService.add(entity);
-        return ResponseHelp.success(entity);
     }
     }
 
 
     @RequestMapping(value = "/export/note/course", method = RequestMethod.POST)
     @RequestMapping(value = "/export/note/course", method = RequestMethod.POST)
     @ApiOperation(value = "导出课程笔记", notes = "导出课程笔记", httpMethod = "POST")
     @ApiOperation(value = "导出课程笔记", notes = "导出课程笔记", httpMethod = "POST")
-    public Response<UserExport> exportNoteCourse(@RequestBody @Validated UserExportDto dto)  {
+    public Response<Integer> exportNoteCourse(@RequestBody @Validated UserExportDto dto)  {
         User user = (User) shiroHelp.getLoginUser();
         User user = (User) shiroHelp.getLoginUser();
-        UserExport entity = Transform.dtoToEntity(dto);
+        UserExport entity = exportService.addCourseNote(user.getId(), JSONObject.parseObject(JSONObject.toJSONString(dto.getSetting())));
-        entity.setUserId(user.getId());
+        return ResponseHelp.success(entity.getId());
-        entity.setType(ExportType.NOTE_COURSE.key);
-        entity = userExportService.add(entity);
-        return ResponseHelp.success(entity);
     }
     }
 
 
-    @RequestMapping(value = "/export/note/course", method = RequestMethod.GET)
+    @RequestMapping(value = "/export/detail", method = RequestMethod.GET)
     @ApiOperation(value = "导出详情", notes = "导出详情", httpMethod = "GET")
     @ApiOperation(value = "导出详情", notes = "导出详情", httpMethod = "GET")
     public Response<UserExport> exportDetail(int id)  {
     public Response<UserExport> exportDetail(int id)  {
         UserExport entity = userExportService.get(id);
         UserExport entity = userExportService.get(id);

+ 3 - 3
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserAskCourseDto.java

@@ -9,7 +9,7 @@ public class UserAskCourseDto {
 
 
     private Integer courseNoId;
     private Integer courseNoId;
 
 
-    private String position;
+    private Integer position;
 
 
     private String originContent;
     private String originContent;
 
 
@@ -31,11 +31,11 @@ public class UserAskCourseDto {
         this.courseNoId = courseNoId;
         this.courseNoId = courseNoId;
     }
     }
 
 
-    public String getPosition() {
+    public Integer getPosition() {
         return position;
         return position;
     }
     }
 
 
-    public void setPosition(String position) {
+    public void setPosition(Integer position) {
         this.position = position;
         this.position = position;
     }
     }
 
 

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserCourseNoIdsDto.java

@@ -0,0 +1,13 @@
+package com.qxgmat.dto.request;
+
+public class UserCourseNoIdsDto {
+    private Integer[] courseNoIds;
+
+    public Integer[] getCourseNoIds() {
+        return courseNoIds;
+    }
+
+    public void setCourseNoIds(Integer[] courseNoIds) {
+        this.courseNoIds = courseNoIds;
+    }
+}

+ 0 - 10
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserExportDto.java

@@ -7,8 +7,6 @@ import com.qxgmat.data.dao.entity.UserExport;
 public class UserExportDto {
 public class UserExportDto {
     private Object setting;
     private Object setting;
 
 
-    private String type;
-
     public Object getSetting() {
     public Object getSetting() {
         return setting;
         return setting;
     }
     }
@@ -16,12 +14,4 @@ public class UserExportDto {
     public void setSetting(Object setting) {
     public void setSetting(Object setting) {
         this.setting = setting;
         this.setting = setting;
     }
     }
-
-    public String getType() {
-        return type;
-    }
-
-    public void setType(String type) {
-        this.type = type;
-    }
 }
 }

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/dto/request/UserQuestionIdsDto.java

@@ -1,6 +1,6 @@
 package com.qxgmat.dto.request;
 package com.qxgmat.dto.request;
 
 
-public class UserQuestionIdsDto {
+public class UserQuestionNoIdsDto {
     private Integer[] questionNoIds;
     private Integer[] questionNoIds;
 
 
     public Integer[] getQuestionNoIds() {
     public Integer[] getQuestionNoIds() {

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

@@ -5,6 +5,8 @@ import com.nuliji.tools.AbstractService;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.ParameterException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.exception.SystemException;
 import com.nuliji.tools.mybatis.Example;
 import com.nuliji.tools.mybatis.Example;
+import com.qxgmat.data.constants.enums.status.AskStatus;
+import com.qxgmat.data.constants.enums.status.DirectionStatus;
 import com.qxgmat.data.dao.UserNoteCourseMapper;
 import com.qxgmat.data.dao.UserNoteCourseMapper;
 import com.qxgmat.data.dao.entity.UserNoteCourse;
 import com.qxgmat.data.dao.entity.UserNoteCourse;
 import org.slf4j.Logger;
 import org.slf4j.Logger;
@@ -22,6 +24,30 @@ public class UserNoteCourseService extends AbstractService {
     @Resource
     @Resource
     private UserNoteCourseMapper userNoteCourseMapper;
     private UserNoteCourseMapper userNoteCourseMapper;
 
 
+    public Page<UserNoteCourse> listByCourse(int page, int size, String keyword, Integer userId, Integer courseId, String order, DirectionStatus direction){
+        Example example = new Example(UserNoteCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("courseId", courseId)
+        );
+        if (keyword != null)
+            example.and(
+                    example.createCriteria()
+                            .orLike("content", "%"+keyword+"%")
+            );
+        if(order == null || order.isEmpty()) order = "id";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(userNoteCourseMapper, example, page, size);
+    }
+
     public List<UserNoteCourse> listByCourse(Number courseId){
     public List<UserNoteCourse> listByCourse(Number courseId){
         Example example = new Example(UserNoteCourse.class);
         Example example = new Example(UserNoteCourse.class);
         example.and(
         example.and(
@@ -85,6 +111,27 @@ public class UserNoteCourseService extends AbstractService {
         return relationMap;
         return relationMap;
     }
     }
 
 
+    /**
+     * 删除笔记
+     * @param userId
+     * @param courseNoId
+     * @return
+     */
+    @Transactional
+    public boolean deleteNote(Integer userId, Integer courseNoId){
+        Example example = new Example(UserNoteCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("courseNoId", courseNoId)
+        );
+        UserNoteCourse in = one(userNoteCourseMapper, example);
+        if (in == null){
+            return true;
+        }
+        return delete(in.getId());
+    }
+
     public UserNoteCourse add(UserNoteCourse message){
     public UserNoteCourse add(UserNoteCourse message){
         int result = insert(userNoteCourseMapper, message);
         int result = insert(userNoteCourseMapper, message);
         message = one(userNoteCourseMapper, message.getId());
         message = one(userNoteCourseMapper, message.getId());

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

@@ -187,7 +187,7 @@ public class UserNoteQuestionService extends AbstractService {
     }
     }
 
 
     /**
     /**
-     * 取消收藏题目编号
+     * 删除笔记
      * @param userId
      * @param userId
      * @param questionId
      * @param questionId
      * @return
      * @return

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

@@ -147,30 +147,30 @@ public class UsersService extends AbstractService {
                 throw new ParameterException("该微信账户已绑定其他手机号,您可直接使用微信登录");
                 throw new ParameterException("该微信账户已绑定其他手机号,您可直接使用微信登录");
             }
             }
         }
         }
-        openUser = User.builder()
+        User mm = User.builder()
-                .id(openUser != null ? openUser.getId() : user != null ? user.getId() : null)
+                .id(openUser != null ? openUser.getId() : null)
                 .build();
                 .build();
-        if (user ==null || user.getAvatar() == null || user.getAvatar().isEmpty()) openUser.setAvatar(data.getAvatar());
+        if (openUser ==null || openUser.getAvatar() == null || openUser.getAvatar().isEmpty()) mm.setAvatar(data.getAvatar());
-        if (user == null || user.getNickname() == null|| user.getNickname().isEmpty() )openUser.setNickname(data.getNickName());
+        if (openUser == null || openUser.getNickname() == null|| openUser.getNickname().isEmpty() )mm.setNickname(data.getNickName());
         switch(platform){
         switch(platform){
             case "wechat_pc":
             case "wechat_pc":
-                openUser.setWechatOpenidPc(data.getOpenId());
+                mm.setWechatOpenidPc(data.getOpenId());
-                openUser.setWechatUnionid(data.getUnionId());
+                mm.setWechatUnionid(data.getUnionId());
                 break;
                 break;
             case "wechat_native":
             case "wechat_native":
-                openUser.setWechatOpenidWechat(data.getOpenId());
+                mm.setWechatOpenidWechat(data.getOpenId());
-                openUser.setWechatUnionid(data.getUnionId());
+                mm.setWechatUnionid(data.getUnionId());
-                openUser.setWechatAccessToken(data.getAccessToken());
+                mm.setWechatAccessToken(data.getAccessToken());
-                openUser.setWechatRefreshToken(data.getRefreshToken());
+                mm.setWechatRefreshToken(data.getRefreshToken());
-                openUser.setWechatExpireTime(data.getExpiresTime());
+                mm.setWechatExpireTime(data.getExpiresTime());
                 break;
                 break;
         }
         }
-        if (openUser.getId() != null){
+        if (mm.getId() != null){
             // 直接更新数据
             // 直接更新数据
-            edit(openUser);
+            edit(mm);
         }
         }
 
 
-        return openUser;
+        return mm;
     }
     }
 
 
     /**
     /**

+ 37 - 303
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExportService.java

@@ -1,325 +1,59 @@
 package com.qxgmat.service.extend;
 package com.qxgmat.service.extend;
 
 
-import com.nuliji.tools.Tools;
+import com.alibaba.fastjson.JSONObject;
-import com.nuliji.tools.Transform;
+import com.qxgmat.data.constants.enums.user.ExportType;
-import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.dao.entity.UserExport;
-import com.qxgmat.data.constants.enums.QuestionSubject;
+import com.qxgmat.service.UserNoteCourseService;
-import com.qxgmat.data.constants.enums.QuestionType;
+import com.qxgmat.service.UserNoteQuestionService;
-import com.qxgmat.data.constants.enums.module.VideoCourseType;
-import com.qxgmat.data.dao.entity.*;
-import com.qxgmat.data.relation.entity.UserRecordStatRelation;
 import com.qxgmat.service.inline.*;
 import com.qxgmat.service.inline.*;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.stereotype.Service;
 import org.springframework.stereotype.Service;
 
 
 import javax.annotation.Resource;
 import javax.annotation.Resource;
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
 
 
 @Service
 @Service
 public class ExportService {
 public class ExportService {
 
 
     @Autowired
     @Autowired
-    private CourseService courseService;
+    private UserNoteQuestionService userNoteQuestionService;
 
 
     @Autowired
     @Autowired
-    private UserCourseService userCourseService;
+    private UserNoteCourseService userNoteCourseService;
 
 
     @Autowired
     @Autowired
-    private UserOrderRecordService userOrderRecordService;
+    private QuestionService questionService;
 
 
     @Autowired
     @Autowired
-    private UserCourseRecordService userCourseRecordService;
+    private QuestionNoService questionNoService;
 
 
     @Resource
     @Resource
-    private UserCourseProgressService userCourseProgressService;
+    private UserExportService userExportService;
-
+
-    /**
+    public UserExport addQuestion(Integer userId, JSONObject setting){
-     * 计算vs课程有效期
+        UserExport export = UserExport.builder()
-     * @param vsNumber
+                .userId(userId)
-     */
+                .type(ExportType.QUESTION.key)
-    public int computeExpire(Integer vsNumber, Course course){
+                .setting(setting)
-        // day / 10
+                .build();
-        Integer expireDays = course.getExpirePreDays();
+        return userExportService.add(export);
-
+    }
-        return Math.max(vsNumber / 10, 1) * expireDays;
+
-    }
+    public UserExport addQuestionNote(Integer userId, JSONObject setting){
-
+        UserExport export = UserExport.builder()
-    /**
+                .userId(userId)
-     * 获取video课程有效期
+                .type(ExportType.NOTE_QUESTION.key)
-     * @param course
+                .setting(setting)
-     * @return
+                .build();
-     */
+        return userExportService.add(export);
-    public int computeExpire(Course course){
+    }
-        return course.getUseExpireDays();
+
-    }
+    public UserExport addCourseNote(Integer userId, JSONObject setting){
-
+        UserExport export = UserExport.builder()
-    public void suspendCourse(Integer userId, Integer recordId){
+                .userId(userId)
-        UserOrderRecord record = userOrderRecordService.get(recordId);
+                .type(ExportType.NOTE_COURSE.key)
-        if (record == null){
+                .setting(setting)
-            throw new ParameterException("记录不存在");
+                .build();
-        }
+
-        if (!record.getUserId().equals(userId)){
+        return userExportService.add(export);
-            throw new ParameterException("记录不存在");
-        }
-        if (record.getIsUsed() == 0){
-            throw new ParameterException("课程还未开通");
-        }
-        if (record.getIsSuspend() > 0){
-            throw new ParameterException("已停课1次");
-        }
-        userOrderRecordService.edit(UserOrderRecord.builder()
-                .id(record.getId())
-                .isSuspend(1)
-                .suspendTime(new Date())
-                .build());
-    }
-
-    public void restoreCourse(Integer userId, Integer recordId){
-        UserOrderRecord record = userOrderRecordService.get(recordId);
-        if (record == null){
-            throw new ParameterException("记录不存在");
-        }
-        if (!record.getUserId().equals(userId)){
-            throw new ParameterException("记录不存在");
-        }
-        if (record.getIsUsed() == 0){
-            throw new ParameterException("课程还未开通");
-        }
-        if (record.getIsSuspend() == 0){
-            throw new ParameterException("无需恢复");
-        }
-        if (record.getRestoreTime() != null){
-            throw new ParameterException("已恢复");
-        }
-
-        userOrderRecordService.edit(UserOrderRecord.builder()
-                .id(record.getId())
-                .restoreTime(new Date())
-                .useEndTime(Tools.addDate(record.getUseEndTime(), (int)((new Date().getTime() - record.getSuspendTime().getTime()) / 86400000)))
-                .build());
-    }
-
-    public void awardCourse(Integer userId, Integer recordId, Integer day){
-        UserOrderRecord record = userOrderRecordService.get(recordId);
-        if (record == null){
-            throw new ParameterException("记录不存在");
-        }
-        if (!record.getUserId().equals(userId)){
-            throw new ParameterException("记录不存在");
-        }
-        if (record.getIsUsed() == 0){
-            throw new ParameterException("课程还未开通");
-        }
-        if (record.getCourseAward() > 0){
-            throw new ParameterException("已奖励");
-        }
-
-        userOrderRecordService.edit(UserOrderRecord.builder()
-                .id(record.getId())
-                .courseAward(day)
-                .useEndTime(Tools.addDate(record.getUseEndTime(), day))
-                .build());
-    }
-
-    /**
-     * 累计听课学习时间
-     * @param userId
-     * @return
-     */
-    public Integer studyTime(Integer userId, Date startTime, Date endTime){
-        UserRecordStatRelation record = userCourseRecordService.stat(userId, startTime != null? startTime.toString():null, endTime != null ? endTime.toString(): null);
-        return record != null ? record.getUserTime() : 0;
-    }
-
-    /**
-     * 全站平均听课时间
-     * @return
-     */
-    public Integer studyAvgTime(Date startTime, Date endTime){
-        UserRecordStatRelation record = userCourseRecordService.statAvg(startTime != null? startTime.toString():null, endTime != null ? endTime.toString(): null);
-        return record != null ? record.getUserTime() : 0;
-    }
-
-    public UserCourse userCourse(Integer userId, Integer courseId){
-        return userCourseService.getCourse(userId, courseId);
-    }
-
-    /**
-     * 根据题目类型获取课程信息
-     * @param questionType
-     * @return
-     */
-    public Integer questionRelationCourse(Integer userId, QuestionType questionType){
-        QuestionSubject subject = QuestionSubject.FromType(questionType);
-        // 只查询系统授课记录
-        List<Course> courseList = courseService.listByExtend(questionType.key, subject.key, VideoCourseType.SYSTEM.key);
-        if (courseList.size()==0)return null;
-        Collection ids = Transform.getIds(courseList, Course.class, "id");
-        List<UserCourse> userCourseList = userCourseService.listByCourse(userId, ids);
-        if (userCourseList.size() == 0) return null;
-        if (userCourseList.size() == 1) return userCourseList.get(0).getRecordId();
-        // 获取回答时间最小的记录
-        Collection recordIds = Transform.getIds(userCourseList, UserCourse.class, "recordId");
-        List<UserOrderRecord> userOrderRecordList =  userOrderRecordService.select(recordIds);
-        int min = 0;
-        Integer minId = null;
-        for(UserOrderRecord userOrderRecord : userOrderRecordList){
-            if (minId == null || min > userOrderRecord.getAskTime()){
-                min = userOrderRecord.getAskTime();
-                minId = userOrderRecord.getId();
-            }
-        }
-        return minId;
-    }
-
-    /**
-     * 获取已完成课时序号
-     * @param courseNoList
-     * @param progressList
-     * @return
-     */
-    public int computeCourseNoFinish(Collection<CourseNo> courseNoList, Collection<UserCourseProgress> progressList){
-        Map progressMap = Transform.getMap(progressList, UserCourseProgress.class, "courseNoId");
-
-        int min = 0;
-        for(CourseNo no : courseNoList){
-            UserCourseProgress progress = (UserCourseProgress)progressMap.get(no.getId());
-            if(progress == null) continue;
-            if (min != 0 && min > no.getNo()) continue;
-            if (progress.getProgress() > 50) {
-                min = no.getNo();
-            }
-        }
-        return min;
-    }
-
-    /**
-     * 获取当前课时
-     * @param courseNoList
-     * @param progressList
-     * @return
-     */
-    public int computeCourseNoCurrent(Collection<CourseNo> courseNoList, Collection<UserCourseProgress> progressList){
-        Map progressMap = Transform.getMap(progressList, UserCourseProgress.class, "courseNoId");
-
-        int min = 0;
-        for(CourseNo no : courseNoList){
-            // 如果进度不过半,按当前课时+下一课时
-            // 如果进度过半,下2次课时
-            UserCourseProgress progress = (UserCourseProgress)progressMap.get(no.getId());
-            if(progress == null) continue;
-            if (min != 0 && min > no.getNo()) continue;
-            min = no.getNo();
-        }
-        return min;
-    }
-
-
-    /**
-     * 计算用户该课程的总学习时长
-     * @param userCourseRecords
-     * @return
-     */
-    public int computeCourseTime(Collection<UserCourseRecord> userCourseRecords){
-        int time = 0;
-        for(UserCourseRecord userCourseRecord:userCourseRecords){
-            time += userCourseRecord.getUserTime();
-        }
-        return time;
-    }
-
-    /**
-     * 计算用户该课程的总学习天数
-     * @param  record
-     * @return
-     */
-    public int computeCourseDay(UserOrderRecord record){
-        if(record.getUseEndTime() == null){
-            return 0;
-        }
-        int suspend = 0;
-        if(record.getIsSuspend() > 0){
-            if(record.getRestoreTime() == null){
-                suspend = (int)(Tools.day(new Date()).getTime() - Tools.day(record.getSuspendTime()).getTime())/86400000;
-            }else{
-                suspend = (int)(Tools.day(record.getRestoreTime()).getTime() - Tools.day(record.getSuspendTime()).getTime())/86400000;
-            }
-        }
-        if (record.getUseEndTime().before(new Date())){
-            return (int)(Tools.day(record.getUseEndTime()).getTime() - Tools.day(record.getUseStartTime()).getTime())/86400000 - suspend;
-        }else{
-            return (int)(Tools.day(new Date()).getTime() - Tools.day(record.getUseStartTime()).getTime())/86400000 - suspend;
-        }
-//        Date min = null;
-//        Date max = null;
-//        for(UserCourseRecord userCourseRecord:userCourseRecords){
-//            if(min==null || min.after(userCourseRecord.getCreateTime())){
-//                min = userCourseRecord.getCreateTime();
-//            }
-//            if (max == null || max.before(userCourseRecord.getCreateTime())){
-//                max = userCourseRecord.getCreateTime();
-//            }
-//        }
-//        int suspend = 0;
-//        if (min == null) return 0;
-//        return (int)((Tools.day(max).getTime() - Tools.day(min).getTime())/86400000) - suspend;
-    }
-
-    /**
-     * 根据用户权限更新资源信息
-     * @param user
-     * @param courseId
-     * @param courseNoList
-     */
-    public void refreshNoResource(User user, Integer courseId, List<CourseNo> courseNoList){
-        if (user != null){
-            if (userCourseService.getCourse(user.getId(), courseId) == null){
-                for(CourseNo courseNo : courseNoList){
-                    courseNo.setResource(courseNo.getTrailResource());
-                }
-            }
-        }else{
-            for(CourseNo courseNo : courseNoList){
-                courseNo.setResource(courseNo.getTrailResource());
-            }
-        }
-    }
-
-    /**
-     * 根据用户权限更新资源信息
-     * @param user
-     * @param courseData
-     */
-    public void refreshDataResource(User user, CourseData courseData){
-        // 处理权限
-        if (user != null){
-            if (!userOrderRecordService.hasData(user.getId(), courseData.getId())){
-                courseData.setResource(courseData.getTrailResource());
-            }
-        }else{
-            courseData.setResource(courseData.getTrailResource());
-        }
-    }
-    /**
-     * 根据用户权限更新资源信息
-     * @param user
-     * @param courseDataList
-     */
-    public void refreshDataResource(User user, List<CourseData> courseDataList){
-        // 处理权限
-        if (user != null){
-            for(CourseData courseData : courseDataList){
-                if (!userOrderRecordService.hasData(user.getId(), courseData.getId())){
-                    courseData.setResource(courseData.getTrailResource());
-                }
-            }
-        }else{
-            for(CourseData courseData : courseDataList){
-                courseData.setResource(courseData.getTrailResource());
-            }
-        }
     }
     }
 }
 }

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

@@ -317,10 +317,21 @@ public class MessageExtendService {
     }
     }
 
 
     /**
     /**
+     * 邮箱绑定
+     * @param user
+     */
+    public void sendEmailBind(User user){
+        Map<String, String> map = new HashMap<>();
+        map.put("nickname", user.getNickname());
+        map.put("email", user.getEmail());
+        send(user, MessageCategory.EMAIL_CHANGE, map);
+    }
+
+    /**
      * 邮箱变更
      * 邮箱变更
      * @param user
      * @param user
      */
      */
-    public void sendEmailChange(User user){
+    public void sendEmailChange(User user, String email){
         Map<String, String> map = new HashMap<>();
         Map<String, String> map = new HashMap<>();
         map.put("nickname", user.getNickname());
         map.put("nickname", user.getNickname());
         map.put("email", user.getEmail());
         map.put("email", user.getEmail());

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

@@ -61,7 +61,7 @@ public class UserAskCourseService extends AbstractService {
         return p;
         return p;
     }
     }
 
 
-    public List<UserAskCourse> listByCoursePosition(Number courseNoId, String position, Boolean showStatus){
+    public List<UserAskCourse> listByCoursePosition(Number courseNoId, Integer position, Boolean showStatus){
         Example example = new Example(UserAskCourse.class);
         Example example = new Example(UserAskCourse.class);
         example.and(
         example.and(
                 example.createCriteria()
                 example.createCriteria()
@@ -80,6 +80,83 @@ public class UserAskCourseService extends AbstractService {
         return select(userAskCourseMapper, example);
         return select(userAskCourseMapper, example);
     }
     }
 
 
+    public Page<UserAskCourse> listByCourse(int page, int size, String keyword, Integer courseId, Integer courseNoId, Integer position, Boolean showStatus, String order, DirectionStatus direction){
+        Example example = new Example(UserAskCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("courseId", courseId)
+        );
+        if(courseNoId != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("courseNoId", courseNoId)
+            );
+        if(position != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("position", position)
+            );
+        if (keyword != null)
+            example.and(
+                    example.createCriteria()
+                            .orLike("content", "%"+keyword+"%")
+                            .orLike("answer", "%"+keyword+"%")
+            );
+
+        if (showStatus != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("showStatus", showStatus?1:0)
+                            .andEqualTo("answerStatus", 1)
+
+            );
+        if(order == null || order.isEmpty()) order = "sort";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(userAskCourseMapper, example, page, size);
+    }
+
+    public Page<UserAskCourse> listByUser(int page, int size, String keyword, Integer userId, Integer courseId, Integer courseNoId, AskStatus askStatus, String order, DirectionStatus direction){
+        Example example = new Example(UserAskCourse.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andEqualTo("courseId", courseId)
+        );
+        if(courseNoId != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("courseNoId", courseNoId)
+            );
+        if (askStatus != null)
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("answerStatus", askStatus.index)
+            );
+        if (keyword != null)
+            example.and(
+                    example.createCriteria()
+                            .orLike("content", "%"+keyword+"%")
+                            .orLike("answer", "%"+keyword+"%")
+            );
+        if(order == null || order.isEmpty()) order = "id";
+        switch(direction){
+            case ASC:
+                example.orderBy(order).asc();
+                break;
+            case DESC:
+            default:
+                example.orderBy(order).desc();
+        }
+        return select(userAskCourseMapper, example, page, size);
+    }
+
     public List<UserAskCourse> listByRecord(Number recordId){
     public List<UserAskCourse> listByRecord(Number recordId){
         Example example = new Example(UserAskCourse.class);
         Example example = new Example(UserAskCourse.class);
         example.and(
         example.and(