Browse Source

fix(all): 修复统一bug

Go 4 years ago
parent
commit
c296aaf329
35 changed files with 363 additions and 229 deletions
  1. 25 5
      front/.eslintrc
  2. 1 0
      front/config/index.js
  3. 2 0
      front/project/Constant.js
  4. 6 6
      front/project/admin/routes/user/abnormal/page.js
  5. 2 1
      front/project/admin/routes/user/detail/page.js
  6. 9 0
      front/project/www/components/Login/index.js
  7. 13 5
      front/project/www/components/OtherModal/index.js
  8. 1 1
      front/project/www/components/PayModal/index.js
  9. 2 1
      front/project/www/routes/course/detail/page.js
  10. 1 1
      front/project/www/routes/examination/list/page.js
  11. 1 0
      front/project/www/routes/examination/main/page.js
  12. 2 2
      front/project/www/routes/my/data/page.js
  13. 5 5
      front/project/www/routes/my/main/page.js
  14. 1 1
      front/project/www/routes/my/tools/page.js
  15. 15 9
      front/project/www/routes/paper/process/base/index.js
  16. 42 11
      front/project/www/routes/paper/process/page.js
  17. 4 4
      front/project/www/routes/paper/question/detail/index.js
  18. 74 66
      front/project/www/routes/paper/report/page.js
  19. 5 7
      front/project/www/stores/user.js
  20. 5 0
      server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java
  21. 0 5
      server/data/src/main/java/com/qxgmat/data/relation/UserReportRelationMapper.java
  22. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/ExaminationPaperRelationMapper.xml
  23. 2 2
      server/data/src/main/java/com/qxgmat/data/relation/mapping/QuestionNoRelationMapper.xml
  24. 20 0
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml
  25. 0 21
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserReportRelationMapper.xml
  26. 7 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  27. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/QuestionController.java
  28. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/extend/UserExtendDto.java
  29. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/UserReportExtendDto.java
  30. 21 0
      server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java
  31. 1 1
      server/gateway-api/src/main/java/com/qxgmat/service/extend/ExaminationService.java
  32. 60 52
      server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java
  33. 6 1
      server/gateway-api/src/main/java/com/qxgmat/service/inline/QuestionNoService.java
  34. 7 18
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserReportService.java
  35. 1 1
      server/gateway-api/src/main/java/com/qxgmat/task/ScheduledTask.java

+ 25 - 5
front/.eslintrc

@@ -1,11 +1,30 @@
 {
   "parser": "babel-eslint",
-  "extends": ["standard-react", "airbnb-base"],
-  "plugins": ["react", "import"],
+  "extends": [
+    "standard-react",
+    "airbnb-base"
+  ],
+  "plugins": [
+    "react",
+    "import"
+  ],
   "settings": {
     "import/resolver": {
       "alias": {
-        "map": [["@src", "./src"], ["@project", "./project/admin"], ["@components", "./components"]]
+        "map": [
+          [
+            "@src",
+            "./src"
+          ],
+          [
+            "@project",
+            "./project/admin"
+          ],
+          [
+            "@components",
+            "./components"
+          ]
+        ]
       }
     }
   },
@@ -39,7 +58,8 @@
     "__PcUrl__": false,
     "__H5Url__": false,
     "__WechatPcAppId__": false,
-    "__WechatH5AppId__": false
+    "__WechatH5AppId__": false,
+    "__AssetsQrCode__": false,
   },
   "rules": {
     "camelcase": "off",
@@ -66,4 +86,4 @@
     "import/no-named-as-default": "off",
     "operator-linebreak": "off"
   }
-}
+}

+ 1 - 0
front/config/index.js

@@ -56,6 +56,7 @@ config.globals = {
   __WechatPcAppId__: `\'${config.WechatPcAppId}\'`,
   __H5Url__: `\'${config.H5Url}\'`,
   __WechatH5AppId__: `\'${config.WechatH5AppId}\'`,
+  __AssetsQrCode__: `\'qrcode${config.env == 'test' ? '_test' : ''}\'`,
 };
 
 debug(`Looking for environment overrides for NODE_ENV '${config.env}'.`);

+ 2 - 0
front/project/Constant.js

@@ -6,6 +6,8 @@ export const H5Url = __H5Url__;
 
 export const WechatH5AppId = __WechatH5AppId__;
 
+export const QrCode = __AssetsQrCode__;
+
 export const QuestionDifficult = [{ label: 'Easy', value: 'easy', sort: 2 }, { label: 'Medium', value: 'medium', sort: 1 }, { label: 'Hard', value: 'hard', sort: 0 }];
 
 export const QuestionType = [{ label: '语法SC', value: 'sc', long: 'Sentence Correnction' }, { label: '阅读RC', value: 'rc', long: 'Reading Comprehension' }, { label: '逻辑CR', value: 'cr', long: 'Critical Reasoning' }, { label: '数学PS', value: 'ps', long: 'Problem solving' }, { label: '数学DS', value: 'ds', long: 'Data Sufficiency' }, { label: '综合推理IR', value: 'ir', long: 'Integrated Reasoning' }, { label: '作文AWA', value: 'awa', long: 'Analytical Writing Assessment' }];

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

@@ -74,20 +74,20 @@ export default class extends Page {
         return <div className="table-button">
           {!!record.isIgnore && '已忽略'}
           {!!record.isAlert && '已警告'}
-          {!!record.isAlert && !!record.user.isFrozen && (
+          {!!record.user.isFrozen && (
             <a onClick={() => {
               this.noFrozenAction(record);
             }}>取消封禁</a>
           )}
-          {!record.isIgnore && !record.isAlert && (
+          {!record.user.isFrozen && (
             <a onClick={() => {
-              this.alertAction(record);
-            }}>警告</a>
+              this.frozenAction(record);
+            }}>封禁</a>
           )}
           {!record.isIgnore && !record.isAlert && (
             <a onClick={() => {
-              this.frozenAction(record);
-            }}>封禁</a>
+              this.alertAction(record);
+            }}>警告</a>
           )}
           {!record.isIgnore && !record.isAlert && (
             <a onClick={() => {

+ 2 - 1
front/project/admin/routes/user/detail/page.js

@@ -25,6 +25,7 @@ export default class extends Page {
       key: 'money',
       type: 'number',
       name: '增加金额',
+      min: 0,
     }];
     this.columns = [{
       title: '订单时间',
@@ -111,7 +112,7 @@ export default class extends Page {
     page.current = p || 1;
     page.pageSize = size || 20;
     this.setState({ page });
-    User.listService({ user_id: id, page: page.current, size: page.pageSize })
+    User.listService({ userId: id, page: page.current, size: page.pageSize })
       .then(result => {
         this.setTableData(result.list, result.total);
       });

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

@@ -3,6 +3,7 @@ import './index.less';
 import { Modal, Button, Tooltip } from 'antd';
 import Assets from '@src/components/Assets';
 import { asyncSMessage } from '@src/services/AsyncTools';
+import { checkEmail, checkMobile } from '@src/services/Tools';
 import { Icon as GIcon } from '../Icon';
 import { Button as GButton } from '../Button';
 import RadioItem from '../RadioItem';
@@ -162,6 +163,10 @@ export default class Login extends Component {
     const { data } = this.state;
     const { area, mobile } = data;
     if (!area || !mobile) return;
+    if (!checkMobile(mobile)) {
+      this.setState({ mobileError: '请输入正确的手机号' });
+      return;
+    }
     this.validMobileNumber += 1;
     const number = this.validMobileNumber;
     User.validWechat(area, mobile)
@@ -185,6 +190,10 @@ export default class Login extends Component {
     const { data } = this.state;
     const { email } = data;
     if (!email) return;
+    if (!checkEmail(email)) {
+      this.setState({ emailError: '请输入正确的邮箱' });
+      return;
+    }
     this.validEmailNumber += 1;
     const number = this.validEmailNumber;
     User.validEmail(email)

+ 13 - 5
front/project/www/components/OtherModal/index.js

@@ -9,14 +9,14 @@ import scale from '@src/services/Scale';
 import { asyncSMessage } from '@src/services/AsyncTools';
 import AnswerButton from '../AnswerButton';
 import { SelectInput, VerificationInput, DefaultInput, Input, Textarea } from '../Input';
-import { MobileArea, TextbookFeedbackTarget, TextbookSubject, AskTarget } from '../../../Constant';
+import { MobileArea, TextbookFeedbackTarget, TextbookSubject, AskTarget, QrCode } from '../../../Constant';
 import Invite from '../Invite';
 import Modal from '../Modal';
 import { Common } from '../../stores/common';
 import { User } from '../../stores/user';
 import { My } from '../../stores/my';
 import Select from '../Select';
-import { formatDate, getMap } from '../../../../src/services/Tools';
+import { formatDate, getMap, checkMobile, checkEmail } from '../../../../src/services/Tools';
 
 const TextbookFeedbackTargetMap = getMap(TextbookFeedbackTarget, 'value', 'tip');
 
@@ -70,6 +70,10 @@ export class BindPhone extends Component {
     const { data } = this.state;
     const { area, mobile } = data;
     if (!area || !mobile) return;
+    if (!checkMobile(mobile)) {
+      this.setState({ mobileError: '请输入正确手机号' });
+      return;
+    }
     this.validNumber += 1;
     const number = this.validNumber;
     if (mobile === this.props.data.mobile) {
@@ -247,6 +251,10 @@ export class BindEmail extends Component {
     const { data } = this.state;
     const { email } = data;
     if (!email) return;
+    if (!checkEmail(email)) {
+      this.setState({ error: '请输入正确邮箱' });
+      return;
+    }
     this.validNumber += 1;
     const number = this.validNumber;
     if (email === this.props.data.email) {
@@ -521,7 +529,7 @@ export class RealAuth extends Component {
             <div className="t3">扫码关注公众号,点击“我的-实名认证”</div>
           </div>
           <div className="real-auth-qrcode">
-            <Assets name="qrcode" />
+            <Assets name={QrCode} width={150} height={150} />
           </div>
         </div>
       </Modal>
@@ -1051,7 +1059,7 @@ export class CourseNoteModal extends Component {
 
   componentWillReceiveProps(nextProps) {
     if (nextProps.show && nextProps.defaultData) {
-      this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
+      this.setState({ data: Object.assign({}, nextProps.defaultData) });
     }
   }
 
@@ -1475,7 +1483,7 @@ export class QuestionNoteModal extends Component {
 
   componentWillReceiveProps(nextProps) {
     if (nextProps.show && nextProps.defaultData) {
-      this.setState({ data: Object.assign({}, nextProps.defaultData, this.state.data) });
+      this.setState({ data: Object.assign({}, nextProps.defaultData) });
     }
   }
 

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

@@ -392,7 +392,7 @@ export class PayKBankModal extends Component {
           汇款成功后,请添加微信号XXX或扫描二维码联系小助手,进行核实。
         </div>
         <div className="p-a" style={{ right: 0, top: 50 }}>
-          <Assets name="qrcode" />
+          <Assets name={QrCode} width={150} height={150} />
         </div>
       </Modal>
     );

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

@@ -21,6 +21,7 @@ import { User } from '../../../stores/user';
 import { Order } from '../../../stores/order';
 import { Question } from '../../../stores/question';
 import { My } from '../../../stores/my';
+import { QrCode } from '../../../../Constant';
 
 export default class extends Page {
   initState() {
@@ -648,7 +649,7 @@ export default class extends Page {
     return (
       <div className="tab-layout">
         <div className="qr-layout">
-          <Assets name="qrcode" className="m-r-2 v-a-t" />
+          <Assets name={QrCode} className="m-r-2 v-a-t" />
           <div className="p-l-1 d-i-b t-l">
             <div className="t-1">千行小助手:</div>
             <div className="t-1 m-b-2">1232104-310431</div>

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

@@ -667,7 +667,7 @@ export default class extends Page {
               },
             ]}
             data={list}
-            columns={this.qxCatColumns}
+            columns={this.qxCat ? this.qxCatColumns : (this.cat ? this.catColumns : this.columns)}
           />
         </div>
 

+ 1 - 0
front/project/www/routes/examination/main/page.js

@@ -317,6 +317,7 @@ export default class extends Page {
                 title={struct.title}
                 data={struct}
                 onOpen={() => {
+                  struct.unUseRecord.title = struct.title;
                   this.setState({ record: struct.unUseRecord });
                 }}
               />;

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

@@ -116,7 +116,7 @@ function barOption1(avgTotal, avgCorrect, avgIncorrent) {
     yAxis: {
       show: false,
       min: 0,
-      max: 100,
+      max: 300,
       axisTick: { show: false },
       axisLine: { show: false },
       splitLine: { show: false },
@@ -187,7 +187,7 @@ function barOption2(title, subTitle, data) {
     yAxis: {
       type: 'value',
       min: 0,
-      max: 100,
+      max: 300,
       axisLabel: { color: '#686872' },
       axisLine: { lineStyle: { color: '#D1D6DF' } },
     },

+ 5 - 5
front/project/www/routes/my/main/page.js

@@ -88,10 +88,10 @@ class LogItem extends Component {
               size="small"
               columns={[
                 { key: '', title: '', render: () => '得分/排名' },
-                { key: 'total', title: 'Total', render: (text, record) => `${record.totalScore}/${record.totalRank}th` },
-                { key: 'ir', title: 'IR', render: (text, record) => `${record.irScore}/${record.irRank}th` },
-                { key: '4', title: 'Verbal', render: (text, record) => `${record.verbalScore}/${record.verbalRank}th` },
-                { key: '5', title: 'Quant', render: (text, record) => `${record.quantScore}/${record.quantRank}th` },
+                { key: 'total', title: 'Total', render: (text, record) => `${record.totalScore || 0}/${record.totalRank || 0}th` },
+                { key: 'ir', title: 'IR', render: (text, record) => `${record.irScore || 0}/${record.irRank || 0}th` },
+                { key: '4', title: 'Verbal', render: (text, record) => `${record.verbalScore || 0}/${record.verbalRank || 0}th` },
+                { key: '5', title: 'Quant', render: (text, record) => `${record.quantScore || 0}/${record.quantRank || 0}th` },
               ]}
               data={[row.score]}
             />];
@@ -334,7 +334,7 @@ export default class extends Page {
           return {
             title: row.title,
             time: formatDate(row.report.createTime, 'YYYY-MM-DD HH:mm:ss'),
-            score: row.report.score,
+            score: row.report.score || {},
           };
         }),
       });

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

@@ -148,7 +148,7 @@ export default class extends Page {
     });
     Question.getExaminationInfo().then(result => {
       result.expireDay =
-        result.expireTime && parseInt((new Date().getTime() - new Date(result.expireTime).getTime()) / 86400000, 10);
+        result.expireTime && parseInt((new Date(result.expireTime).getTime() - new Date().getTime()) / 86400000, 10);
       this.setState({ data: result });
     });
   }

+ 15 - 9
front/project/www/routes/paper/process/base/index.js

@@ -168,6 +168,11 @@ export default class extends Component {
     }
   }
 
+  stage() {
+    const { flow } = this.props;
+    flow.next();
+  }
+
   render() {
     const { modal } = this.state;
     const { scene, paper } = this.props;
@@ -240,7 +245,7 @@ export default class extends Component {
   }
 
   renderDetail() {
-    const { paper, userQuestion, question = { content: {} }, singleTime, stageTime, flow } = this.props;
+    const { paper, userQuestion, question = { content: {} }, totalTime, stageTime, totalNumber, flow } = this.props;
     if (!userQuestion.id) return null;
     const { showCalculator, showTime, showNo } = this.state;
     const { typeset = 'one' } = question.content;
@@ -274,7 +279,7 @@ export default class extends Component {
             >
               <Assets name="timeleft_icon" />
               {showTime && stageTime && `Time left ${formatMinuteSecond(stageTime)}`}
-              {showTime && !stageTime && singleTime && `Time cost ${formatMinuteSecond(singleTime)}`}
+              {showTime && !stageTime && totalTime && `Time cost ${formatMinuteSecond(totalTime)}`}
             </div>
             <div
               className="block"
@@ -283,7 +288,7 @@ export default class extends Component {
               }}
             >
               <Assets name="subjectnumber_icon" />
-              {showNo && `${userQuestion.no} of ${paper.questionNumber}`}
+              {showNo && `${userQuestion.no} of ${totalNumber}`}
             </div>
           </div>
         </div>
@@ -313,7 +318,8 @@ export default class extends Component {
   renderExaminationStart() {
     // const { paper, userQuestion, singleTime, stageTime, flow } = this.props;
     const { showTime } = this.state;
-    const { paper, flow, startTime } = this.props;
+    const { paper, flow, startTime, setting } = this.props;
+    const { disorder, order } = setting;
     return (
       <div className="layout">
         <div className="fixed" />
@@ -349,7 +355,7 @@ export default class extends Component {
           <div className="full">
             <Assets name="fullscreen_icon" onClick={() => flow.toggleFullscreen()} />
           </div>
-          <div className="next" onClick={() => this.next()}>
+          <div className="next" onClick={() => flow.start({ disorder: paper.finishTimes > 0 ? !disorder : false, order: order.filter(row => row) })}>
             Next
             <Assets name="next_icon" />
           </div>
@@ -398,7 +404,7 @@ export default class extends Component {
 
   renderExaminationStartCAT() {
     const { paper, flow, setting } = this.props;
-    const { disorder, order, orderIndex } = setting;
+    const { disorder, order = [], orderIndex } = setting;
     return (
       <div className="exercise-start default">
         <div className="title">Section Ordering</div>
@@ -435,7 +441,7 @@ export default class extends Component {
           </div>}
           <div className="text">
             Click{' '}
-            <div className="next" onClick={() => flow.start({ disorder: paper.finishTimes > 0 ? !disorder : false, order })}>
+            <div className="next" onClick={() => flow.start({ disorder: paper.finishTimes > 0 ? !disorder : false, order: order.filter(row => row) })}>
               Next
               <Assets name="next_icon" />
             </div>{' '}
@@ -461,7 +467,7 @@ export default class extends Component {
                 {orderIndex === index && <AntDIcon type="check" style={{ color: '#fff' }} />}
                 {row.list.map((r, i) => {
                   return <div className="block-text" onClick={() => {
-                    if (order.indexOf(r.value) > 0) {
+                    if (order.indexOf(r.value) >= 0) {
                       // 取消
                       order[i] = '';
                     } else {
@@ -540,7 +546,7 @@ export default class extends Component {
           <div className="full">
             <Assets name="fullscreen_icon" onClick={() => flow.toggleFullscreen()} />
           </div>
-          <div className="next" onClick={() => this.next()}>
+          <div className="next" onClick={() => this.stage()}>
             Next
             <Assets name="next_icon" />
           </div>

+ 42 - 11
front/project/www/routes/paper/process/page.js

@@ -15,6 +15,9 @@ export default class extends Page {
     this.singleTime = null;
     this.singleInterval = null;
 
+    this.totalTime = null;
+    this.totalInterval = null;
+
     this.stages = {};
     this.stage = '';
     this.stageInterval = null;
@@ -46,14 +49,16 @@ export default class extends Page {
     // type 是获取基础paper的表信息
     // 等同于PaperOrigin
     Question.getPaper(type, id).then(paper => {
-      this.setState({ paper });
+      let totalNumber = paper.questionNumber;
       let handler = null;
       if (paper.paperModule === 'examination') {
         // 模考获取配置信息
         handler = Main.getExaminationNumber().then(result => {
+          totalNumber = 0;
           Object.keys(result).forEach(key => {
             result[key].time = Number(result[key].time);
             result[key].number = Number(result[key].number);
+            totalNumber += result[key].number;
           });
           this.stages = result;
           this.relaxProcess = { time: 8 * 60 };
@@ -61,6 +66,7 @@ export default class extends Page {
       } else {
         handler = Promise.resolve();
       }
+      this.setState({ paper, totalNumber });
       const { r } = this.state.search;
       if (r) {
         handler.then(() => {
@@ -101,6 +107,7 @@ export default class extends Page {
         const { order } = setting;
         this.initStage(order[0], 0, 0);
       }
+      this.totalQuestionTime();
       return this.next();
     });
   }
@@ -117,6 +124,7 @@ export default class extends Page {
           const { stage, time, number } = report.setting;
           this.initStage(stage, time[stage], number[stage]);
         }
+        this.totalQuestionTime(report.userTime || 0);
         return this.next();
       })
       .catch(() => {
@@ -128,8 +136,21 @@ export default class extends Page {
     const { report, scene } = this.state;
     const { setting = {} } = report;
     if (scene === 'relax') {
+      // 进入下一阶段
       this.nextStage();
     }
+    // 更新模考做题进度
+    if (report.paperModule === 'examination') {
+      this.stageNumber += 1;
+      if (this.stageNumber >= this.stageProcess.number) {
+        const { order } = report.setting;
+        // 进入休息
+        if (order.indexOf(this.stage) < order.length - 1) {
+          this.relaxStage();
+          return Promise.resolve();
+        }
+      }
+    }
     return Question.next(report.id)
       .then(userQuestion => {
         const questionSetting = {};
@@ -180,14 +201,6 @@ export default class extends Page {
     }
     return Question.submit(userQuestion.id, answer, singleTime, questionSetting).then(() => {
       this.singleQuestionTime(true);
-      // 更新模考做题进度
-      if (report.paperModule === 'examination') {
-        this.stageNumber += 1;
-        if (this.stageNumber >= this.stageProcess.number) {
-          // 进入休息
-          this.relaxStage();
-        }
-      }
     });
   }
 
@@ -215,7 +228,6 @@ export default class extends Page {
       });
   }
 
-  // todo initTime
   singleQuestionTime(stop) {
     if (this.singleInterval) {
       clearInterval(this.singleInterval);
@@ -230,6 +242,22 @@ export default class extends Page {
     }
   }
 
+  totalQuestionTime(initTime, stop) {
+    if (initTime) {
+      this.totalTime = initTime;
+    }
+    if (this.totalInterval) {
+      clearInterval(this.totalInterval);
+      this.totalInterval = null;
+    }
+    if (!stop) {
+      this.totalInterval = setInterval(() => {
+        this.totalTime += 1;
+        this.setState({ totalTime: this.totalTime });
+      }, 1000);
+    }
+  }
+
   stageQuestionTime(initTime, stop) {
     if (this.stageInterval) {
       clearInterval(this.stageInterval);
@@ -250,7 +278,7 @@ export default class extends Page {
             this.stage();
           }
         }
-        this.setState({ stageTime: this.targetProcess.time - this.stageTime });
+        this.setState({ stageTime: this.stageProcess.time - this.stageTime });
       }, 1000);
     }
   }
@@ -284,6 +312,7 @@ export default class extends Page {
     this.stageProcess = this.stages[this.stage];
     this.stageNumber = 0;
     this.stageQuestionTime(0);
+    this.setState({ totalNumber: this.stageProcess.number });
   }
 
   relaxStage() {
@@ -293,6 +322,7 @@ export default class extends Page {
     this.setState({
       scene: 'relax',
     });
+    return true;
   }
 
   initStage(stage, time, number) {
@@ -301,6 +331,7 @@ export default class extends Page {
     this.stageTime = time;
     this.stageNumber = number;
     this.stageQuestionTime(time);
+    this.setState({ totalNumber: this.stageProcess.number });
   }
 
   toggleFullscreen() {

+ 4 - 4
front/project/www/routes/paper/question/detail/index.js

@@ -19,7 +19,7 @@ import AnswerTable from '../../../../components/AnswerTable';
 import OtherAnswer from '../../../../components/OtherAnswer';
 import { Textarea } from '../../../../components/Input';
 import { QuestionNoteModal } from '../../../../components/OtherModal';
-import { AskTarget } from '../../../../../Constant';
+import { AskTarget, QrCode } from '../../../../../Constant';
 import { Question } from '../../../../stores/question';
 import { My } from '../../../../stores/my';
 import { User } from '../../../../stores/user';
@@ -738,7 +738,7 @@ export default class extends Component {
               </div>
             </div>
             <div className="right">
-              <Assets name="qrcode" />
+              <Assets name={QrCode} width={150} height={150} />
               <div className="text">扫码关注公众号</div>
               <div className="text">千行GMAT</div>
             </div>
@@ -772,7 +772,7 @@ export default class extends Component {
               <Link to="/">了解更多></Link>
             </div>
             <div className="right">
-              <Assets name="qrcode" />
+              <Assets name={QrCode} width={150} height={150} />
               <div className="text">扫码关注公众号</div>
               <div className="text">千行GMAT</div>
             </div>
@@ -880,7 +880,7 @@ export default class extends Component {
               <div className="text">您也可以关注公众号及时获取结果。</div>
             </div>
             <div className="right">
-              <Assets name="qrcode" />
+              <Assets name={QrCode} width={150} height={150} />
               <div className="text">扫码关注公众号</div>
               <div className="text">千行GMAT</div>
             </div>

+ 74 - 66
front/project/www/routes/paper/report/page.js

@@ -153,7 +153,7 @@ function BarOption2(title, data, legend, color) {
     yAxis: {
       type: 'value',
       min: 0,
-      max: 100,
+      max: 300,
       axisLabel: { color: '#686872' },
       axisLine: { lineStyle: { color: '#D1D6DF' } },
     },
@@ -195,7 +195,7 @@ function lineOption1(title, data, legend, color) {
     yAxis: {
       type: 'value',
       min: 0,
-      max: 100,
+      max: 300,
       axisLabel: { color: '#686872' },
       axisLine: { lineStyle: { color: '#D1D6DF' } },
     },
@@ -252,7 +252,7 @@ function barOption1(title, value, allValue, avgCorrect, avgIncorrent) {
       gridIndex: 0,
       show: false,
       min: 0,
-      max: 100,
+      max: 300,
       axisTick: { show: false },
       axisLine: { show: false },
       splitLine: { show: false },
@@ -261,7 +261,7 @@ function barOption1(title, value, allValue, avgCorrect, avgIncorrent) {
       gridIndex: 1,
       show: false,
       min: 0,
-      max: 100,
+      max: 300,
       axisTick: { show: false },
       axisLine: { show: false },
       splitLine: { show: false },
@@ -270,7 +270,7 @@ function barOption1(title, value, allValue, avgCorrect, avgIncorrent) {
   // const yAxis2 = {
   //   show: false,
   //   min: 0,
-  //   max: 100,
+  //   max: 300,
   //   axisTick: { show: false },
   //   axisLine: { show: false },
   //   splitLine: { show: false },
@@ -1146,6 +1146,16 @@ export default class extends Page {
     const { detail = {} } = report;
     const { subject = {} } = detail;
     const subjectDetail = tab === 'main' ? null : (subject || {})[tab] || { info: {}, defficlt: [], place: [], pace: [] };
+    const tabs = [{ key: 'main', name: '总览 Overview' }];
+    if (subject.verbal) {
+      tabs.push({ key: 'verbal', name: '语文 Verbal' });
+    }
+    if (subject.quant) {
+      tabs.push({ key: 'quant', name: '数学 Quant' });
+    }
+    if (subject.ir) {
+      tabs.push({ key: 'ir', name: '综合推理 IR' });
+    }
     return <div>
       <div className="body">
         <div className="content">
@@ -1154,12 +1164,7 @@ export default class extends Page {
             theme="gray"
             active={tab}
             space={7}
-            tabs={[
-              { key: 'main', name: '总览 Overview' },
-              { key: 'verbal', name: '语文 Verbal' },
-              { key: 'quant', name: '数学 Quant' },
-              { key: 'ir', name: '综合推理 IR' },
-            ]}
+            tabs={tabs}
             onChange={(value) => {
               this.setState({ tab: value });
             }}
@@ -1169,75 +1174,75 @@ export default class extends Page {
             <div className="detail">
               <div className="block">
                 <div className="t1" />
-                <div className="t4">Verbal</div>
-                <div className="t4">Quant</div>
-                <div className="t4">IR</div>
+                {subject.verbal && <div className="t4">Verbal</div>}
+                {subject.quant && <div className="t4">Quant</div>}
+                {subject.ir && <div className="t4">IR</div>}
               </div>
               <div className="block">
                 <div className="t1">总耗时</div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.verbal || {}).userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.quant || {}).userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.ir || {}).userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
+                {subject.verbal && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.verbal.info.userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
+                {subject.quant && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.quant.info.userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
+                {subject.ir && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.ir.info.userTime).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
               </div>
               <div className="block">
                 <div className="t1">超出建议用时</div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.verbal || {}).userTime - (subject.verbal || {}).time).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.quant || {}).userTime - (subject.quant || {}).time).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
-                <div className="t1">
-                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds((subject.ir || {}).userTime - (subject.ir || {}).time).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
-                </div>
+                {subject.verbal && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.verbal.info.userTime > subject.verbal.info.time ? subject.verbal.info.userTime - subject.verbal.info.time : 0).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
+                {subject.quant && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.quant.info.userTime > subject.quant.info.time ? subject.quant.info.userTime - subject.quant.info.time : 0).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
+                {subject.ir && <div className="t1">
+                  <div className="t2" dangerouslySetInnerHTML={{ __html: formatSeconds(subject.ir.info.userTime > subject.ir.info.time ? subject.ir.info.userTime - subject.ir.info.time : 0).replace(/([0-9]+)(min|m|hour|h|s)/g, '$1<div class="t3">$2</div>') }} />
+                </div>}
               </div>
               <div className="block">
                 <div className="t1" />
-                <div className="t1">
+                {subject.verbal && <div className="t1">
                   <div className="line" />
-                </div>
-                <div className="t1">
+                </div>}
+                {subject.quant && <div className="t1">
                   <div className="line" />
-                </div>
-                <div className="t1">
+                </div>}
+                {subject.ir && <div className="t1">
                   <div className="line" />
-                </div>
+                </div>}
               </div>
               <div className="block">
                 <div className="t1">完成题目</div>
-                <div className="t1">
-                  <div className="t2">{(subject.verbal || {}).userNumber}</div>
+                {subject.verbal && <div className="t1">
+                  <div className="t2">{subject.verbal.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
-                <div className="t1">
-                  <div className="t2">{(subject.quant || {}).userNumber}</div>
+                </div>}
+                {subject.quant && <div className="t1">
+                  <div className="t2">{subject.quant.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
-                <div className="t1">
-                  <div className="t2">{(subject.ir || {}).userNumber}</div>
+                </div>}
+                {subject.ir && <div className="t1">
+                  <div className="t2">{subject.ir.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
+                </div>}
               </div>
               <div className="block">
                 <div className="t1">剩余未做</div>
-                <div className="t1">
-                  <div className="t2">{(subject.verbal || {}).questionNumber - (subject.verbal || {}).userNumber}</div>
+                {subject.verbal && <div className="t1">
+                  <div className="t2">{subject.verbal.info.questionNumber - subject.verbal.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
-                <div className="t1">
-                  <div className="t2">{(subject.quant || {}).questionNumber - (subject.quant || {}).userNumber}</div>
+                </div>}
+                {subject.quant && <div className="t1">
+                  <div className="t2">{subject.quant.info.questionNumber - subject.quant.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
-                <div className="t1">
-                  <div className="t2">{(subject.ir || {}).questionNumber - (subject.ir || {}).userNumber}</div>
+                </div>}
+                {subject.ir && <div className="t1">
+                  <div className="t2">{subject.ir.info.questionNumber - subject.ir.info.userNumber}</div>
                   <div className="t3">题</div>
-                </div>
+                </div>}
               </div>
             </div></div>}
           {subjectDetail && <div>
@@ -1267,7 +1272,7 @@ export default class extends Page {
                 (function (sd) {
                   let userTime = 0;
                   let time = 0;
-                  sd.pace.map(row => {
+                  return sd.pace.map(row => {
                     userTime += row.userTime;
                     time += row.time;
                     return [`${row.no}`, userTime, time];
@@ -1318,9 +1323,10 @@ export default class extends Page {
             <tbody>
               {ExaminationQuestionType.map(row => {
                 const typeDetail = detail.type[row.value];
+                if (!typeDetail) return null;
                 return <tr>
                   <td>{row.long}</td>
-                  <td>{typeDetail.info.questionNumber}</td>
+                  <td>{typeDetail.info.userNumber}</td>
                   <td>{typeDetail.info.userCorrect}</td>
                   <td>
                     {formatPercent(typeDetail.info.userCorrect, typeDetail.info.userNumber)}
@@ -1332,7 +1338,7 @@ export default class extends Page {
                     {formatSecond(typeDetail.info.correctTime / typeDetail.info.userCorrect)}
                   </td>
                   <td>
-                    {formatSecond(typeDetail.info.incorrectTime / typeDetail.info.userNumber - typeDetail.info.userCorrect)}
+                    {formatSecond(typeDetail.info.incorrectTime / (typeDetail.info.userNumber - typeDetail.info.userCorrect))}
                   </td>
                   <td>{typeDetail.info.avgDiffCorrect}</td>
                   <td>{typeDetail.info.avgDiffIncorrect}</td>
@@ -1408,7 +1414,7 @@ export default class extends Page {
             height={400}
             option={BarOption2(
               '正确率',
-              subjectDetail.difficult.map(row => {
+              Object.values(subjectDetail.difficult).map(row => {
                 return [QuestionDifficultMap[row.key], formatPercent(row.userCorrect, row.userNumber)];
               }),
               ['我的'],
@@ -1424,13 +1430,13 @@ export default class extends Page {
             height={400}
             option={BarOption3(
               ['知识点', '正确率分析', '用时分析'],
-              subjectDetail.place.map(row => {
+              Object.values(subjectDetail.place).map(row => {
                 return row.key;
               }),
-              subjectDetail.place.map(row => {
+              Object.values(subjectDetail.place).map(row => {
                 return [row.userCorrect, row.userNumber];
               }),
-              subjectDetail.place.map(row => {
+              Object.values(subjectDetail.place).map(row => {
                 return row.userTime / row.userNumber;
               }),
               ['#92AFD2', '#BFD4EE'],
@@ -1444,7 +1450,8 @@ export default class extends Page {
 
   renderExaminationScore() {
     const { report = {} } = this.state;
-    const { score } = report;
+    const { score, detail } = report;
+    const { subject } = detail;
     return <div className="body">
       <div className="content">
         <div className="title">成绩单</div>
@@ -1459,13 +1466,14 @@ export default class extends Page {
           </thead>
           <tbody>
             {ExaminationSubject.map(row => {
+              if (!subject[row.value]) return null;
               return <tr>
                 <td>{row.long}</td>
                 <td>{row.ignore ? '--' : score[`${row.value}Score`]}</td>
                 <td>{row.ignore ? '--' : score[`${row.value}Rank`]}</td>
                 <td><Button size="small" radius onClick={() => {
                   Question.getDetailByNo(report.id, 1, row.value).then((r) => {
-                    linkTo(`/paper/question/${r.id}`);
+                    openLink(`/paper/question/${r.id}`);
                   });
                 }}>回顾</Button></td></tr>;
             })}
@@ -1477,7 +1485,7 @@ export default class extends Page {
                 Question.getDetailByNo(report.id, 1).then((r) => {
                   linkTo(`/paper/question/${r.id}`);
                 });
-              }}>回顾</Button></td></tr>;
+              }}>回顾</Button></td></tr>
           </tbody>
         </table>
       </div>

+ 5 - 7
front/project/www/stores/user.js

@@ -91,13 +91,11 @@ export default class UserStore extends BaseStore {
   initAfter() {
     if (this.adminLogin || this.state.login) {
       this.refreshToken().then(() => {
-        if (this.adminLogin) {
-          window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
-        }
-      }).catch(() => {
-        if (this.adminLogin) {
-          window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
-        }
+        // if (this.adminLogin) {
+        //   window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
+        // }
+      }).catch((e) => {
+        console.log(e);
       });
     }
   }

+ 5 - 0
server/data/src/main/java/com/qxgmat/data/relation/UserQuestionRelationMapper.java

@@ -2,6 +2,7 @@ package com.qxgmat.data.relation;
 
 import com.qxgmat.data.dao.entity.UserQuestion;
 import com.qxgmat.data.relation.entity.UserRecordStatRelation;
+import com.qxgmat.data.relation.entity.UserReportLimitRelation;
 import org.apache.ibatis.annotations.Param;
 
 import java.util.Collection;
@@ -50,4 +51,8 @@ public interface UserQuestionRelationMapper {
             @Param("startTime") Date startTime,
             @Param("endTime") Date endTime
     );
+
+    List<UserReportLimitRelation> statLimit(
+            @Param("reportId") Integer reportId
+    );
 }

+ 0 - 5
server/data/src/main/java/com/qxgmat/data/relation/UserReportRelationMapper.java

@@ -36,11 +36,6 @@ public interface UserReportRelationMapper {
             @Param("paperIds") Collection paperIds
     );
 
-    List<UserReportLimitRelation> statLimit(
-            @Param("paperOrigin") String paperOrigin,
-            @Param("originId") Integer originId
-    );
-
     List<UserStudyStatRelation> statGroupOrigin(
             @Param("userId") Integer userId
     );

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

@@ -47,7 +47,7 @@
     left join `user_paper` up on ep.`id` = up.`origin_id`
       and up.`paper_origin` = 'examination'
       and up.`user_id` = #{userId,jdbcType=VARCHAR}
-      <if test="qxCatNo != null">
+      <if test="qxCat != null">
         and up.`qx_cat` = #{qxCat,jdbcType=VARCHAR}
       </if>
       <if test="times != null">

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

@@ -162,13 +162,13 @@
     <if test="structId != null">
       and find_in_set(#{structId,jdbcType=VARCHAR}, qn.`module_struct`)
     </if>
-    <if test="targetTypes != null">
+    <if test="targetTypes != null and targetTypes.size() > 0">
       and q.`question_type` IN
       <foreach collection="targetTypes" item="item" index="index" open="(" separator="," close=")">
         #{item}
       </foreach>
     </if>
-    <if test="filterIds != null">
+    <if test="filterIds != null and filterIds.size()>0">
       and qn.`id` NOT IN
       <foreach collection="filterIds" item="item" index="index" open="(" separator="," close=")">
         #{item}

+ 20 - 0
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserQuestionRelationMapper.xml

@@ -13,6 +13,13 @@
     -->
     <id column="user_time" jdbcType="INTEGER" property="userTime" />
   </resultMap>
+  <resultMap id="limitMap" type="com.qxgmat.data.relation.entity.UserReportLimitRelation">
+    <!--
+      WARNING - @mbg.generated
+    -->
+    <id column="user_number" jdbcType="INTEGER" property="userNumber" />
+    <id column="user_correct" jdbcType="INTEGER" property="userCorrect" />
+  </resultMap>
   <sql id="Id_Column_List">
     <!--
       WARNING - @mbg.generated
@@ -201,4 +208,17 @@
       and uq.`create_time` &lt; #{endTime,jdbcType=TIMESTAMP}
     </if>
   </select>
+
+  <!--
+    用户限时完成的统计记录
+  -->
+  <select id="statLimit" resultMap="limitMap">
+    select
+    sum(`user_number`) as `user_number`, sum(`user_correct`) as `user_correct`
+    from `user_question`
+    where
+    `user_time` &lt; `time`
+    and `user_number` = `question_number`
+    and `report_id` = #{reportId,jdbcType=INTEGER}
+  </select>
 </mapper>

+ 0 - 21
server/data/src/main/java/com/qxgmat/data/relation/mapping/UserReportRelationMapper.xml

@@ -7,13 +7,6 @@
     -->
     <id column="id" jdbcType="INTEGER" property="id" />
   </resultMap>
-  <resultMap id="limitMap" type="com.qxgmat.data.relation.entity.UserReportLimitRelation">
-    <!--
-      WARNING - @mbg.generated
-    -->
-    <id column="user_number" jdbcType="INTEGER" property="userNumber" />
-    <id column="user_correct" jdbcType="INTEGER" property="userCorrect" />
-  </resultMap>
   <resultMap id="studyMap" type="com.qxgmat.data.relation.entity.UserStudyStatRelation">
     <!--
       WARNING - @mbg.generated
@@ -124,20 +117,6 @@
   </select>
 
   <!--
-    用户限时完成的统计记录
-  -->
-  <select id="statLimit" resultMap="limitMap">
-    select
-      sum(`user_number`) as `user_number`, sum(`user_correct`) as `user_correct`
-    from `user_report`
-    where
-      `user_time` &lt; `time`
-    and `user_number` = `question_number`
-    and `paper_origin` = #{paperOrigin,jdbcType=VARCHAR}
-    and `origin_id` = #{originId,jdbcType=INTEGER}
-  </select>
-
-  <!--
     用户不同来源记录统计
   -->
   <select id="statGroupOrigin" resultMap="studyMap">

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

@@ -1043,8 +1043,14 @@ public class UserController {
 
         if (dto.getIsAlert() != null && dto.getIsAlert() > 0){
             User user = usersService.get(in.getUserId());
-            usersService.edit(User.builder().id(user.getId()).totalAlert(user.getTotalAlert() + 1).build());
+            User tmp = User.builder().id(user.getId()).totalAlert(user.getTotalAlert() + 1).build();
+            if (tmp.getTotalAlert() ==3){
+                // 自动禁用用户
+                tmp.setIsFrozen(1);
+            }
+            usersService.edit(tmp);
             messageExtendService.sendLoginAbnormal(user, in);
+
         }
 
         entity = userAbnormalService.edit(entity);

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

@@ -544,7 +544,7 @@ public class QuestionController {
             // 获取最后一次结果
             Collection paperIds = Transform.getIds(paperList, UserPaper.class, "id");
             List<UserReport> reportList = userReportService.listWithLast(paperIds);
-            Transform.combine(pr, reportList, UserExaminationPaperDto.class, "id", "report", UserReport.class, "paperId", UserReportExtendDto.class);
+            Transform.combine(pr, reportList, UserExaminationPaperDto.class, "id", "report", UserReport.class, "originId", UserReportExtendDto.class);
 
             if (serviceKey == ServiceKey.QX_CAT && user.getQxCat() > 0){
                 // 获取上一遍模考成绩

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

@@ -17,6 +17,8 @@ public class UserExtendDto {
 
     private Integer totalMoney;
 
+    private Integer totalAlert;
+
     private String registerIp;
 
     private String registerCity;
@@ -96,4 +98,12 @@ public class UserExtendDto {
     public void setCreateTime(Date createTime) {
         this.createTime = createTime;
     }
+
+    public Integer getTotalAlert() {
+        return totalAlert;
+    }
+
+    public void setTotalAlert(Integer totalAlert) {
+        this.totalAlert = totalAlert;
+    }
 }

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

@@ -30,6 +30,8 @@ public class UserReportExtendDto {
 
     private Integer isFinish;
 
+    private Date createTime;
+
     private Date updateTime;
 
     private JSONObject setting;
@@ -149,4 +151,12 @@ public class UserReportExtendDto {
     public void setTimes(Integer times) {
         this.times = times;
     }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
 }

+ 21 - 0
server/gateway-api/src/main/java/com/qxgmat/service/UserQuestionService.java

@@ -17,6 +17,7 @@ import com.qxgmat.data.dao.entity.UserReport;
 import com.qxgmat.data.inline.UserQuestionStat;
 import com.qxgmat.data.relation.UserQuestionRelationMapper;
 import com.qxgmat.data.relation.entity.UserRecordStatRelation;
+import com.qxgmat.data.relation.entity.UserReportLimitRelation;
 import com.qxgmat.service.annotation.InitQuestion;
 import com.qxgmat.service.inline.QuestionNoService;
 import com.qxgmat.service.inline.SentenceQuestionService;
@@ -166,6 +167,9 @@ public class UserQuestionService extends AbstractService {
         Map<Object, UserQuestionStat> relationMap = new HashMap<>();
         Map<Integer, List<UserQuestion>> map = new HashMap<>();
         for (UserQuestion userQuestion: userQuestionList){
+            if (userQuestion.getUserTime()<=0){
+                continue;
+            }
             if (!map.containsKey(userQuestion.getQuestionId())){
                 map.put(userQuestion.getQuestionId(), new ArrayList<>());
             }
@@ -188,6 +192,9 @@ public class UserQuestionService extends AbstractService {
         Map<Object, UserQuestionStat> relationMap = new HashMap<>();
         Map<Integer, List<UserQuestion>> map = new HashMap<>();
         for (UserQuestion userQuestion: userQuestionList){
+            if (userQuestion.getUserTime()<=0){
+                continue;
+            }
             if (!map.containsKey(userQuestion.getQuestionNoId())){
                 map.put(userQuestion.getQuestionNoId(), new ArrayList<>());
             }
@@ -332,6 +339,20 @@ public class UserQuestionService extends AbstractService {
         return null;
     }
 
+    /**
+     * 按report统计在限定时间内的做题结果
+     * @param reportId
+     * @return
+     */
+    public UserReportLimitRelation statLimit(Integer reportId){
+        List<UserReportLimitRelation> relations =  userQuestionRelationMapper.statLimit(reportId);
+        if (relations.size() > 0 && relations.get(0) != null){
+            return relations.get(0);
+        }else{
+            return new UserReportLimitRelation();
+        }
+    }
+
     public UserQuestion add(UserQuestion question){
         int result = insert(userQuestionMapper, question);
         question = one(userQuestionMapper, question.getId());

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

@@ -373,7 +373,7 @@ public class ExaminationService extends AbstractService {
                     target = quantDS;
                     break;
             }
-            if (target == 0 || target > typeNumber.get(type)){
+            if (target == 0 || typeNumber.get(type) == null || target > typeNumber.get(type)){
                 targetTypes.add(type);
             }
         }

+ 60 - 52
server/gateway-api/src/main/java/com/qxgmat/service/extend/QuestionFlowService.java

@@ -577,12 +577,12 @@ public class QuestionFlowService {
         if (!userReport.getUserId().equals(userId)){
             throw new ParameterException("试卷不存在");
         }
-        if (userReport.getDetail() != null && userReport.getFinishTime() != null){
-            throw new ParameterException("做题结束");
-        }
-        if (userReport.getUserNumber()>=userReport.getQuestionNumber()){
-            throw new ParameterException("答题结束,请提交完成");
-        }
+//        if (userReport.getDetail() != null && userReport.getFinishTime() != null){
+//            throw new ParameterException("做题结束");
+//        }
+//        if (userReport.getUserNumber()>=userReport.getQuestionNumber()){
+//            throw new ParameterException("答题结束,请提交完成");
+//        }
 
         return relationReport(userReport);
     }
@@ -881,7 +881,7 @@ public class QuestionFlowService {
         String stage = setting.getString("stage");
         JSONObject time = setting.getJSONObject("time");
         JSONObject number = setting.getJSONObject("number");
-        time.put(stage, time.getIntValue(stage)+ lastQuestion.getUserTime());
+        time.put(stage, time.getIntValue(stage)+ (lastQuestion !=null ?lastQuestion.getUserTime():0));
         Integer totalNumber = toolsService.examinationSubjectNumber(stage);
         // 判断数量是否已经完成
         if (number.getIntValue(stage) >= totalNumber){
@@ -920,7 +920,7 @@ public class QuestionFlowService {
         }else{
             questionNoId = randomCompute(subject, paper, questionTypes, setting, subnumber, ids, userQuestionList);
         }
-        if (questionNoId == 0) {
+        if (questionNoId ==null || questionNoId == 0) {
             throw new ParameterException("模考出题流程错误:题目生成错误");
         }
         QuestionNoRelation relation = questionNoService.getWithRelation(questionNoId);
@@ -928,6 +928,7 @@ public class QuestionFlowService {
         question.setQuestionId(relation.getQuestionId());
         question.setQuestionType(relation.getQuestion().getQuestionType());
         question.setTime(toolsService.computerTime(relation));
+        question.setStage(stage);
         // 更新题目数
         number.put(stage, subnumber + 1);
         return true;
@@ -1065,7 +1066,7 @@ public class QuestionFlowService {
                 }
                 // 判断是否后续阅读题
                 JSONObject rc = setting.getJSONObject("rc");
-                if(rc.getInteger(subnumber.toString()) != null){
+                if(rc != null && rc.getInteger(subnumber.toString()) != null){
                     return rc.getIntValue(subnumber.toString());
                 }
                 break;
@@ -1415,8 +1416,8 @@ public class QuestionFlowService {
 
         JSONObject limit = new JSONObject();
         // 限时统计考试正确度
-        UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId());
-        limit.put("userNumber", relation.getUserNumber());
+        UserReportLimitRelation relation = userQuestionService.statLimit(report.getId());
+        limit.put("userNumber", questionList.size());
         limit.put("userCorrect", relation.getUserCorrect());
         detail.put("limit", limit);
 
@@ -1508,8 +1509,8 @@ public class QuestionFlowService {
 
         JSONObject limit = new JSONObject();
         // 限时统计考试正确度
-        UserReportLimitRelation relation = userReportService.statLimit(report.getPaperOrigin(), report.getOriginId());
-        limit.put("userNumber", relation.getUserNumber());
+        UserReportLimitRelation relation = userQuestionService.statLimit(report.getId());
+        limit.put("userNumber", questionList.size());
         limit.put("userCorrect", relation.getUserCorrect());
         detail.put("limit", limit);
 
@@ -1632,8 +1633,13 @@ public class QuestionFlowService {
      */
     private void statExaminationReport(UserReport report, List<UserQuestion> questionList){
         UserPaper paper = userPaperService.get(report.getPaperId());
-        Collection questionNoIds = Transform.getIds(questionList, UserQuestion.class, "questionNoId");
-        Map<Number, QuestionNoRelation> relationMap = questionNoService.mapWithRelationByIds((Integer[])questionNoIds.toArray());
+        Integer[] tmpIds = new Integer[questionList.size()];
+        int i = 0;
+        for (UserQuestion question: questionList) {
+            tmpIds[i] = question.getQuestionNoId();
+            i++;
+        }
+        Map<Number, QuestionNoRelation> relationMap = questionNoService.mapWithRelationByIds(tmpIds);
 
         // report
         JSONObject detail = new JSONObject();
@@ -1642,7 +1648,6 @@ public class QuestionFlowService {
         // 成绩单
         JSONObject subjectMap = new JSONObject();
         JSONObject typeMap = new JSONObject();
-        JSONObject tempMap = new JSONObject();
         JSONObject difficult = null;
         JSONObject place = null;
         for (UserQuestion userQuestion : questionList){
@@ -1650,35 +1655,15 @@ public class QuestionFlowService {
             QuestionType questionType = QuestionType.ValueOf(relation.getQuestion().getQuestionType());
             QuestionSubject questionSubject = QuestionSubject.FromType(questionType);
             JSONObject type = typeMap.getJSONObject(questionType.key);
-            JSONObject tempType = tempMap.getJSONObject(questionType.key);
             JSONObject subject = subjectMap.getJSONObject(questionSubject.key);
-            JSONObject tempSubject = tempMap.getJSONObject(questionSubject.key);
 
             // 归类
-            if (type == null || type.isEmpty()){
-                type = new JSONObject();
-                type.put("key", questionType.key);
-                subject.put("pace", new JSONArray());
-                JSONObject initTypeInfo = new JSONObject();
-                // 初始化题型基础信息
-                initTypeInfo.put("userNumber", 0);
-                initTypeInfo.put("userTime", 0);
-                initTypeInfo.put("userCorrect", 0);
-                initTypeInfo.put("correctTime", 0);
-                initTypeInfo.put("incorrectTime", 0);
-                initTypeInfo.put("diffCorrect", 0f);
-                initTypeInfo.put("diffIncorrect", 0f);
-                type.put("info", initTypeInfo);
-                typeMap.put(questionType.key, type);
-                tempType = new JSONObject();
-                tempType.put("place", new JSONObject());
-                tempType.put("difficult", new JSONObject());
-                tempMap.put(questionType.key, tempType);
-            }
             if (subject == null || subject.isEmpty()){
                 subject = new JSONObject();
                 subject.put("key", questionSubject.key);
                 subject.put("pace", new JSONArray());
+                subject.put("place", new JSONObject());
+                subject.put("difficult", new JSONObject());
                 JSONObject initSubjectInfo = new JSONObject();
                 JSONObject subjectBase = toolsService.examinationSubjectInit(questionSubject);
                 // 初始化学科基础信息
@@ -1694,18 +1679,32 @@ public class QuestionFlowService {
                 initSubjectInfo.put("difficultScore", 0);
                 subject.put("info", initSubjectInfo);
                 subjectMap.put(questionSubject.key, subject);
-                tempSubject = new JSONObject();
-                tempSubject.put("place", new JSONObject());
-                tempSubject.put("difficult", new JSONObject());
-                tempMap.put(questionSubject.key, tempType);
+            }
+            if (type == null || type.isEmpty()){
+                type = new JSONObject();
+                type.put("key", questionType.key);
+                type.put("pace", new JSONArray());
+                type.put("place", new JSONObject());
+                type.put("difficult", new JSONObject());
+                JSONObject initTypeInfo = new JSONObject();
+                // 初始化题型基础信息
+                initTypeInfo.put("userNumber", 0);
+                initTypeInfo.put("userTime", 0);
+                initTypeInfo.put("userCorrect", 0);
+                initTypeInfo.put("correctTime", 0);
+                initTypeInfo.put("incorrectTime", 0);
+                initTypeInfo.put("diffCorrect", 0f);
+                initTypeInfo.put("diffIncorrect", 0f);
+                type.put("info", initTypeInfo);
+                typeMap.put(questionType.key, type);
             }
             JSONArray paceType = type.getJSONArray("pace");
-            JSONObject placeTypeMap = tempType.getJSONObject("place");
-            JSONObject difficultTypeMap = tempType.getJSONObject("difficult");
+            JSONObject placeTypeMap = type.getJSONObject("place");
+            JSONObject difficultTypeMap = type.getJSONObject("difficult");
             JSONObject typeInfo = type.getJSONObject("info");
             JSONArray paceSubject = subject.getJSONArray("pace");
-            JSONObject placeSubjectMap = tempType.getJSONObject("place");
-            JSONObject difficultSubjectMap = tempType.getJSONObject("difficult");
+            JSONObject placeSubjectMap = subject.getJSONObject("place");
+            JSONObject difficultSubjectMap = subject.getJSONObject("difficult");
             JSONObject subjectInfo = subject.getJSONObject("info");
 
             // 每题用时
@@ -1827,15 +1826,24 @@ public class QuestionFlowService {
         }
 
         // 学科得分计算
+        Integer quantScore = 0;
+        Integer verbalScore = 0;
+        Integer irScore = 0;
         JSONObject quantSubject = subjectMap.getJSONObject(QuestionSubject.QUANT.key);
-        JSONObject quantInfo = quantSubject.getJSONObject("info");
-        Integer quantScore = toolsService.quantScore(quantInfo.getIntValue("number"), quantInfo.getIntValue("userNumber"), quantInfo.getFloatValue("difficultScore"), quantInfo.getInteger("userCorrect"));
+        if (quantSubject != null){
+            JSONObject quantInfo = quantSubject.getJSONObject("info");
+            quantScore = toolsService.quantScore(quantInfo.getIntValue("number"), quantInfo.getIntValue("userNumber"), quantInfo.getFloatValue("difficultScore"), quantInfo.getInteger("userCorrect"));
+        }
         JSONObject verbalSubject = subjectMap.getJSONObject(QuestionSubject.VERBAL.key);
-        JSONObject verbalInfo = verbalSubject.getJSONObject("info");
-        Integer verbalScore = toolsService.verbalScore(verbalInfo.getIntValue("number"), verbalInfo.getIntValue("userNumber"), verbalInfo.getFloatValue("difficultScore"), verbalInfo.getInteger("userCorrect"));
+        if (verbalSubject != null){
+            JSONObject verbalInfo = verbalSubject.getJSONObject("info");
+            verbalScore = toolsService.verbalScore(verbalInfo.getIntValue("number"), verbalInfo.getIntValue("userNumber"), verbalInfo.getFloatValue("difficultScore"), verbalInfo.getInteger("userCorrect"));
+        }
         JSONObject irSubject = subjectMap.getJSONObject(QuestionSubject.IR.key);
-        JSONObject irInfo = irSubject.getJSONObject("info");
-        Integer irScore = toolsService.irScore(irInfo.getIntValue("number"), irInfo.getIntValue("userNumber"), irInfo.getInteger("difficultScore"), irInfo.getInteger("userCorrect"));
+        if (irSubject != null){
+            JSONObject irInfo = irSubject.getJSONObject("info");
+            irScore = toolsService.irScore(irInfo.getIntValue("number"), irInfo.getIntValue("userNumber"), irInfo.getInteger("difficultScore"), irInfo.getInteger("userCorrect"));
+        }
 
         Rank rank = toolsService.totalScore(quantScore, verbalScore);
         score.put("totalScore", rank.getTotalScore());

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

@@ -347,8 +347,13 @@ public class QuestionNoService extends AbstractService {
                         .andGreaterThan("questionId", 0)
                 .andCondition(String.format(formatSet, structId, "module_struct"))
                 .andEqualTo("relationNumber", number)
-                .andNotIn("id", filterIds)
         );
+        if (filterIds != null && filterIds.size() > 0){
+            example.and(
+                    example.createCriteria()
+                            .andNotIn("id", filterIds)
+            );
+        }
         example.and(
                 example.createCriteria()
                         .andIsNull("deleteTime")

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

@@ -103,21 +103,6 @@ public class UserReportService extends AbstractService {
     }
 
     /**
-     * 按report统计在限定时间内的做题结果
-     * @param origin
-     * @param originId
-     * @return
-     */
-    public UserReportLimitRelation statLimit(String origin, Integer originId){
-        List<UserReportLimitRelation> relations =  userReportRelationMapper.statLimit(origin, originId);
-        if (relations.size() > 0 && relations.get(0) != null){
-            return relations.get(0);
-        }else{
-            return new UserReportLimitRelation();
-        }
-    }
-
-    /**
      * 获取指定时间内的模块做题记录
      * @param userId
      * @param paperModule
@@ -204,20 +189,24 @@ public class UserReportService extends AbstractService {
      * @return
      */
     public UserReport newByPaper(UserPaper paper, JSONObject setting){
-        return UserReport.builder()
+        UserReport report = UserReport.builder()
                 .paperModule(paper.getPaperModule())
                 .paperOrigin(paper.getPaperOrigin())
                 .originId(paper.getOriginId())
                 .paperId(paper.getId())
                 .setting(setting)
                 .userId(paper.getUserId())
-                .questionNoIds(paper.getQuestionNoIds())
-                .questionNumber(paper.getQuestionNoIds().length)
                 .time(paper.getTime())
                 .userCorrect(0)
                 .userNumber(0)
                 .userTime(0)
                 .build();
+        if (paper.getQuestionNoIds() !=null){
+            report.setQuestionNoIds(paper.getQuestionNoIds());
+            report.setQuestionNumber(paper.getQuestionNoIds().length);
+        }
+
+        return report;
     }
 
     /**

+ 1 - 1
server/gateway-api/src/main/java/com/qxgmat/task/ScheduledTask.java

@@ -122,7 +122,7 @@ public class ScheduledTask {
     }
 
     // 每小时刷新备考统计信息
-    @Scheduled(cron="*/5 * * * * *")
+    @Scheduled(cron="*/30 * * * * *")
     public void refreshPrepare(){
         logger.info("Start refresh Prepare");
         JSONObject value = new JSONObject();