Explorar o código

fix(front): 修复样式

Go %!s(int64=5) %!d(string=hai) anos
pai
achega
e9ed2f1923

+ 3 - 0
front/project/admin/routes/show/comment/page.js

@@ -228,6 +228,9 @@ export default class extends Page {
     const info = Object.assign({}, row);
     info.channel = info.channel.split('-');
     asyncForm('编辑', item, info, data => {
+      data.isShow = 1;
+      data.isSystem = 1;
+      data.isSpecial = 1;
       data.channel = data.channel.join('-');
       return System.editComment(data).then(() => {
         asyncSMessage('编辑成功!');

+ 3 - 0
front/project/admin/routes/show/faq/page.js

@@ -210,6 +210,9 @@ export default class extends Page {
     const info = Object.assign({}, row);
     info.channel = info.channel.split('-');
     asyncForm('编辑', this.itemList, info, data => {
+      data.isShow = 1;
+      data.isSystem = 1;
+      data.isSpecial = 1;
       data.channel = data.channel.join('-');
       return System.editFAQ(data).then(() => {
         asyncSMessage('编辑成功!');

+ 6 - 0
front/project/www/app.js

@@ -4,6 +4,12 @@ import zhCN from 'antd/lib/locale-provider/zh_CN';
 import './app.less';
 import Header from './components/Header';
 import Login from './components/Login';
+import './components/OtherModal';
+import './components/Other';
+import './components/VipRenew';
+import './components/UserAction';
+import './components/UserTable';
+import './components/UserPagination';
 import { PayModal } from './components/PayModal';
 
 export default class extends Component {

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

@@ -27,7 +27,7 @@ export class CommentFalls extends Component {
                 <div className="item-header">
                   <Assets src={row.user ? row.user.avatar : row.avatar} />
                   <div className="name">{row.user ? row.user.nickname : row.nickname}</div>
-                  <div className="date">{formatDate(row.createTime, 'yyyy年mm月dd日')}</div>
+                  <div className="date">{formatDate(row.createTime, 'YYYY年MM月DD日')}</div>
                 </div>
                 <div className="item-body">{row.content}</div>
               </div>

+ 31 - 19
front/project/www/components/OtherModal/index.js

@@ -692,7 +692,7 @@ export class FeedbackErrorDataModal extends Component {
   }
 
   componentWillReceiveProps(nextProps) {
-    if (nextProps.defaultData) {
+    if (nextProps.show && nextProps.defaultData) {
       this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
     }
   }
@@ -703,16 +703,16 @@ export class FeedbackErrorDataModal extends Component {
     if (!data.content || !data.originContent) return;
     My.addFeedbackErrorData(data.dataId, data.title, data.position.join(','), data.originContent, data.content).then(
       () => {
-        if (onConfirm) onConfirm();
         this.setState({ data: { position: ['', '', ''] } });
+        if (onConfirm) onConfirm();
       },
     );
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: { position: [] } });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -794,7 +794,7 @@ export class AskCourseModal extends Component {
   }
 
   componentWillReceiveProps(nextProps) {
-    if (nextProps.defaultData) {
+    if (nextProps.show && nextProps.defaultData) {
       this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
     }
   }
@@ -804,15 +804,15 @@ export class AskCourseModal extends Component {
     const { data } = this.state;
     if (!data.position || !data.originContent || !data.content) return;
     My.addCourseAsk(course.id, courseNo.id, data.position.join(','), data.originContent, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: { position: [] } });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -877,7 +877,7 @@ export class CourseNoteModal extends Component {
   }
 
   componentWillReceiveProps(nextProps) {
-    if (nextProps.defaultData) {
+    if (nextProps.show && nextProps.defaultData) {
       this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
     }
   }
@@ -887,15 +887,15 @@ export class CourseNoteModal extends Component {
     const { data } = this.state;
     if (!data.content) return;
     My.updateCourseNote(course.id, data.courseNoId, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: {} });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -968,7 +968,7 @@ export class TextbookFeedbackModal extends Component {
   }
 
   componentWillReceiveProps(nextProps) {
-    if (nextProps.defaultData) {
+    if (nextProps.show && nextProps.defaultData) {
       this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
     }
   }
@@ -979,15 +979,15 @@ export class TextbookFeedbackModal extends Component {
     if (!data.content) return;
     if (data.target !== 'new' && !data.no) return;
     My.addTextbookFeedback(data.textbookSubject, data.target, data.no, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: {} });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -1053,20 +1053,26 @@ export class FaqModal extends Component {
     this.state = { data: {} };
   }
 
+  componentWillReceiveProps(nextProps) {
+    if (nextProps.defaultData && nextProps.show) {
+      this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
+    }
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
     if (!data.content) return;
     My.addFaq(data.channel, data.position, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: {} });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -1096,20 +1102,26 @@ export class CommentModal extends Component {
     this.state = { data: {} };
   }
 
+  componentWillReceiveProps(nextProps) {
+    if (nextProps.show && nextProps.defaultData) {
+      this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
+    }
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
     if (!data.content) return;
     My.addComment(data.channel, data.position, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: {} });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {
@@ -1154,7 +1166,7 @@ export class SuppleModal extends Component {
   }
 
   componentWillReceiveProps(nextProps) {
-    if (nextProps.defaultData) {
+    if (nextProps.show && nextProps.defaultData) {
       this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
     }
   }
@@ -1164,15 +1176,15 @@ export class SuppleModal extends Component {
     const { data } = this.state;
     if (!data.content) return;
     My.addRoomFeedback(data.roomId, data.content).then(() => {
-      if (onConfirm) onConfirm();
       this.setState({ data: {} });
+      if (onConfirm) onConfirm();
     });
   }
 
   onCancel() {
     const { onCancel } = this.props;
-    if (onCancel) onCancel();
     this.setState({ data: {} });
+    if (onCancel) onCancel();
   }
 
   render() {

+ 2 - 2
front/project/www/routes/course/data/page.js

@@ -295,8 +295,8 @@ export default class extends Page {
       <FeedbackErrorDataModal
         show={showFeedbackError}
         defaultData={feedbackError}
-        onConfirm={() => this.setState({ showFeedbackError: false })}
-        onCancel={() => this.setState({ showFeedbackError: false })}
+        onConfirm={() => this.setState({ showFeedbackError: false, feedbackError: {} })}
+        onCancel={() => this.setState({ showFeedbackError: false, feedbackError: {} })}
       />,
     ];
   }

+ 4 - 4
front/project/www/routes/course/dataDetail/page.js

@@ -94,11 +94,11 @@ export default class extends Page {
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, comment: {} })}
+          onClose={() => this.setState({ showComment: false, comment: {} })}
         />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           show={showFinish}
           onConfirm={() => this.setState({ showFinish: false })}

+ 6 - 6
front/project/www/routes/course/detail/page.js

@@ -463,19 +463,19 @@ export default class extends Page {
         </div>
         <Contact data={base.contact} />
         <Footer />
-        <AskCourseModal getContainer={() => document.getElementById(this.video.state.id)} show={showAsk} defaultData={ask} course={data} courseNo={item} selectList={timelineSelect} onConfirm={() => this.setState({ showAsk: false })} onCancel={() => this.setState({ showAsk: false })} />
-        <CourseNoteModal getContainer={() => document.getElementById(this.video.state.id)} show={showNote} defaultData={note} course={data} courseNos={courseNos} noteMap={this.noteMap} onConfirm={() => {
+        <AskCourseModal getContainer={() => (showTab ? document.getElementById(this.video.state.id) : document.body)} show={showAsk} defaultData={ask} course={data} courseNo={item} selectList={timelineSelect} onConfirm={() => this.setState({ showAsk: false })} onCancel={() => this.setState({ showAsk: false })} />
+        <CourseNoteModal getContainer={() => (showTab ? document.getElementById(this.video.state.id) : document.body)} show={showNote} defaultData={note} course={data} courseNos={courseNos} noteMap={this.noteMap} onConfirm={() => {
           this.setState({ showNote: false });
           this.refreshNote();
         }} onCancel={() => this.setState({ showNote: false })} />
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, commnet: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, commnet: {} })}
+          onClose={() => this.setState({ showComment: false, commnet: {} })}
         />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           getContainer={() => document.getElementById(this.video.state.id)}
           show={showFinish}

+ 1 - 1
front/project/www/routes/course/experience/page.js

@@ -235,7 +235,7 @@ class Article extends Component {
           <div className="f-r t-3 t-s-12 f-w-d">
             <span>{data.updateTime && formatDate(data.updateTime, 'YYYY-MM-DD HH:mm:ss')}</span>
             <span className="m-l-2">阅读 {data.viewNumber}</span>
-            <span className="m-l-2 link" onClick={(e) => {
+            <span className="m-l-2 c-p" onClick={(e) => {
               e.stopPropagation();
               this.onCollect();
             }}>

+ 1 - 1
front/project/www/routes/course/experienceDetail/page.js

@@ -63,7 +63,7 @@ export default class extends Page {
             <div className="t-6 m-b-2">
               <span className="m-r-2">{data.updateTime && formatDate(data.updateTime, 'YYYY-MM-DD HH:mm:ss')}</span>
               <span className="m-r-2 m-l-1">阅读 {data.viewNumber || 0}</span>
-              <span className="m-l-1" onClick={() => this.onCollect()}>
+              <span className="m-l-1 c-p" onClick={() => this.onCollect()}>
                 {!collectStatus ? '收藏' : '取消收藏'}
               </span>
             </div>

+ 2 - 2
front/project/www/routes/course/main/page.js

@@ -36,7 +36,7 @@ export default class extends Page {
       this.setState({ faqs: result.list });
     });
     Main.listComment({ page: 1, size: 100, channel: 'course-index' }).then(result => {
-      this.setState({ coments: result.list });
+      this.setState({ comments: result.list });
     });
   }
 
@@ -145,7 +145,7 @@ export default class extends Page {
         <AnswerCarousel list={faqs} onFaq={() => this.setState({ showFaq: true, faq: { channel: 'course-index' } })} />
         <Contact data={base.contact} />
         <Footer />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           show={showFinish}
           onConfirm={() => this.setState({ showFinish: false })}

+ 3 - 3
front/project/www/routes/course/online/page.js

@@ -84,7 +84,7 @@ export default class extends Page {
       this.setState({ faqs: result.list });
     });
     Main.listComment({ page: 1, size: 100, channel: 'course-video_index' }).then(result => {
-      this.setState({ coments: result.list });
+      this.setState({ comments: result.list });
     });
     Course.listVideo(Object.assign({ structId: this.state.search.parentStructId }, this.state.search))
       .then(result => {
@@ -97,7 +97,7 @@ export default class extends Page {
       this.setState({ faqs: result.list });
     });
     Main.listComment({ page: 1, size: 100, channel: 'course-package_index' }).then(result => {
-      this.setState({ coments: result.list });
+      this.setState({ comments: result.list });
     });
     Course.listPackage(Object.assign({}, this.state.search))
       .then(result => {
@@ -156,7 +156,7 @@ export default class extends Page {
         <AnswerCarousel list={faqs} onFaq={() => this.setState({ showFaq: true, faq: { channel: tab === 'single' ? 'course-video_index' : 'course-package_index' } })} />
         <Contact data={base.contact} />
         <Footer />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           show={showFinish}
           onConfirm={() => this.setState({ showFinish: false })}

+ 4 - 4
front/project/www/routes/course/vs/page.js

@@ -137,11 +137,11 @@ export default class extends Page {
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, comment: {} })}
+          onClose={() => this.setState({ showComment: false, comment: {} })}
         />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           show={showFinish}
           onConfirm={() => this.setState({ showFinish: false })}

+ 3 - 3
front/project/www/routes/my/course/page.js

@@ -522,9 +522,9 @@ export default class extends Page {
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, comment: {} })}
+          onClose={() => this.setState({ showComment: false, comment: {} })}
         />
         <FinishModal
           show={showFinish}

+ 22 - 1
front/project/www/routes/my/note/page.js

@@ -1,5 +1,6 @@
 import React from 'react';
 import { Link } from 'react-router-dom';
+import { Icon } from 'antd';
 import './index.less';
 import Page from '@src/containers/Page';
 import { timeRange, getMap, formatDate } from '@src/services/Tools';
@@ -479,9 +480,29 @@ export default class extends Page {
   }
 
   renderModal() {
-    const { showWarn, warn = {}, showClearConfirm, clearInfo = {}, showVip, showExamination, showReal, showExportWait, showExportConfirm, exportInfo = {} } = this.state;
+    const { showTips, showWarn, warn = {}, showClearConfirm, clearInfo = {}, showVip, showExamination, showReal, showExportWait, showExportConfirm, exportInfo = {} } = this.state;
     const { info } = this.props.user;
     return [
+      <Modal show={showTips} title="操作提示" confirmText="好的,知道了" btnAlign="center" onConfirm={() => this.setState({ showTips: false })}>
+        <div className="flex-layout m-b-2">
+          <div className="flex-block">
+            <div className="t-1 t-s-18">组卷功能</div>
+            <div className="t-2">操作数量:10-50;</div>
+            <div className="t-2">注意事项:可跨题型、不可跨学科。</div>
+          </div>
+          <div className="flex-block">
+            <div className="t-1 t-s-18">导出功能</div>
+            <div className="t-2">操作数量:1-100;</div>
+            <div className="t-2">注意事项:“综合推理IR”暂时无法导出。</div>
+          </div>
+        </div>
+
+        <div className="t-3">
+          *您可点击
+          <Icon type="question-circle" theme="filled" />
+          查阅以上信息。
+        </div>
+      </Modal>,
       <Modal show={showWarn} title={warn.title} confirmText="好的,知道了" btnAlign="center" onConfirm={() => this.setState({ showWarn: false })}>
         <div className="t-2 t-s-18">{warn.content}</div>
       </Modal>,

+ 9 - 9
front/project/www/routes/my/tools/page.js

@@ -400,23 +400,23 @@ export default class extends Page {
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, comment: {} })}
+          onClose={() => this.setState({ showComment: false, comment: {} })}
         />
         <FeedbackErrorDataModal
           show={showFeedbackError}
           defaultData={feedbackError}
-          onConfirm={() => this.setState({ showFeedbackError: false, showFinish: true })}
-          onCancel={() => this.setState({ showFeedbackError: false })}
-          onClose={() => this.setState({ showFeedbackError: false })}
+          onConfirm={() => this.setState({ showFeedbackError: false, feedbackError: {}, showFinish: true })}
+          onCancel={() => this.setState({ showFeedbackError: false, feedbackError: {} })}
+          onClose={() => this.setState({ showFeedbackError: false, feedbackError: {} })}
         />
         <TextbookFeedbackModal
           show={showFeedback}
           defaultData={feedback}
-          onConfirm={() => this.setState({ showFeedback: false, showFinish: true })}
-          onCancel={() => this.setState({ showFeedback: false })}
-          onClose={() => this.setState({ showFeedback: false })}
+          onConfirm={() => this.setState({ showFeedback: false, feedback: {}, showFinish: true })}
+          onCancel={() => this.setState({ showFeedback: false, feedback: {} })}
+          onClose={() => this.setState({ showFeedback: false, feedback: {} })}
         />
         <FinishModal
           show={showFinish}

+ 1 - 1
front/project/www/routes/page/ready/page.js

@@ -359,7 +359,7 @@ export default class extends Page {
               <div className="t-1 t-s-18">{index + 1}.{item.title}</div>
               <div className="t-1">{item.address}</div>
               <div className="t-1">
-                温馨提示: {item.description} <span className="t-4" onClick={() => User.needLogin().then(() => this.setState({ showSupple: true, supple: { roomId: item.id }, room: item }))}>我要补充</span>
+                温馨提示: {item.description} <span className="t-4 c-p" onClick={() => User.needLogin().then(() => this.setState({ showSupple: true, supple: { roomId: item.id }, room: item }))}>我要补充</span>
               </div>
             </div>
           );

+ 7 - 7
front/project/www/routes/textbook/main/page.js

@@ -287,18 +287,18 @@ export default class extends Page {
         <TextbookFeedbackModal
           show={showFeedback}
           defaultData={feedback}
-          onConfirm={() => this.setState({ showFeedback: false, showFinish: true })}
-          onCancel={() => this.setState({ showFeedback: false })}
-          onClose={() => this.setState({ showFeedback: false })}
+          onConfirm={() => this.setState({ showFeedback: false, feedback: {}, showFinish: true })}
+          onCancel={() => this.setState({ showFeedback: false, feedback: {} })}
+          onClose={() => this.setState({ showFeedback: false, feedback: {} })}
         />
         <CommentModal
           show={showComment}
           defaultData={comment}
-          onConfirm={() => this.setState({ showComment: false, showFinish: true })}
-          onCancel={() => this.setState({ showComment: false })}
-          onClose={() => this.setState({ showComment: false })}
+          onConfirm={() => this.setState({ showComment: false, comment: {}, showFinish: true })}
+          onCancel={() => this.setState({ showComment: false, comment: {} })}
+          onClose={() => this.setState({ showComment: false, comment: {} })}
         />
-        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false })} onConfirm={() => this.setState({ showFaq: false, showFinish: true })} />
+        <FaqModal show={showFaq} defaultData={faq} onCancel={() => this.setState({ showFaq: false, faq: {} })} onConfirm={() => this.setState({ showFaq: false, faq: {}, showFinish: true })} />
         <FinishModal
           show={showFinish}
           onConfirm={() => this.setState({ showFinish: false })}

+ 72 - 19
server/data/src/main/resources/db/migration/V1__init_table.sql

@@ -386,25 +386,78 @@ CREATE TABLE message_template (
 
 INSERT INTO message_template (id, title, message_method, message_category, content, link, send_time, send_number, send_status, create_time)
 VALUES
-	(1,'登录异常','inside','login_abnormal','123','http://www.baidu.com/12312','2019-08-01 23:48:16',0,1,'2019-08-01 23:53:40'),
-	(2,'新增换库','inside','textbook_update',NULL,'',NULL,0,1,NULL),
-	(3,'预习作业提醒','inside','preview_notice',NULL,'',NULL,0,1,NULL),
-	(4,'购买成功提醒','inside','payed',NULL,'',NULL,0,1,NULL),
-	(5,'资料更新','inside','data_update',NULL,'',NULL,0,1,NULL),
-	(6,'提问回复','inside','ask_question',NULL,'',NULL,0,1,NULL),
-	(7,'提问回复','inside','ask_course',NULL,'',NULL,0,1,NULL),
-	(8,'咨询回复','inside','faq_callback',NULL,'',NULL,0,1,NULL),
-	(9,'纠错回复','inside','feedback_callback',NULL,'',NULL,0,1,NULL),
-	(10,'您的账户登录异常','email','login_abnormal',NULL,'',NULL,0,1,NULL),
-	(11,'欢迎下载机经','email','textbook_update',NULL,'',NULL,0,1,NULL),
-	(12,'感谢您注册千行GMAT','email','register',NULL,'',NULL,0,1,NULL),
-	(13,'请尽快完成作业','email','preview_notice',NULL,'',NULL,0,1,NULL),
-	(14,'感谢您购买千行GMAT产品','email','payed',NULL,'',NULL,0,1,NULL),
-	(15,'{nickname}向您发送了一个邀请','email','invited',NULL,'',NULL,0,1,NULL),
-	(16,'邮箱变更成功','email','email_change',NULL,'',NULL,0,1,NULL),
-	(17,'您订阅的资料有了更新','email','data_update',NULL,'',NULL,0,1,NULL),
-	(18,'提问回复','wechat','ask_question',NULL,'',NULL,0,1,NULL),
-	(19,'提问回复','wechat','ask_course',NULL,'',NULL,0,1,NULL);
+	(1, '登录异常', 'inside', 'login_abnormal', '您的账号于{time}发生异常登入,异常登入可能会影响您账号的正常使用,望知悉。', '', NULL, 0, 1, '2019-08-01 23:53:40'),
+	(2, '换库', 'inside', 'textbook_library', '最新换库时间是{date},上次换库时间是{prevDate},间隔{period}天,库长{days}天。', '', NULL, 0, 1, NULL),
+	(3, '预习作业提醒', 'inside', 'preview_notice', '您有{number}份“{title}”作业待完成', '', NULL, 0, 1, NULL),
+	(4, '机经反馈', 'inside', 'textbook_feedback_handle', '您于{time}反馈如下问题:\r\n机经类别:{subject}\r\n反馈类型:{target}\r\n题号:{no}\r\n{result}:{answer}\r\n处理结果:{handle}。\r\n感谢您的反馈,{useExpireDays}天VIP权限已送至您的账户。', '', NULL, 11, 1, NULL),
+	(5, '资料更新', 'inside', 'data_update_paper', '您购买的资料“{title}”已更新到版本{version}', '', NULL, 0, 1, NULL),
+	(6, '提问回复', 'inside', 'ask_question_handle', '您在{date}对“{title}”的提问“{content}”已经被老师回答啦~', '', NULL, 0, 1, NULL),
+	(7, '提问回复', 'inside', 'ask_course_handle', '您在{date}对“{title}-课时{no}”的提问“{content}”已经被老师回答啦~', '', NULL, 0, 1, NULL),
+	(8, '咨询回复', 'inside', 'faq_handle', '咨询板块:{channel}\r\n您的问题:{content}\r\n回答:{answer}\r\n希望对您有帮助。', '', NULL, 0, 1, NULL),
+	(9, '纠错回复', 'inside', 'feedback_error_handle', '您于{time}反馈如下问题:\r\n纠错对象:{title}-{position}\r\n错误内容是:{originContent}\r\n应该更改为:{content}\r\n处理结果:需要修改,已更正。\r\n感谢您的反馈,{useExpireDays}天VIP权限已送至您的账户。', '', NULL, 0, 1, NULL),
+	(10, '[千行GMAT]登入异常', 'email', 'login_abnormal', '同学您好,\r\n您的账号于{time}发生异常登入,异常登入可能会影响您账号的正常使用,望知悉。\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(11, '[千行GMAT]换库消息', 'email', 'textbook_library', '同学您好,\r\n最新换库时间是{date},上次换库时间是{prevDate},间隔{period}天,库长{days}天。\r\n查看本年度换库情况: {linkSecondHtml}\r\n获取机经:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(12, '[千行GMAT]注册成功', 'email', 'register', '同学您好,\r\n欢迎加入“千行GMAT”,您的账号已绑定该邮箱地址。\r\n愿您Waste Less, Learn More.\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(13, '[千行GMAT]作业提醒', 'email', 'preview_notice', '同学您好,\r\n您有{number}份“{title}”作业待完成,去做作业:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(14, '[千行GMAT]购买成功', 'email', 'data_pay', '同学您好,\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 8, 1, NULL),
+	(15, '[千行GMAT]{nickname}发来的邀请', 'email', 'invited', '您的好友{nickname}邀请您加入“千行GMAT”,{linkHtml}\r\n\r\n{content}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(16, '[千行GMAT]绑定邮箱', 'email', 'email_change', '同学您好,\r\n您的“千行GMAT”账号更换绑定邮箱成功。\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(17, '[千行GMAT]资料更新', 'email', 'data_update_paper', '同学您好,\r\n您订阅的“{title}”已更新至版本{version},\r\n更新日志:{description}\r\n您也可以:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(18, '登录异常', 'sms', 'login_abnormal', NULL, '', NULL, 0, 1, NULL),
+	(19, '新增换库', 'sms', 'textbook_library', NULL, '', NULL, 0, 1, NULL),
+	(20, '[千行GMAT]解绑邮箱', 'email', 'email_unbind', '同学您好,\r\n您的“千行GMAT”账号不再绑定本邮箱,您更换的新邮箱地址为:{email}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(21, '[千行GMAT]实名认证成功', 'email', 'real', '同学您好,\r\n您已完成实名认证,{useExpireDays}天VIP权限已赠送至您的账户,VIP有效期至{expireTime}.\r\n我们将重视和保护您的隐私,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(22, '[千行GMAT]购买成功', 'email', 'pay_multi', '同学您好,\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(23, '[千行GMAT]开通提醒', 'email', 'course_open_expire', '同学您好,\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(24, '[千行GMAT]开通提醒', 'email', 'textbook_open_expire', '同学您好,\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(25, '[千行GMAT]开通提醒', 'email', 'qx_cat_open_expire', '同学您好,\r\n请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(26, '[千行GMAT]到期提醒', 'email', 'course_use_expire', '同学您好,\r\n您的“{title}”将于{days}天后过期,{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(27, '[千行GMAT]到期提醒', 'email', 'textbook_use_expire', '同学您好,\r\n您的“{title}”将于{days}天后过期,{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(28, '[千行GMAT]到期提醒', 'email', 'qx_cat_use_expire', '同学您好,\r\n您的“{title}”将于{days}天后过期,{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(29, '[千行GMAT]机经更新至{version}', 'email', 'textbook_update', '同学您好,\r\n数学机经{quantDescription},更新至版本{quantVersion};\r\n逻辑机经{irDescription},更新至版本{irVersion};\r\n阅读机经{rcDescription},更新至版本{rcVersion}.\r\n您可以:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(30, '[千行GMAT]资料更新', 'email', 'data_update_subscribe', '同学您好,\r\n您订阅的“{title}”已更新至版本{version},\r\n更新日志:{description}\r\n附件为最新版资料,您也可以:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(31, '[千行GMAT]资料更新', 'email', 'data_update_base', '同学您好,\r\n您订阅的“{title}”已更新至版本{version},\r\n更新日志:{description}\r\n您也可以:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(32, '课程到期', 'sms', 'course_use_expire', NULL, '', NULL, 0, 1, NULL),
+	(33, '课程开通到期', 'sms', 'course_open_expire', NULL, '', NULL, 0, 1, NULL),
+	(34, '机经开通到期', 'sms', 'textbook_open_expire', NULL, '', NULL, 0, 1, NULL),
+	(35, '模考开通到期', 'sms', 'qx_cat_open_expire', NULL, '', NULL, 0, 1, NULL),
+	(36, '购买成功', 'inside', 'vip_pay', '您已成功购买“{title}({useExpireDays}天)”服务,有效期至{expireTime}', '', NULL, 0, 1, NULL),
+	(37, '[千行GMAT]购买成功', 'email', 'vip_pay', '同学您好,\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(38, '[千行GMAT]购买成功', 'email', 'textbook_pay', '同学您好,\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(39, '[千行GMAT]购买成功', 'email', 'qx_cat_pay', '同学您好,\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(40, '到期提醒', 'inside', 'course_use_expire', '您的“{title}”将于{days}天后过期。', '', NULL, 0, 1, NULL),
+	(41, '开通提醒', 'inside', 'course_open_expire', '请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。', '', NULL, 0, 1, NULL),
+	(42, '赠送', 'inside', 'invited_success', '您的第{number}位好友已加入”千行GMAT“,{useExpireDays}天VIP权限已赠送至您的账户,VIP有效期至{expireTime}', '', NULL, 0, 1, NULL),
+	(43, '赠送', 'inside', 'real', '您已完成实名认证,{useExpireDays}天VIP权限已赠送至您的账户,VIP有效期至{expireTime}', '', NULL, 0, 1, NULL),
+	(44, '赠送', 'inside', 'prepare', '您已完善备考信息,{useExpireDays}天VIP权限已赠送至您的账户,VIP有效期至{expireTime}', '', NULL, 0, 1, NULL),
+	(45, '到期提醒', 'inside', 'vip_use_expire', '您的“{title}”将于{days}天后过期', '', NULL, 0, 1, NULL),
+	(46, '购买成功', 'inside', 'qx_cat_pay', '您已成功购买\"{title}”服务,开通有效期为{expireDays}天,使用有效期为{useExpireDays}天。', '', NULL, 0, 1, NULL),
+	(47, '开通提醒', 'inside', 'qx_cat_open_expire', '请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。', '', NULL, 0, 1, NULL),
+	(48, '到期提醒', 'inside', 'qx_cat_use_expire', '您的“{title}”将于{days}天后过期。', '', NULL, 0, 1, NULL),
+	(49, '购买成功', 'inside', 'textbook_pay', '您已成功购买\"{title}”服务,开通有效期为{expireDays}天,使用有效期为{useExpireDays}天。', '', NULL, 0, 1, NULL),
+	(50, '开通提醒', 'inside', 'textbook_open_expire', '请于{expireDate}前开通“{title}”,过期后将无法正常开通使用。', '', NULL, 0, 1, NULL),
+	(51, '[千行GMAT]购买成功', 'email', 'course_pay', '同学您好,\r\n您已成功购买“{title}”服务,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(52, '[千行GMAT]购买成功', 'email', 'course_pay_multi', '同学您好,\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(53, '[千行GMAT]购买成功', 'email', 'data_pay_multi', '同学您好,\r\n您已成功购买“{titleJoin}”共{number}个商品,祝您在 千行 学习愉快~\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(54, '购买成功', 'inside', 'course_pay', '您已成功购买\"{title}”,开通有效期为{expireDays}天,使用有效期为{useExpireDays}天。', '', NULL, 0, 1, NULL),
+	(55, '购买成功', 'inside', 'course_pay_multi', '您已成功购买\"{title}”等{number}个商品,查看开通有效期和使用有效期', '', NULL, 0, 1, NULL),
+	(56, '购买成功', 'inside', 'pay_multi', '您已成功购买\"{title}”等{number}个商品,查看开通有效期和使用有效期', '', NULL, 0, 1, NULL),
+	(57, '购买成功', 'inside', 'data_pay', '您已成功购买\"{title}”', '', NULL, 0, 1, NULL),
+	(58, '购买成功', 'inside', 'data_pay_multi', '您已成功购买“{titleJoin}”', '', NULL, 0, 1, NULL),
+	(59, '机经更新', 'inside', 'textbook_update', '数学机经{quantDescription},更新至版本{quantVersion};\r\n逻辑机经{irDescription},更新至版本{irVersion};\r\n阅读机经{rcDescription},更新至版本{rcVersion}.', '', NULL, 0, 1, NULL),
+	(60, '资料更新', 'inside', 'data_update_base', '您购买的资料“{title}”已更新到版本{version}', '', NULL, 0, 1, NULL),
+	(61, '资料更新', 'inside', 'data_update_subscribe', '您购买的资料“{title}”已更新到版本{version},最新版本已发送至您的邮箱{email}', '', NULL, 0, 1, NULL),
+	(62, '纠错回复', 'inside', 'feedback_error_nohandle', '您于{time}反馈如下问题:\r\n纠错对象:{title}-{position}\r\n错误内容是:{originContent}\r\n应该更改为:{content}\r\n处理结果:无需修改。\r\n感谢您的反馈。', '', NULL, 0, 1, NULL),
+	(63, '机经反馈', 'inside', 'textbook_feedback_nohandle', '您于{time}反馈如下问题:\r\n机经类别:{subject}\r\n反馈类型:{target}\r\n题号:{no}\r\n{result}:{content}\r\n处理结果:无需修改。\r\n感谢您的反馈。', '', NULL, 0, 1, NULL),
+	(64, '提问回复', 'inside', 'ask_question_ignore', '您在{date}对“{title}”的提问“{content}”与本题无关,老师无法作出回答,敬请谅解。', '', NULL, 0, 1, NULL),
+	(65, '提问回复', 'inside', 'ask_course_ignore', '您在{date}对“{title}-课时{no}”的提问“{content}”与课程内容无关,老师无法作出回答,敬请谅解。', '', NULL, 0, 1, NULL),
+	(66, '赠送', 'inside', 'course_gift', '“{title}”已赠送至您的账户,开通有效期为{expireDays}天,使用有效期为{useExpireDays}天。', '', NULL, 0, 1, NULL),
+	(67, '[千行GMAT]机经更新至{version}', 'email', 'textbook_update_subscribe', '同学您好,\r\n数学机经{quantDescription},更新至版本{quantVersion};\r\n逻辑机经{irDescription},更新至版本{irVersion};\r\n阅读机经{rcDescription},更新至版本{rcVersion}.\r\n附件为最新版机经,您也可以:{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(68, '机经更新', 'inside', 'textbook_update_subscribe', '数学机经{quantDescription},更新至版本{quantVersion};\r\n逻辑机经{irDescription},更新至版本{irVersion};\r\n阅读机经{rcDescription},更新至版本{rcVersion}.\r\n最新版本机经已发送至您的邮箱{email}', '', NULL, 0, 1, NULL),
+	(69, '[千行GMAT]到期提醒', 'email', 'vip_use_expire', '同学您好,\r\n您的“{title}”将于{days}天后过期,{linkHtml}\r\n\r\nBest\r\n千行团队', '', NULL, 0, 1, NULL),
+	(70, '提问回复', 'inside', 'ask_question_special', '您在{date}对“{title}”的提问“{content}”已经被老师回答并精选啦~', '', NULL, 0, 0, NULL),
+	(71, '提问回复', 'inside', 'ask_course_special', '您在{date}对“{title}-课时{no}”的提问“{content}”已经被老师回答并精选啦~', '', NULL, 0, 0, NULL);
+
 
 CREATE TABLE pay (
   id bigint(30) unsigned NOT NULL AUTO_INCREMENT,

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

@@ -537,7 +537,7 @@ public class SettingController {
         // 绑定用户
         Collection userIds = Transform.getIds(p, Comment.class, "userId");
         List<User> userList = usersService.select(userIds);
-        Transform.combine(pr, userList, CommentDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+        Transform.combine(pr, userList, CommentInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
 
         // 绑定课程
         List<CommentInfoDto> prCourse = pr.stream().filter((row)-> row.getChannel().equals("course-video")).collect(Collectors.toList());
@@ -631,7 +631,7 @@ public class SettingController {
         // 绑定用户
         Collection userIds = Transform.getIds(p, Faq.class, "userId");
         List<User> userList = usersService.select(userIds);
-        Transform.combine(pr, userList, CommentDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
+        Transform.combine(pr, userList, FaqInfoDto.class, "userId", "user", User.class, "id", UserExtendDto.class);
 
         // 绑定position
         // 绑定课程

+ 6 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/ExportService.java

@@ -4,6 +4,7 @@ import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.nuliji.tools.Transform;
 import com.nuliji.tools.exception.ParameterException;
+import com.qxgmat.data.constants.enums.QuestionType;
 import com.qxgmat.data.constants.enums.user.AskTarget;
 import com.qxgmat.data.constants.enums.user.ExportType;
 import com.qxgmat.data.dao.entity.*;
@@ -254,6 +255,11 @@ public class ExportService {
         Map questionNoMap = Transform.getMap(questionNoList, QuestionNo.class, "id", "questionId");
         Transform.combine(relationList, questionNoMap, UserQuestionRelation.class, "questionNoId", "questionId");
         List<Question> questionList = questionService.select(questionIds);
+        for(Question question : questionList){
+            if (QuestionType.ValueOf(question.getQuestionType()) == QuestionType.IR){
+                throw new ParameterException("“综合推理IR”暂时无法导出。");
+            }
+        }
         Transform.combine(relationList, questionList, UserQuestionRelation.class, "questionId", "question", Question.class, "id");
 
         // 题源联想

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

@@ -21,6 +21,7 @@ import org.slf4j.LoggerFactory;
 import org.springframework.stereotype.Service;
 
 import javax.annotation.Resource;
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Date;
 import java.util.List;
@@ -51,6 +52,7 @@ public class UserOrderCheckoutService extends AbstractService {
      * @return
      */
     public List<UserOrderCheckout> listWithProduct(Integer userId, ProductType productType, Collection productIds){
+        if(productIds == null || productIds.size()==0) return new ArrayList<>();
         Example example = new Example(UserOrderCheckout.class);
         example.and(
                 example.createCriteria()

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

@@ -193,6 +193,7 @@ public class UserOrderRecordService extends AbstractService {
      * @return
      */
     public List<UserOrderRecord> listWithUserData(Integer userId, Collection dataIds){
+        if (dataIds == null || dataIds.size() == 0) return new ArrayList<>();
         Example example = new Example(UserOrderRecord.class);
         example.and(
                 example.createCriteria()
@@ -210,6 +211,7 @@ public class UserOrderRecordService extends AbstractService {
      * @return
      */
     public List<UserOrderRecord> listWithDataUser(Integer dataId, Collection userIds){
+        if (userIds == null || userIds.size() == 0) return new ArrayList<>();
         Example example = new Example(UserOrderRecord.class);
         example.and(
                 example.createCriteria()