浏览代码

fix(front): 必填输入

Go 5 年之前
父节点
当前提交
8a157b795a

+ 22 - 9
front/project/www/components/Login/index.js

@@ -21,13 +21,18 @@ export default class Login extends Component {
   constructor(props) {
     super(props);
     this.validNumber = 0;
-    this.state = { type: LOGIN_WX, empty: {}, data: { area: MobileArea[0].value } };
+    this.needScan = true;
+    this.state = { scanNumber: 0, type: LOGIN_WX, empty: {}, data: { area: MobileArea[0].value } };
     this.validMobileNumber = 0;
     this.validEmailNumber = 0;
     window.addEventListener(
       'message',
       event => {
         if (typeof event.data === 'string' && event.data.indexOf('code:') === 0) {
+          if (!this.needScan) {
+            return;
+          }
+          this.needScan = false;
           const code = event.data.split(':')[1];
           if (this.state.type === LOGIN_WX) {
             this.scanLogin(code);
@@ -87,16 +92,16 @@ export default class Login extends Component {
   }
 
   bind() {
-    const { data, needEmail, mobileError, emailError, validError, error } = this.state;
+    const { data, needEmail, mobileError, emailError, validError, empty } = this.state;
     const { area, mobile, mobileVerifyCode, email } = data;
     if (mobileError || emailError || validError) return;
     if (!area || !mobile || !mobileVerifyCode || (needEmail && !email)) {
-      error[BIND_PHONE] = { mobile: !mobile, mobileVerifyCode: !mobileVerifyCode, email: !email };
-      this.setState({ error });
+      empty[BIND_PHONE] = { mobile: !mobile, mobileVerifyCode: !mobileVerifyCode, email: !email };
+      this.setState({ empty });
       return;
     }
-    error[BIND_PHONE] = {};
-    this.setState({ error });
+    empty[BIND_PHONE] = {};
+    this.setState({ empty });
     User.bind(area, mobile, mobileVerifyCode, email)
       .then(() => {
         this.close();
@@ -140,6 +145,7 @@ export default class Login extends Component {
     let { data, empty } = this.state;
     data = data || {};
     empty = empty || {};
+    empty[this.state.type] = empty[this.state.type] || {};
     data[field] = value;
     if (value) empty[this.state.type][field] = !value;
     this.setState({ data, empty });
@@ -208,7 +214,12 @@ export default class Login extends Component {
   }
 
   changeType(type) {
-    this.setState({ type, empty: {}, mobileError: '', emailError: '', validError: '' });
+    let { scanNumber } = this.state;
+    if (type === LOGIN_WX || type === BIND_WX) {
+      this.needScan = true;
+      scanNumber += 1;
+    }
+    this.setState({ scanNumber, type, empty: {}, mobileError: '', emailError: '', validError: '', data: {} });
   }
 
   render() {
@@ -231,10 +242,10 @@ export default class Login extends Component {
           onClick={() => {
             if (type === BIND_WX_ERROR) {
               // 绑定微信错误,返回重新绑定微信
-              this.setState({ type: BIND_WX });
+              this.changeType(BIND_WX);
             } else {
-              this.setState({ type: LOGIN_WX });
               User.closeLogin(new Error('no login'));
+              this.changeType(LOGIN_WX);
             }
           }}
         />
@@ -352,6 +363,7 @@ export default class Login extends Component {
         <div className="title">微信扫码登录</div>
         <div className="qr-code">
           <iframe
+            key={this.state.scanNumber}
             frameBorder="0"
             src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent(PcUrl)}`}
             width="300"
@@ -469,6 +481,7 @@ export default class Login extends Component {
         </div>
         <div className="qr-code">
           <iframe
+            key={this.state.scanNumber}
             frameBorder="0"
             src={`/login.html?appid=${WechatPcAppId}&redirectUri=${encodeURIComponent(PcUrl)}`}
             width="300"

+ 144 - 50
front/project/www/components/OtherModal/index.js

@@ -772,11 +772,32 @@ export class FeedbackErrorDataModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
+  changeDataIndex(field, index, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field][index] = value;
+    if (value) empty[`${field}[${index}]`] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content || !data.originContent) return;
-    My.addFeedbackErrorData(data.dataId, data.title, data.position.join(','), data.originContent, data.content).then(
+    if (!data.position[0] || !data.position[1] || !data.position[2] || !data.content || !data.originContent) {
+      this.setState({ empty: { 'position[0]': !data.position[0], 'position[1]': !data.position[1], 'position[2]': !data.position[2], content: !data.content, originContent: !data.originContent } });
+      return Promise.reject();
+    }
+    return My.addFeedbackErrorData(data.dataId, data.title, data.position.join(','), data.originContent, data.content).then(
       () => {
         this.setState({ data: { position: ['', '', ''], content: '', originContent: '' } });
         if (onConfirm) onConfirm();
@@ -792,7 +813,7 @@ export class FeedbackErrorDataModal extends Component {
 
   render() {
     const { show } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal
         show={show}
@@ -808,9 +829,9 @@ export class FeedbackErrorDataModal extends Component {
             value={data.position[0]}
             className="t-c b-c-1 m-r-5"
             style={{ width: 56 }}
+            empty={empty['position[0]']}
             onChange={e => {
-              data.position[0] = e.target.value;
-              this.setState({ data });
+              this.changeDataIndex('position', 0, e.target.value);
             }}
           />
           <span className="require">页</span>
@@ -818,9 +839,9 @@ export class FeedbackErrorDataModal extends Component {
             value={data.position[1]}
             className="t-c b-c-1 m-r-5"
             style={{ width: 56 }}
+            empty={empty['position[1]']}
             onChange={e => {
-              data.position[1] = e.target.value;
-              this.setState({ data });
+              this.changeDataIndex('position', 1, e.target.value);
             }}
           />
           <span className="require">行</span> , 题号
@@ -828,9 +849,9 @@ export class FeedbackErrorDataModal extends Component {
             value={data.position[2]}
             className="t-c b-c-1"
             style={{ width: 56 }}
+            empty={empty['position[2]']}
             onChange={e => {
-              data.position[2] = e.target.value;
-              this.setState({ data });
+              this.changeDataIndex('position', 2, e.target.value);
             }}
           />
         </div>
@@ -840,9 +861,9 @@ export class FeedbackErrorDataModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={10}
           placeholder={'可简单描述您发现的问题'}
+          empty={empty.originContent}
           onChange={e => {
-            data.originContent = e.target.value;
-            this.setState({ data });
+            this.changeData('originContent', e.target.value);
           }}
         />
         <div className="t-2 t-s-16">应该更改为:</div>
@@ -851,9 +872,9 @@ export class FeedbackErrorDataModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={10}
           placeholder={'提供您认为正确的内容即可'}
+          empty={empty.content}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -874,11 +895,23 @@ export class AskCourseModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { course, courseNo, onConfirm } = this.props;
     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 (!data.content || !data.originContent) {
+      this.setState({ empty: { content: !data.content, originContent: !data.originContent } });
+      return Promise.reject();
+    }
+    return My.addCourseAsk(course.id, courseNo.id, data.position.join(','), data.originContent, data.content).then(() => {
       this.setState({ data: { position: [], content: '', originContent: '' } });
       if (onConfirm) onConfirm();
     });
@@ -892,7 +925,7 @@ export class AskCourseModal extends Component {
 
   render() {
     const { show, selectList, courseNo, getContainer } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal
         show={show}
@@ -911,8 +944,7 @@ export class AskCourseModal extends Component {
             theme="white"
             list={selectList}
             onChange={item => {
-              data.position = item.key;
-              this.setState({ data });
+              this.changeData('position', item.key);
             }}
           />
           进行提问.
@@ -923,9 +955,9 @@ export class AskCourseModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={4}
           placeholder={'请简单描述,以便老师准确定位。'}
+          empty={empty.originContent}
           onChange={e => {
-            data.originContent = e.target.value;
-            this.setState({ data });
+            this.changeData('originContent', e.target.value);
           }}
         />
         <div className="t-2 t-s-16">您的问题是:</div>
@@ -935,8 +967,7 @@ export class AskCourseModal extends Component {
           rows={4}
           placeholder={'老师会在n小时内回答你的问题。'}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -957,11 +988,23 @@ export class CourseNoteModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { course, onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content) return;
-    My.updateCourseNote(course.id, data.courseNoId, data.content).then(() => {
+    if (!data.content || !data.originContent) {
+      this.setState({ empty: { content: !data.content } });
+      return Promise.reject();
+    }
+    return My.updateCourseNote(course.id, data.courseNoId, data.content).then(() => {
       this.setState({ data: { content: '' } });
       if (onConfirm) onConfirm();
     });
@@ -975,7 +1018,7 @@ export class CourseNoteModal extends Component {
 
   render() {
     const { show, course = {}, courseNos = [], noteMap = {}, getContainer } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal
         show={show}
@@ -1011,9 +1054,9 @@ export class CourseNoteModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={10}
           placeholder={'写下笔记,方便以后复习。'}
+          empty={empty.content}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -1048,12 +1091,27 @@ export class TextbookFeedbackModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content) return;
-    if (data.target !== 'new' && !data.no) return;
-    My.addTextbookFeedback(data.textbookSubject, data.target, data.no, data.content)
+    if (data.target !== 'new' && (!data.no || !data.content)) {
+      this.setState({ empty: { content: !data.content, no: !data.no } });
+      return Promise.reject();
+    }
+    if (!data.content) {
+      this.setState({ empty: { content: !data.content } });
+      return Promise.reject();
+    }
+    return My.addTextbookFeedback(data.textbookSubject, data.target, data.no, data.content)
       .then(() => {
         this.setState({ data: { content: '' } });
         if (onConfirm) onConfirm();
@@ -1071,7 +1129,7 @@ export class TextbookFeedbackModal extends Component {
 
   render() {
     const { show } = this.props;
-    const { data, targetList, textbookSubject } = this.state;
+    const { data, targetList, textbookSubject, empty = {} } = this.state;
     return (
       <Modal show={show} title="反馈" width={630} onConfirm={() => this.onConfirm()} onCancel={() => this.onCancel()}>
         <div className="t-2 t-s-16 m-b-1">
@@ -1102,9 +1160,9 @@ export class TextbookFeedbackModal extends Component {
               value={data.no}
               style={{ width: 80 }}
               className="m-l-1 b-c-1 t-c"
+              empty={empty.no}
               onChange={e => {
-                data.no = e.target.value;
-                this.setState({ data });
+                this.changeData('no', e.target.value);
               }}
             />
           </span>
@@ -1115,9 +1173,9 @@ export class TextbookFeedbackModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={10}
           placeholder={TextbookFeedbackTargetMap[data.target]}
+          empty={empty.content}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -1138,11 +1196,23 @@ export class FaqModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content) return;
-    My.addFaq(data.channel, data.position, data.content).then(() => {
+    if (!data.content) {
+      this.setState({ empty: { content: !data.content } });
+      return Promise.reject();
+    }
+    return My.addFaq(data.channel, data.position, data.content).then(() => {
       this.setState({ data: { content: '' } });
       if (onConfirm) onConfirm();
     });
@@ -1156,7 +1226,7 @@ export class FaqModal extends Component {
 
   render() {
     const { show } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal show={show} title="咨询" onConfirm={() => this.onConfirm()} onCancel={() => this.onCancel()}>
         <textarea
@@ -1164,9 +1234,9 @@ export class FaqModal extends Component {
           value={data.content}
           rows={6}
           placeholder="请输入您的问题!"
+          empty={empty.content}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -1187,11 +1257,23 @@ export class CommentModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content) return;
-    My.addComment(data.channel, data.position, data.content).then(() => {
+    if (!data.content) {
+      this.setState({ empty: { content: !data.content } });
+      return Promise.reject();
+    }
+    return My.addComment(data.channel, data.position, data.content).then(() => {
       this.setState({ data: { content: '' } });
       if (onConfirm) onConfirm();
     });
@@ -1205,7 +1287,7 @@ export class CommentModal extends Component {
 
   render() {
     const { show } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal show={show} title="评价" onConfirm={() => this.onConfirm()} onCancel={() => this.onCancel()}>
         <textarea
@@ -1213,9 +1295,9 @@ export class CommentModal extends Component {
           className="b-c-1 w-10 p-10"
           rows={6}
           placeholder="您的看法对我们来说很重要!"
+          empty={empty.content}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />
@@ -1250,11 +1332,23 @@ export class SuppleModal extends Component {
     }
   }
 
+  changeData(field, value) {
+    let { data, empty } = this.state;
+    data = data || {};
+    empty = empty || {};
+    data[field] = value;
+    if (value) empty[field] = !value;
+    this.setState({ data, empty });
+  }
+
   onConfirm() {
     const { onConfirm } = this.props;
     const { data } = this.state;
-    if (!data.content) return;
-    My.addRoomFeedback(data.roomId, data.content).then(() => {
+    if (!data.content) {
+      this.setState({ empty: { content: !data.content } });
+      return Promise.reject();
+    }
+    return My.addRoomFeedback(data.roomId, data.content).then(() => {
       this.setState({ data: { content: '' } });
       if (onConfirm) onConfirm();
     });
@@ -1268,7 +1362,7 @@ export class SuppleModal extends Component {
 
   render() {
     const { show, info = {} } = this.props;
-    const { data } = this.state;
+    const { data, empty = {} } = this.state;
     return (
       <Modal show={show} title="考场信息" onConfirm={() => this.onConfirm()} onCancel={() => this.onCancel()}>
         <div className="t-2 t-s-16">考场位置: {info.isOverseas ? '海外' : '中国'}{info.area ? ` ${info.area}` : ''} {info.title}</div>
@@ -1276,10 +1370,10 @@ export class SuppleModal extends Component {
         <textarea
           value={data.content}
           className="b-c-1 w-10 p-10"
+          empty={empty.content}
           rows={6}
           onChange={e => {
-            data.content = e.target.value;
-            this.setState({ data });
+            this.changeData('content', e.target.value);
           }}
         />
         <div className="b-b m-t-2" />

+ 1 - 5
front/project/www/routes/page/home/index.less

@@ -437,11 +437,7 @@
           }
 
           &:hover {
-            height: 250px;
-
-            .desc {
-              width: 250px;
-            }
+            height: 210px;
           }
         }
 

+ 2 - 2
front/project/www/routes/page/home/page.js

@@ -227,7 +227,7 @@ export default class extends Page {
                   </div>
                   <div className="item m-r-1-5 m-l-1-5 item2" onClick={() => linkTo('/textbook')}>
                     <Assets className="sun" name="sun_red" />
-                    <div className="title" style={{ color: '#FFB676' }}>
+                    <div className="title" style={{ color: '#F36565' }}>
                       机经服务<span className="sub">></span>
                     </div>
                     <div className="desc">⾼效整理:梳理逻辑结构,⽆“反吞 噬”⻛险</div>
@@ -236,7 +236,7 @@ export default class extends Page {
                   </div>
                   <div className="item m-l-1-5 item3" onClick={() => User.needLogin().then(() => linkTo('/my'))}>
                     <Assets className="sun" name="sun_yello" />
-                    <div className="title" style={{ color: '#F36565' }}>
+                    <div className="title" style={{ color: '#FFB676' }}>
                       VIP服务<span className="sub">></span>
                     </div>
                     <div className="desc">⾃由组卷,练你想练</div>

+ 1 - 1
front/src/services/Tools.js

@@ -312,7 +312,7 @@ export function formatSeconds(seconds, rand = false) {
   if (time >= 60 && time < 3600) {
     return `${parseInt(time / 60, 10)}min${rand ? '' : formatSeconds(time % 60)}`;
   }
-  return `${parseInt(time / 3600, 10)}hour${rand ? '' : formatSecond(time % 3600)}hour`;
+  return `${parseInt(time / 3600, 10)}hour${rand ? '' : formatSeconds(time % 3600)}`;
 }
 
 export function formatPercent(child, mother, number = true) {

+ 2 - 0
server/gateway-api/build.gradle

@@ -5,6 +5,7 @@ mainClassName = 'com.qxgmat.Application'
 repositories {
     mavenLocal()
     maven { url = "http://maven.aliyun.com/nexus/content/groups/public" }
+    maven { url = "http://repo.e-iceblue.com/nexus/content/groups/public" }
     mavenCentral()
 }
 
@@ -26,6 +27,7 @@ dependencies {
     compileClasspath group: 'org.apache.poi', name: 'poi', version: '3.17'
     compileClasspath group: 'org.apache.poi', name: 'poi-ooxml', version: '3.17'
 
+    compileClasspath group: 'e-iceblue', name: 'spire.pdf', version: '2.2.0'
 
 //    compile group: 'commons-lang', name: 'commons-lang', version:'2.6'
 //    compile group: 'commons-fileupload', name: 'commons-fileupload', version:'1.3.3'

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

@@ -23,10 +23,7 @@ import com.qxgmat.dto.request.FaqDto;
 import com.qxgmat.dto.request.UserCollectQuestionDto;
 import com.qxgmat.dto.request.UserNoteQuestionDto;
 import com.qxgmat.dto.response.*;
-import com.qxgmat.help.AiHelp;
-import com.qxgmat.help.MailHelp;
-import com.qxgmat.help.ShiroHelp;
-import com.qxgmat.help.SmsHelp;
+import com.qxgmat.help.*;
 import com.qxgmat.service.*;
 import com.qxgmat.service.extend.*;
 import com.qxgmat.service.inline.*;
@@ -39,10 +36,13 @@ import org.springframework.validation.annotation.Validated;
 import org.springframework.web.bind.annotation.*;
 import org.springframework.web.multipart.MultipartFile;
 
+import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
 import javax.servlet.http.HttpSession;
 import javax.validation.Validator;
 import java.io.File;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.text.DateFormat;
 import java.text.ParseException;
@@ -61,6 +61,9 @@ public class MyController {
     @Autowired
     private SmsHelp smsHelp;
 
+    @Autowired
+    private PdfHelp pdfHelp;
+
     @Value("${upload.local_path}")
     private String localPath;
 
@@ -2186,4 +2189,73 @@ public class MyController {
 
         return ResponseHelp.success(pr);
     }
+
+    @RequestMapping(value = "/download/data", method = RequestMethod.GET)
+    @ApiOperation(value = "获取资料", httpMethod = "GET")
+    public void pdfDownLoad(@RequestParam(required = true) Integer id, HttpServletRequest request, HttpServletResponse response){
+        User user = (User) shiroHelp.getLoginUser();
+        CourseData courseData = courseDataService.get(id);
+        if (!userOrderRecordService.hasData(user.getId(), courseData.getId())){
+            throw new AuthException("未授权");
+        }
+        try {
+            String resource = courseData.getResource();
+            String fileName = pdfHelp.generatePdfImage(user.getId(), resource, false);
+            FileInputStream fileInputStream = new FileInputStream(fileName);
+            ServletOutputStream outputStream = response.getOutputStream();
+            response.setHeader("content-disposition","attachment;filename="+fileName);
+            response.setHeader("content-type", "application/pdf");
+            //输出
+            int len = 1;
+            byte[] bs = new byte[1024];
+            while((len = fileInputStream.read(bs)) != -1){
+                outputStream.write(bs, 0, len);
+            }
+            fileInputStream.close();
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+    }
+
+    @RequestMapping(value = "/download/textbook", method = RequestMethod.GET)
+    @ApiOperation(value = "获取机经", httpMethod = "GET")
+    public void pdfDownLoad(@RequestParam(required = true) String subject, HttpServletRequest request, HttpServletResponse response){
+        User user = (User) shiroHelp.getLoginUser();
+        if (!userServiceService.hasService(user.getId(), ServiceKey.TEXTBOOK)){
+            throw new AuthException("未授权");
+        }
+        TextbookSubject textbookSubject = TextbookSubject.ValueOf(subject);
+        if (textbookSubject == null){
+            throw new ParameterException("subject错误");
+        }
+        TextbookLibrary latest = textbookLibraryService.getLatest();
+        try {
+            String resource = "";
+            switch(textbookSubject){
+                case IR:
+                    resource = latest.getIr();
+                    break;
+                case RC:
+                    resource = latest.getRc();
+                    break;
+                case QUANT:
+                    resource = latest.getQuant();
+                    break;
+            }
+            String fileName = pdfHelp.generatePdfImage(user.getId(), resource, false);
+            FileInputStream fileInputStream = new FileInputStream(fileName);
+            ServletOutputStream outputStream = response.getOutputStream();
+            response.setHeader("content-disposition","attachment;filename="+fileName);
+            response.setHeader("content-type", "application/pdf");
+            //输出
+            int len = 1;
+            byte[] bs = new byte[1024];
+            while((len = fileInputStream.read(bs)) != -1){
+                outputStream.write(bs, 0, len);
+            }
+            fileInputStream.close();
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+    }
 }

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

@@ -245,7 +245,7 @@ public class TextbookController
         Date start = Tools.baseDate(String.format("%s-01-01", year));
         Date end = Tools.addYear(start, 1);
         List<TextbookLibrary> libraryList = textbookLibraryService.listByTime(start, end);
-        textbookService.refreshLibraryResource(user, libraryList);
+        textbookService.refreshLibraryResource(null, libraryList);
         return ResponseHelp.success(libraryList);
     }
 

+ 119 - 0
server/gateway-api/src/main/java/com/qxgmat/help/PdfHelp.java

@@ -0,0 +1,119 @@
+package com.qxgmat.help;
+
+import com.spire.pdf.PdfDocument;
+import com.spire.pdf.PdfPageBase;
+import com.spire.pdf.graphics.*;
+import com.spire.pdf.widget.PdfPageCollection;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Service;
+
+import javax.imageio.ImageIO;
+import java.awt.*;
+import java.awt.geom.Dimension2D;
+import java.awt.geom.Point2D;
+import java.awt.geom.Rectangle2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.io.IOException;
+
+/**
+ * Created by GaoJie on 2017/11/3.
+ */
+@Service
+public class PdfHelp {
+    private static final Logger logger = LoggerFactory.getLogger(PdfHelp.class);
+
+    @Value("${upload.local_path}")
+    private String localPath;
+
+    @Value("${upload.web_url}")
+    private String webUrl;
+
+    @Value("${upload.water}")
+    private String water;
+    
+    public String generatePdfImage(Integer userId, String pdfUrl, boolean force) throws IOException {
+        String pdfFile = pdfUrl.replace(webUrl, localPath);
+        String dest = pdfFile.replace(".pdf", String.format("_%d.pdf", userId));
+        File file = new File(dest);
+
+        if (!force && file.exists()){
+            return dest;
+        }
+
+        PdfDocument pdf = new PdfDocument();
+        pdf.loadFromFile(pdfFile);
+
+        File srcImgFile = new File(water);
+        Image srcImg = ImageIO.read(srcImgFile);
+
+        BufferedImage bi = toBufferedImage(srcImg);
+        for (Object page: pdf.getPages()) {
+            AddImageWatermark((PdfPageBase)page, bi);
+        }
+
+        //保存
+        pdf.saveToFile(dest);
+        //关闭
+        pdf.close();
+        return dest;
+    }
+
+    public static BufferedImage toBufferedImage(Image img)
+    {
+        if (img instanceof BufferedImage)
+        {
+            return (BufferedImage) img;
+        }
+
+        // Create a buffered image with transparency
+        BufferedImage bimage = new BufferedImage(img.getWidth(null), img.getHeight(null), BufferedImage.TYPE_INT_ARGB);
+
+        // Draw the image on to the buffered image
+        Graphics2D bGr = bimage.createGraphics();
+        bGr.drawImage(img, 0, 0, null);
+        bGr.dispose();
+
+        // Return the buffered image
+        return bimage;
+    }
+
+    /**
+     * @param page
+     * 要添加水印的页面
+     * @param image
+     * 水印图片路径
+     */
+    static void AddImageWatermark(PdfPageBase page, BufferedImage image)
+    {
+        page.setBackgroundImage(image);
+        Rectangle2D rect = new Rectangle2D.Float();
+        rect.setFrame(page.getClientSize().getWidth()/2 - image.getWidth() / 2, page.getClientSize().getHeight()/2 - image.getHeight()/2, image.getWidth(), image.getHeight());
+        page.setBackgroundRegion(rect);
+    }
+ 
+    /**
+      * @param page
+      * 要添加水印的页面
+      * @param textWatermark
+      * 水印文字
+      */
+    static void AddTextWatermark(PdfPageBase page, String textWatermark)
+    {
+        Dimension2D dimension2D = new Dimension();
+        dimension2D.setSize(page.getCanvas().getClientSize().getWidth() / 2, page.getCanvas().getClientSize().getHeight() / 3);
+        PdfTilingBrush brush = new PdfTilingBrush(dimension2D);
+        brush.getGraphics().setTransparency(0.3F);
+        brush.getGraphics().save();
+        brush.getGraphics().translateTransform((float) brush.getSize().getWidth() / 2, (float) brush.getSize().getHeight() / 2);
+        brush.getGraphics().rotateTransform(-45);
+        brush.getGraphics().drawString(textWatermark, new PdfTrueTypeFont(new Font("Arial Unicode MS",Font.PLAIN,30),true), PdfBrushes.getRed(), 0, 0, new PdfStringFormat(PdfTextAlignment.Center));
+        brush.getGraphics().restore();
+        brush.getGraphics().setTransparency(1);
+        Rectangle2D loRect = new Rectangle2D.Float();
+        loRect.setFrame(new Point2D.Float(0, 0), page.getCanvas().getClientSize());
+        page.getCanvas().drawRectangle(brush, loRect);
+    }
+}

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

@@ -325,7 +325,7 @@ public class UsersService extends AbstractService {
         // 查找手机或邀请码
         example.and(
                 example.createCriteria()
-                        .orEqualTo("invite_code", inviteCode)
+                        .orEqualTo("inviteCode", inviteCode)
                         .orEqualTo("mobile", inviteCode)
         );
         return one(userMapper, example);

+ 4 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java

@@ -296,6 +296,8 @@ public class CourseExtendService {
         if (user != null){
             if (!userOrderRecordService.hasData(user.getId(), courseData.getId())){
                 courseData.setResource(courseData.getTrailResource());
+            }else{
+                courseData.setResource("/api/my/download/data?id="+courseData.getId());
             }
         }else{
             courseData.setResource(courseData.getTrailResource());
@@ -315,6 +317,8 @@ public class CourseExtendService {
             for(CourseData courseData : courseDataList){
                 if (!map.containsKey(courseData.getId())){
                     courseData.setResource(courseData.getTrailResource());
+                }else{
+                    courseData.setResource("/api/my/download/data?id="+courseData.getId());
                 }
             }
         }else{

+ 23 - 4
server/gateway-api/src/main/java/com/qxgmat/service/extend/MessageExtendService.java

@@ -12,6 +12,7 @@ import com.qxgmat.data.constants.enums.user.DataType;
 import com.qxgmat.data.constants.enums.user.FeedbackTarget;
 import com.qxgmat.data.dao.entity.*;
 import com.qxgmat.help.MailHelp;
+import com.qxgmat.help.PdfHelp;
 import com.qxgmat.help.SmsHelp;
 import com.qxgmat.help.WechatHelp;
 import com.qxgmat.service.inline.*;
@@ -37,6 +38,9 @@ public class MessageExtendService {
     private SmsHelp smsHelp;
 
     @Resource
+    private PdfHelp pdfHelp;
+
+    @Resource
     private UserMessageService userMessageService;
 
     @Resource
@@ -302,8 +306,15 @@ public class MessageExtendService {
         map.put("rcVersion", String.valueOf(textbookLibrary.getRcVersion()));
         map.put("rcDescription", String.valueOf(textbookLibrary.getRcDescription()));
         if (subscribe){
-            map.put("attachments", String.format("%s;%s;%s", textbookLibrary.getQuant(), textbookLibrary.getIr(), textbookLibrary.getRc()));
-            send(user, MessageCategory.TEXTBOOK_UPDATE_SUBSCRIBE, map, 0);
+            try {
+                String quant = pdfHelp.generatePdfImage(user.getId(), textbookLibrary.getQuant(), true);
+                String ir = pdfHelp.generatePdfImage(user.getId(), textbookLibrary.getIr(), true);
+                String rc = pdfHelp.generatePdfImage(user.getId(), textbookLibrary.getRc(), true);
+                map.put("attachments", String.format("%s;%s;%s", quant, ir, rc));
+                send(user, MessageCategory.TEXTBOOK_UPDATE_SUBSCRIBE, map, 0);
+            }catch (Exception e){
+
+            }
         }else{
             send(user, MessageCategory.TEXTBOOK_UPDATE, map, 0);
         }
@@ -588,8 +599,16 @@ public class MessageExtendService {
                 break;
             case ELECTRON:
                 if (subscribe){
-                    map.put("attachment", data.getResource());
-                    send(user, MessageCategory.DATA_UPDATE_SUBSCRIBE, map, data.getId());
+                    try{
+                        // todo 获取水印文件
+                        String file = pdfHelp.generatePdfImage(user.getId(), data.getResource(), true);
+
+                        map.put("attachment", file);
+                        send(user, MessageCategory.DATA_UPDATE_SUBSCRIBE, map, data.getId());
+                    }catch (Exception e){
+
+                    }
+
                 }else{
                     send(user, MessageCategory.DATA_UPDATE_BASE, map, data.getId());
                 }

+ 12 - 0
server/gateway-api/src/main/java/com/qxgmat/service/extend/TextbookService.java

@@ -217,6 +217,11 @@ public class TextbookService {
                 textbookLibrary.setRc("");
                 textbookLibrary.setIr("");
                 textbookLibrary.setQuant("");
+            }else{
+                // 替换为水印地址
+                textbookLibrary.setRc("/api/my/download/textbook?subject=rc");
+                textbookLibrary.setIr("/api/my/download/textbook?subject=ir");
+                textbookLibrary.setQuant("/api/my/download/textbook?subject=quant");
             }
         }else{
             textbookLibrary.setRc("");
@@ -239,6 +244,13 @@ public class TextbookService {
                     textbookLibrary.setIr("");
                     textbookLibrary.setQuant("");
                 }
+            }else{
+                for (TextbookLibrary textbookLibrary : textbookLibraryList) {
+                    // 替换为水印地址
+                    textbookLibrary.setRc("/api/my/download/textbook?subject=rc");
+                    textbookLibrary.setIr("/api/my/download/textbook?subject=ir");
+                    textbookLibrary.setQuant("/api/my/download/textbook?subject=quant");
+                }
             }
         }else{
             for(TextbookLibrary textbookLibrary : textbookLibraryList){