Sfoglia il codice sorgente

feat(front): 个人中心

Go 5 anni fa
parent
commit
65e49b14c8
29 ha cambiato i file con 592 aggiunte e 290 eliminazioni
  1. 11 2
      front/project/www/components/Date/index.js
  2. 1 1
      front/project/www/components/More/index.js
  3. 103 138
      front/project/www/routes/examination/list/page.js
  4. 4 4
      front/project/www/routes/examination/main/page.js
  5. 1 1
      front/project/www/routes/exercise/list/page.js
  6. 3 4
      front/project/www/routes/exercise/main/page.js
  7. 79 61
      front/project/www/routes/my/course/page.js
  8. 50 13
      front/project/www/routes/my/order/page.js
  9. 4 0
      front/project/www/stores/order.js
  10. 1 1
      front/project/www/stores/user.js
  11. 1 1
      server/data/src/main/java/com/qxgmat/data/relation/mapping/UserOrderRelationMapper.xml
  12. 7 1
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/CourseController.java
  13. 17 4
      server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java
  14. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/CourseController.java
  15. 4 4
      server/gateway-api/src/main/java/com/qxgmat/controller/api/MyController.java
  16. 55 10
      server/gateway-api/src/main/java/com/qxgmat/controller/api/OrderController.java
  17. 1 1
      server/gateway-api/src/main/java/com/qxgmat/controller/api/TextbookController.java
  18. 3 3
      server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserListDto.java
  19. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/extend/CourseExtendDto.java
  20. 47 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/OrderInvoiceDto.java
  21. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/request/UserCourseAppointmentCommentDto.java
  22. 10 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseDetailDto.java
  23. 52 0
      server/gateway-api/src/main/java/com/qxgmat/dto/response/UserOrderDetailDto.java
  24. 27 18
      server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java
  25. 26 21
      server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java
  26. 34 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserInvoiceService.java
  27. 16 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderRecordService.java
  28. 13 0
      server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderService.java
  29. 1 1
      server/gateway-api/src/main/java/com/qxgmat/task/ScheduledTask.java

+ 11 - 2
front/project/www/components/Date/index.js

@@ -31,10 +31,19 @@ export default class extends Component {
   render() {
     const { show, hideInput, disabledDate, theme = '', value, onChange } = this.props;
     return (
-      <div className={`g-date-block ${hideInput ? 'hide-input' : ''}`}>
+      <div
+        ref={ref => {
+          if (!this.ref) {
+            this.ref = ref;
+            this.setState({ load: false });
+          }
+        }}
+        className={`g-date-block ${hideInput ? 'hide-input' : ''}`}
+      >
         <DatePicker
-          open={show}
+          open={show && this.ref}
           value={value}
+          getCalendarContainer={() => this.ref.parentNode}
           dropdownClassName={`g-date ${theme} ${hideInput ? 'hide-input' : ''}`}
           disabledDate={disabledDate}
           dateRender={date => this.dateRender(date)}

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

@@ -9,7 +9,7 @@ function More(props) {
       overlay={
         <Menu onClick={key => onClick && onClick(key)}>
           {menu.map(item => {
-            if (!item.key) return null;
+            if (!item || !item.key) return null;
             return <Menu.Item key={item.key}>{item.label}</Menu.Item>;
           })}
         </Menu>

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

@@ -32,36 +32,17 @@ export default class extends Page {
               <div>
                 <ProgressText progress={progress} size="small" />
               </div>
-              {this.state.showPrev && (
-                <div className="prev">
-                  <div className="night f-s-16">
-                    {record.title}
-                    {record.prevPaper && record.prevPaper.paperNo > 0
-                      ? String.fromCharCode(64 + record.prevPaper.paperNo)
-                      : ''}
-                  </div>
-                </div>
-              )}
             </div>,
-            <div className="table-row" style={{ paddingRight: 40 }}>
-              <div className="night f-s-16">
-                {record.title}
-                {record.paper && record.paper.paperNo > 0 ? String.fromCharCode(64 + record.paper.paperNo) : ''}
-              </div>
-              <div>
-                <ProgressText progress={progress} size="small" />
-              </div>
-              {this.state.showPrev && (
-                <div className="prev">
-                  <div className="night f-s-16">
-                    {record.title}
-                    {record.prevPaper && record.prevPaper.paperNo > 0
-                      ? String.fromCharCode(64 + record.prevPaper.paperNo)
-                      : ''}
-                  </div>
+            this.state.showPrev && record.prevReport && (
+              <div className="table-row prev t-3">
+                <div className="night f-s-16">
+                  {record.title}
+                  {record.prevPaper && record.prevPaper.paperNo > 0
+                    ? String.fromCharCode(64 + record.prevPaper.paperNo)
+                    : ''}
                 </div>
-              )}
-            </div>,
+              </div>
+            ),
           ];
         },
       },
@@ -76,29 +57,15 @@ export default class extends Page {
                 {record.report ? `${record.report.score.totalScore}分${record.report.score.totalRank}th` : '-分-th'}
               </div>
               <div className="f-s-12">全站: {Math.round(record.totalScore / record.totalTimes)}分</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div className="night f-s-16 f-w-b">
-                    {record.prevReport.score.totalScore}分{record.prevReport.score.totalRank}th
-                  </div>
-                  <div className="f-s-12">全站: {Math.round(record.secondTotalScore / record.secondTotalTimes)}分</div>
-                </div>
-              )}
             </div>,
-            <div className="table-row">
-              <div className="night f-s-16 f-w-b">
-                {record.report ? `${record.report.score.totalScore}分${record.report.score.totalRank}th` : '-分-th'}
-              </div>
-              <div className="f-s-12">全站: {Math.round(record.totalScore / record.totalTimes)}分</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div className="night f-s-16 f-w-b">
-                    {record.prevReport.score.totalScore}分{record.prevReport.score.totalRank}th
-                  </div>
-                  <div className="f-s-12">全站: {Math.round(record.secondTotalScore / record.secondTotalTimes)}分</div>
+            this.state.showPrev && record.prevReport && (
+              <div className="table-row prev t-3">
+                <div className="night f-s-16 f-w-b">
+                  {record.prevReport.score.totalScore}分{record.prevReport.score.totalRank}th
                 </div>
-              )}
-            </div>,
+                <div className="f-s-12">全站: {Math.round(record.secondTotalScore / record.secondTotalTimes)}分</div>
+              </div>
+            ),
           ];
         },
       },
@@ -107,22 +74,22 @@ export default class extends Page {
         width: 110,
         align: 'left',
         render: record => {
-          return (
+          return [
             <div className="table-row">
               <div className="night f-s-16 f-w-b">
                 {record.report ? `${record.report.score.verbalScore}分${record.report.score.verbalRank}th` : '-分-th'}
               </div>
               <div className="f-s-12">全站: {Math.round(record.verbalScore / record.totalTimes)}分</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div className="night f-s-16 f-w-b">
-                    {record.prevReport.score.verbalScore}分{record.prevReport.score.verbalRank}th
-                  </div>
-                  <div className="f-s-12">全站: {Math.round(record.secondVerbalScore / record.secondTotalTimes)}分</div>
+            </div>,
+            this.state.showPrev && record.prevReport && (
+              <div className="table-row prev t-3">
+                <div className="night f-s-16 f-w-b">
+                  {record.prevReport.score.verbalScore}分{record.prevReport.score.verbalRank}th
                 </div>
-              )}
-            </div>
-          );
+                <div className="f-s-12">全站: {Math.round(record.secondVerbalScore / record.secondTotalTimes)}分</div>
+              </div>
+            ),
+          ];
         },
       },
       {
@@ -130,22 +97,21 @@ export default class extends Page {
         width: 110,
         align: 'left',
         render: record => {
-          return (
-            <div className="table-row">
+          return [<div className="table-row">
+            <div className="night f-s-16 f-w-b">
+              {record.report ? `${record.report.score.quantScore}分${record.report.score.quantRank}th` : '-分-th'}
+            </div>
+            <div className="f-s-12">全站: {Math.round(record.quantScore / record.totalTimes)}分</div>
+          </div>,
+          this.state.showPrev && record.prevReport && (
+            <div className="table-row prev t-3">
               <div className="night f-s-16 f-w-b">
-                {record.report ? `${record.report.score.quantScore}分${record.report.score.quantRank}th` : '-分-th'}
+                {record.prevReport.score.quantScore}分{record.prevReport.score.quantRank}th
               </div>
-              <div className="f-s-12">全站: {Math.round(record.quantScore / record.totalTimes)}分</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div className="night f-s-16 f-w-b">
-                    {record.prevReport.score.quantScore}分{record.prevReport.score.quantRank}th
-                  </div>
-                  <div className="f-s-12">全站: {Math.round(record.secondQuantScore / record.secondTotalTimes)}分</div>
-                </div>
-              )}
+              <div className="f-s-12">全站: {Math.round(record.secondQuantScore / record.secondTotalTimes)}分</div>
             </div>
-          );
+          ),
+          ];
         },
       },
       {
@@ -153,22 +119,21 @@ export default class extends Page {
         width: 110,
         align: 'left',
         render: record => {
-          return (
-            <div className="table-row">
+          return [<div className="table-row">
+            <div className="night f-s-16 f-w-b">
+              {record.report ? `${record.report.score.irScore}分${record.report.score.irRank}th` : '-分-th'}
+            </div>
+            <div className="f-s-12">全站: {Math.round(record.irScore / record.totalTimes)}分</div>
+          </div>,
+          this.state.showPrev && record.prevReport && (
+            <div className="table-row prev t-3">
               <div className="night f-s-16 f-w-b">
-                {record.report ? `${record.report.score.irScore}分${record.report.score.irRank}th` : '-分-th'}
+                {record.prevReport.score.irScore}分{record.prevReport.score.irRank}th
               </div>
-              <div className="f-s-12">全站: {Math.round(record.irScore / record.totalTimes)}分</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div className="night f-s-16 f-w-b">
-                    {record.prevReport.score.irScore}分{record.prevReport.score.irRank}th
-                  </div>
-                  <div className="f-s-12">全站: {Math.round(record.secondIrScore / record.secondTotalTimes)}分</div>
-                </div>
-              )}
+              <div className="f-s-12">全站: {Math.round(record.secondIrScore / record.secondTotalTimes)}分</div>
             </div>
-          );
+          ),
+          ];
         },
       },
       {
@@ -176,18 +141,17 @@ export default class extends Page {
         width: 100,
         align: 'left',
         render: record => {
-          return (
-            <div className="table-row">
-              <div>{record.report && formatDate(record.report.updateTime, 'YYYY-MM-DD')}</div>
-              <div>{record.report && formatDate(record.report.updateTime, 'HH:mm')}</div>
-              {this.state.showPrev && record.prevReport && (
-                <div className="prev">
-                  <div>{formatDate(record.prevReport.updateTime, 'YYYY-MM-DD')}</div>
-                  <div>{formatDate(record.prevReport.updateTime, 'HH:mm')}</div>
-                </div>
-              )}
+          return [<div className="table-row">
+            <div>{record.report && formatDate(record.report.updateTime, 'YYYY-MM-DD')}</div>
+            <div>{record.report && formatDate(record.report.updateTime, 'HH:mm')}</div>
+          </div>,
+          this.state.showPrev && record.prevReport && (
+            <div className="table-row prev t-3">
+              <div>{formatDate(record.prevReport.updateTime, 'YYYY-MM-DD')}</div>
+              <div>{formatDate(record.prevReport.updateTime, 'HH:mm')}</div>
             </div>
-          );
+          ),
+          ];
         },
       },
       {
@@ -195,29 +159,31 @@ export default class extends Page {
         width: 110,
         align: 'left',
         render: record => {
-          return (
-            <div className="table-row p-t-1">
-              {!record.report && (
-                <IconButton
-                  className="m-r-5"
-                  type="start"
-                  tip="Start"
-                  onClick={() => {
-                    Question.startLink('examination', record);
-                  }}
-                />
-              )}
-              {record.report && !record.report.isFinish && (
-                <IconButton
-                  type="continue"
-                  tip="Continue"
-                  onClick={() => {
-                    Question.continueLink('examination', record);
-                  }}
-                />
-              )}
-            </div>
-          );
+          return [<div className="table-row p-t-1">
+            {!record.report && (
+              <IconButton
+                className="m-r-5"
+                type="start"
+                tip="Start"
+                onClick={() => {
+                  Question.startLink('examination', record);
+                }}
+              />
+            )}
+            {record.report && !record.report.isFinish && (
+              <IconButton
+                type="continue"
+                tip="Continue"
+                onClick={() => {
+                  Question.continueLink('examination', record);
+                }}
+              />
+            )}
+          </div>,
+          this.state.showPrev && record.prevReport && (
+            <div className="table-row prev" />
+          ),
+          ];
         },
       },
       {
@@ -225,33 +191,32 @@ export default class extends Page {
         width: 50,
         align: 'right',
         render: record => {
-          return (
-            <div className="table-row p-t-1">
-              {record.report && record.report.isFinish && (
+          return [<div className="table-row p-t-1">
+            {record.report && record.report.isFinish && (
+              <IconButton
+                className="m-r-5"
+                type="report"
+                tip="Report"
+                onClick={() => {
+                  Question.reportLink(record);
+                }}
+              />
+            )}
+          </div>,
+          this.state.showPrev && (
+            <div className="prev">
+              {record.prevReport && (
                 <IconButton
-                  className="m-r-5"
                   type="report"
                   tip="Report"
                   onClick={() => {
-                    Question.reportLink(record);
+                    Question.reportPrevLink(record);
                   }}
                 />
               )}
-              {this.state.showPrev && (
-                <div className="prev">
-                  {record.prevReport && (
-                    <IconButton
-                      type="report"
-                      tip="Report"
-                      onClick={() => {
-                        Question.reportPrevLink(record);
-                      }}
-                    />
-                  )}
-                </div>
-              )}
             </div>
-          );
+          ),
+          ];
         },
       },
     ];

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

@@ -141,13 +141,13 @@ export default class extends Page {
           },
           {
             title: '剩余',
-            number: row.userNumber ? row.questionNumber - row.userNumber : '-',
+            number: row.userNumber ? row.paperNumber - row.userNumber : '-',
             unit: '套',
           },
         ];
-        row.pieValue = formatPercent(row.userNumber, row.questionNumber);
-        row.pieText = formatPercent(row.userNumber, row.questionNumber, false);
-        row.pieSubText = `共${row.questionNumber}套`;
+        row.pieValue = formatPercent(row.userNumber, row.paperNumber);
+        row.pieText = formatPercent(row.userNumber, row.paperNumber, false);
+        row.pieSubText = `共${row.paperNumber}套`;
 
         return row;
       });

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

@@ -141,7 +141,7 @@ export default class extends Page {
     const { id } = this.params;
     Main.getExerciseParent(id).then(result => {
       const navs = result.map(row => {
-        row.title = `${row.titleZh}${row.titleEn}`;
+        row.title = row.level > 2 ? row.titleZh : `${row.titleZh}${row.titleEn}`;
         return row;
       });
       this.inited = true;

+ 3 - 4
front/project/www/routes/exercise/main/page.js

@@ -458,8 +458,7 @@ export default class extends Page {
       const now = new Date().getTime();
       courseMap.open = result.filter(row => !row.isUsed && (!row.useEndTime || new Date(row.useEndTime).getTime() > now));
       courseMap.end = result.filter(row => (!row.isSuspend || (row.isSuspend && row.restoreTime)) && new Date(row.useEndTime).getTime() < now);
-
-      courseMap.process = result.filter(row => row.isUsed && (row.isSuspend || row.restoreTime) && new Date(row.useEndTime).getTime() >= now);
+      courseMap.process = result.filter(row => row.isUsed && ((!row.isSuspend && new Date(row.useEndTime).getTime() >= now) || (row.isSuspend && !row.restoreTime)));
       this.setState({ courseMap });
     });
 
@@ -746,8 +745,8 @@ export default class extends Page {
             return <Card1
               title={`${row.course.title}${row.vsNo > 0 ? `V${row.vsNo}` : ''}${row.number > 0 ? `(${row.number}课时)` : ''}`}
               tag={CourseModuleMap[row.course.courseModule]}
-              status={row.isStop && !row.isSuspend ? 'stop' : 'ing'}
-              list={row.papers.map(r => {
+              status={row.isSuspend && !row.restoreTime ? 'stop' : 'ing'}
+              list={(row.papers || []).map(r => {
                 let progress = 0;
                 if (r.report) {
                   progress = formatPercent(r.report.userNumber, r.report.questionNumber);

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

@@ -31,20 +31,16 @@ export default class extends Page {
   }
 
   formatRecord(row) {
-    if (row.number > 1 && row.number === row.appointments.length) {
-      row.status = 'end';
-    } else if (row.useEndTime) {
-      if (new Date(row.useEndTime).getTime() > new Date().getTime()) {
-        row.status = 'end';
-      } else if (row.isSuspend && !row.restoreTime) {
+    if (row.useEndTime) {
+      if (row.isSuspend && !row.restoreTime) {
         row.status = 'suspend';
+      } else if (new Date(row.useEndTime).getTime() < new Date().getTime()) {
+        row.status = 'end';
       } else {
         row.status = 'ing';
       }
-    } else if (new Date(row.useEndTime).getTime() < new Date().getTime()) {
-      row.status = 'end';
     } else {
-      row.status = 'no';
+      row.status = 'not';
     }
     row.paperMap = {};
     row.appointmentPaperMap = {};
@@ -77,15 +73,22 @@ export default class extends Page {
       row.currentNo = 0;
     }
     // 如果已经最新预约结束,则添加一个空记录作为最新预约
-    if (!row.appointments || row.appointments.length === 0) {
-      row.appointments = [{}];
-    } else {
+    if (row.appointments) {
       row.appointments.forEach(r => {
         r.paper = row.appointmentPaperMap[r.id];
-        r.noteList = (row.comments || []).map(c => c.type === 'note' && c.appointmentId === r.id);
-        r.supplyList = (row.comments || []).map(c => c.type === 'supply' && c.appointmentId === r.id);
+        r.noteList = (row.comments || []).filter(c => c.type === 'note' && c.appointmentId === r.id);
+        r.supplyList = (row.comments || []).filter(c => c.type === 'supply' && c.appointmentId === r.id);
       });
       // 是否是最后一课时,是否过预约时间
+      const last = row.appointments.length - 1;
+      const appointment = row.appointments[last];
+
+      if (new Date(appointment.endTime).getTime() < new Date().getTime()) {
+        // row.status = 'end';
+        if (row.number !== row.appointments.length) {
+          row.appointments.push([{}]);
+        }
+      }
     }
 
     row.days = new Date(row.userEndTime);
@@ -198,7 +201,8 @@ export default class extends Page {
       });
   }
 
-  submitAppointmentComment(data) {
+  submitAppointmentComment(data, type) {
+    data.type = type;
     if (data.id) {
       My.editAppointmentComment(data)
         .then(() => {
@@ -288,7 +292,7 @@ export default class extends Page {
           onChange={key => this.onStatusChange(key)}
         />
         {this[`renderTab${tab}`]()}
-        <Modal show={showTime} className="clock-modal" title="打卡表" width={460} onClose={() => { }}>
+        <Modal show={showTime} className="clock-modal" title="打卡表" width={460} onClose={() => this.setState({ showTime: false })}>
           <div>
             <div className="d-i-b w-3">
               <div className="t-2 t-s-14">听课频率</div>
@@ -316,6 +320,8 @@ export default class extends Page {
           </div>
           <DatePlane
             hideInput
+            show={showTime}
+            onChange={() => { }}
             disabledDate={(current) => {
               const date = current.format('YYYY-MM-DD');
               return data.stopTimeMap[date];
@@ -383,7 +389,7 @@ export default class extends Page {
           title="上传笔记"
           width={630}
           confirmText="提交"
-          onConfirm={() => this.submitAppointmentComment(note)}
+          onConfirm={() => this.submitAppointmentComment(note, 'note')}
           onCancel={() => this.setState({ showUploadNote: false, note: {} })}
         >
           <textarea
@@ -398,15 +404,15 @@ export default class extends Page {
           />
           <div className={`t-c drag-upload ${this.state.draging ? 'draging' : ''}`}>
             <Button theme="file">上传文件</Button>
-            <span className="m-l-1 t-3 t-s-14">支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件</span>
+            <span className="m-l-1 t-3 t-s-14">{note.file ? `上传文件:${note.name} 成功` : '支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件'}</span>
             <div className="fixed">
-              <span className="f-w-b t-s-18">放开文件立刻上传{supply.file && `上传文件:${supply.name} 成功`}</span>
+              <span className="f-w-b t-s-18">放开文件立刻上传</span>
             </div>
             <FileUpload
               type="none"
               onDragEnter={() => this.setState({ draging: true })}
               onDragLeave={() => this.setState({ draging: false })}
-              onUpload={(file) => Common.uploadImage(file).then(result => {
+              onUpload={({ file }) => Common.upload(file).then(result => {
                 note.file = result.url;
                 note.name = file.name;
                 this.setState({ note });
@@ -427,7 +433,7 @@ export default class extends Page {
         </Modal>
         <Modal show={showUploadSupply} title="上传留言"
           width={630}
-          confirmText="提交" onConfirm={() => this.submitAppointmentComment(supply)} onCancel={() => this.setState({ showUploadSupply: false, supply: {} })}>
+          confirmText="提交" onConfirm={() => this.submitAppointmentComment(supply, 'supply')} onCancel={() => this.setState({ showUploadSupply: false, supply: {} })}>
           <textarea
             className="b-c-1 w-10 p-10 m-b-1"
             rows={6}
@@ -440,15 +446,15 @@ export default class extends Page {
           />
           <div className={`t-c drag-upload ${this.state.draging ? 'draging' : ''}`}>
             <Button theme="file">上传文件</Button>
-            <span className="m-l-1 t-3 t-s-14">支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件</span>
+            <span className="m-l-1 t-3 t-s-14">{supply.file ? `上传文件:${supply.name} 成功` : '支持 docx, xls, PDF, rar, zip, PNG, JPG 等类型的文件'}</span>
             <div className="fixed">
-              <span className="f-w-b t-s-18">放开文件立刻上传{supply.file && `上传文件:${supply.name} 成功`}</span>
+              <span className="f-w-b t-s-18">放开文件立刻上传</span>
             </div>
             <FileUpload
               type="none"
               onDragEnter={() => this.setState({ draging: true })}
               onDragLeave={() => this.setState({ draging: false })}
-              onUpload={(file) => Common.uploadImage(file).then(result => {
+              onUpload={({ file }) => Common.upload(file).then(result => {
                 supply.file = result.url;
                 supply.name = file.name;
                 this.setState({ supply });
@@ -463,7 +469,6 @@ export default class extends Page {
 
   renderTabonline() {
     const { list = [] } = this.state;
-    console.log(list);
     return list.map(item => {
       return <CourseOnline data={item} user={this.props.user} refreshDetail={(recordId) => {
         this.refreshDetail(recordId);
@@ -491,12 +496,12 @@ export default class extends Page {
       }} onComment={() => {
         this.setState({ showComment: true, comment: { channel: 'course-vs', position: item.course.id } });
       }} closeCommentTips={() => this.closeCommentTips(item.id)}
-        onNote={(appointment) => this.setState({ showNote: true, appointment, data: item })}
         onUploadNote={(appointment, row) => this.setState({ showUploadNote: true, appointment, data: item, note: row || {} })}
         onUploadSupply={(appointment, row) => this.setState({ showUploadSupply: true, appointment, data: item, supply: row || {} })}
         onDeleteNote={(appointment, row) => this.deleteAppointmentComment(row)}
         onDeleteSupply={(appointment, row) => this.deleteAppointmentComment(row)}
-        onSupply={(appointment) => this.setState({ whoSupply: true, appointment, data: item })}
+        onNote={(appointment) => this.setState({ showNote: true, appointment, data: item })}
+        onSupply={(appointment) => this.setState({ showSupply: true, appointment, data: item })}
         onUploadQuestion={(appointment, file, name) => this.submitQuestionFile({ id: appointment.id, recordId: appointment.recordId, questionFile: file, questionFileName: name })}
         setCCTalkName={(appointment, cctalkName) => this.setCCTalkName(appointment.recordId, cctalkName)} />;
     });
@@ -706,7 +711,7 @@ class CourseOnline extends Component {
               <div className="t1">授课老师</div>
               <div className="t2">{data.course.teacher}</div>
               <div className="t1">有效期</div>
-              <div className="t2">{formatDate(data.useStartTime, 'YYYY-MM-DD')}至{formatDate(data.useEndTime, 'YYYY-MM-DD')}</div>
+              <div className="t-s-12">{formatDate(data.useStartTime, 'YYYY-MM-DD')}<br />至{formatDate(data.useEndTime, 'YYYY-MM-DD')}</div>
             </div>
           </div>
           <div className="right">
@@ -845,21 +850,22 @@ const statusMap = {
   },
   3: (appointment, data) => {
     if (!data.cctalkName) return 'not';
+    // if (new Date(appointment.endTime).getTime() > new Date()) return 'not';
     return '';
   },
   4: (appointment) => {
-    if (!appointment.noteList && appointment.noteList.length === 0) return 'not';
+    if (!appointment.noteList || appointment.noteList.length === 0) return 'not';
     return '';
   },
   5: (appointment) => {
-    if (!appointment.supplyList && appointment.supplyList.length === 0) return 'not';
+    if (!appointment.supplyList || appointment.supplyList.length === 0) return 'not';
     return '';
   },
   6: () => {
     return '';
   },
   7: (appointment) => {
-    const { paper } = appointment;
+    const { paper = {} } = appointment;
     if (!paper.report || formatPercent(paper.report.userNumber, paper.report.questionNumber) < 100) return 'not';
     return '';
   },
@@ -919,7 +925,7 @@ class CourseVs extends Component {
           title: '课后补充',
           key: 'supply',
           render: (text, record) => {
-            this.props.onSupply(record);
+            return <a onClick={() => this.props.onSupply(record)}>查看</a>;
           },
         },
       ],
@@ -960,7 +966,7 @@ class CourseVs extends Component {
 
   renderIng() {
     const { data, onComment, closeCommentTips } = this.props;
-    const { tab, showTips } = this.state;
+    const { tab, showTips, open } = this.state;
     return (
       <div className="education-item ing">
         <div className="title">
@@ -976,8 +982,8 @@ class CourseVs extends Component {
               }} />
           </div>
         </div>
-        {showTips && <div className="continue" onClick={() => closeCommentTips()}>
-          <Assets name="notice" />
+        {showTips && <div className="continue">
+          <Icon className='close m-r-5 t-3' type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
           课程已过半,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
         </div>}
         <div className="detail">
@@ -1004,8 +1010,11 @@ class CourseVs extends Component {
               </div>
             </div>
           </div>
+          <div className="open">
+            <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
+          </div>
         </div>
-        {(data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
+        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
           className="t-l"
           type="line"
           theme="theme"
@@ -1015,7 +1024,7 @@ class CourseVs extends Component {
           tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
           onChange={key => this.setState({ tab: key })}
         />}
-        {tab === 'ing' ? this.renderTimeLine() : this.renderTable()}
+        {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
       </div>
     );
   }
@@ -1079,8 +1088,8 @@ class CourseVs extends Component {
               }} />
           </div>
         </div>
-        {showTips && <div className="continue" onClick={() => closeCommentTips()}>
-          <Assets name="notice" />
+        {showTips && <div className="continue">
+          <Icon className='close m-r-5 t-3' type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
           课程已结束,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
         </div>}
         <div className="detail">
@@ -1111,7 +1120,7 @@ class CourseVs extends Component {
             <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
           </div>
         </div>
-        {(data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
+        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
           className="t-l"
           type="line"
           theme="theme"
@@ -1121,7 +1130,7 @@ class CourseVs extends Component {
           tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
           onChange={key => this.setState({ tab: key })}
         />}
-        {tab === 'ing' ? this.renderTimeLine() : this.renderTable()}
+        {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
       </div>
     );
   }
@@ -1180,24 +1189,24 @@ class CourseVs extends Component {
     let status = '';
     return ([
       <div className="class-hour">
-        <div className="text">课时 {appointment.no}:{appointment.title}</div>
-        <div className="right">
+        {data.number > 1 && <div className="text">课时 {appointment.no}:{appointment.title}</div>}
+        {data.number > 1 && <div className="right">
           <GIcon name="prev" onClick={() => this.setState({ index: index === 0 ? index : index - 1 })} />
           <span>上一课时</span>
           <span>下一课时</span>
           <GIcon name="next" onClick={() => this.setState({ index: index >= data.appointments.length - 1 ? index : index + 1 })} />
-        </div>
+        </div>}
       </div>,
       <div className="time-line">
         {list.map(item => {
           if (status === '') {
             // 上一阶段完成
-            status = statusMap(appointment, data);
+            status = statusMap[item](appointment, data);
           } else {
             // 上一阶段未完成
             status = 'end';
           }
-          return <TimeLineItem type={item} user={this.props.user} appointment={appointment} data={data} status={status} onUploadNote={onUploadNote} onUploadSupply={onUploadSupply} onUploadQuestion={onUploadQuestion} setCCTalkName={setCCTalkName} />;
+          return <TimeLineItem type={`${item}`} user={this.props.user} appointment={appointment} data={data} status={status} onUploadNote={onUploadNote} onUploadSupply={onUploadSupply} onUploadQuestion={onUploadQuestion} setCCTalkName={setCCTalkName} />;
         })}
       </div>,
     ]);
@@ -1206,7 +1215,7 @@ class CourseVs extends Component {
   renderTable() {
     const { data = {} } = this.props;
     const { appointments = [] } = data;
-    return <UserTable size="small" columns={this.columns[data.course.vsType]} data={appointments} />;
+    return <UserTable size="small" columns={this.columns[data.course.vsType]} data={appointments.filter(row => row.id)} />;
   }
 }
 class TimeLineItem extends Component {
@@ -1228,7 +1237,7 @@ class TimeLineItem extends Component {
     return (
       <div className={`time-line-item ${status}`}>
         <div className="icon-title">
-          <GIcon name={iconMap[type]} active={status !== 'not'} noHover />
+          <GIcon name={iconMap[type]} active={!status} noHover />
           <div className="title">{titleMap[type]}</div>
         </div>
         <div className="time-line-detail">{this.renderDetail()}</div>
@@ -1255,7 +1264,7 @@ class TimeLineItem extends Component {
             return <span className="link">点此上传</span>;
           case 'not':
             return <FileUpload onUpload={(file) => {
-              return Common.upload(file).then((result => onUploadQuestion(appointment, result.url, file.name)));
+              return Common.upload({ file }).then((result => onUploadQuestion(appointment, result.url, file.name)));
             }}><span className="link">点此上传</span></FileUpload>;
           default:
             return <a href={appointment.questionFile} target="_blank">{appointment.questionFileName || '文件'}</a>;
@@ -1263,11 +1272,19 @@ class TimeLineItem extends Component {
       case '3':
         switch (status) {
           case 'end':
-            return <input placeholder="请输入CCtalk用户名查看授课频道" />;
+            return data.cctalkName ? <span>
+              CCtalk 频道号 :{appointment.cctalkChannel} <a className="link" href="" target="_black">CC talk使用手册</a>
+            </span> : <div><input style={{ width: 200 }} className='b-c-1 p-l-1 p-r-1 t-s-12 m-r-1' placeholder="请输入CCtalk用户名查看授课频道" onChange={(e) => {
+              this.setState({ cctalkName: e.target.value });
+            }} /><Button size="small" radius disabled>提交</Button></div>;
           case 'not':
-            return <input placeholder="请输入CCtalk用户名查看授课频道" onChange={(e) => {
-              setCCTalkName(e.target.value);
-            }} />;
+            return data.cctalkName ? <span>
+              CCtalk 频道号 :{appointment.cctalkChannel} <a className="link" href="" target="_black">CC talk使用手册</a>
+            </span> : <div><input style={{ width: 200 }} className='b-c-1 p-l-1 p-r-1 t-s-12 m-r-1' placeholder="请输入CCtalk用户名查看授课频道" onChange={(e) => {
+              this.setState({ cctalkName: e.target.value });
+            }} /><Button size="small" radius onClick={() => {
+              if (this.state.cctalkName) setCCTalkName(appointment, this.state.cctalkName);
+            }} >提交</Button></div>;
           default:
             return <span>
               CCtalk 频道号 :{appointment.cctalkChannel} <a className="link" href="" target="_black">CC talk使用手册</a>
@@ -1278,16 +1295,17 @@ class TimeLineItem extends Component {
           case 'end':
             return <span className="link" >点此上传</span>;
           case 'not':
-            return <span className="link" onClick={() => onUploadNote(appointment)}>点此上传</span>;
+            return <span className="link" onClick={() => onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>点此上传</span>;
           default:
             return (
               <div>
                 <div>
-                  <span className="link" onClick={() => onUploadNote(appointment)}>点此上传</span>
+                  <span className="link" onClick={() => onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>点此上传</span>
                 </div>
                 <div className="note-list">
                   {appointment.noteList.map(row => {
-                    return <Note user={this.props.user} teacher={data.teacher} data={row} reply={!row.userId} actionList={[row.userId && { key: 'edit', title: '编辑' }, row.userId && { key: 'delete', title: '删除' }]} onAction={(key) => {
+                    console.log(row);
+                    return <Note user={this.props.user} teacher={data.teacher} data={row} reply={!row.userId} actionList={row.userId ? [{ key: 'edit', label: '编辑' }, { key: 'delete', label: '删除' }] : null} onAction={(key) => {
                       switch (key) {
                         case 'edit':
                           onUploadNote(appointment, row);
@@ -1296,7 +1314,7 @@ class TimeLineItem extends Component {
                           onDeleteNote(appointment, row);
                           break;
                         case 'reply':
-                          onUploadNote(appointment, { parentId: row.id });
+                          onUploadNote(appointment, { parentId: row.id, appointmentId: appointment.id, recordId: appointment.recordId });
                           break;
                         default:
                       }
@@ -1311,16 +1329,16 @@ class TimeLineItem extends Component {
           case 'end':
             return <span className="link" >写留言</span>;
           case 'not':
-            return <span className="link" onClick={() => onUploadSupply(appointment)}>写留言</span>;
+            return <span className="link" onClick={() => onUploadSupply(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>写留言</span>;
           default:
             return (
               <div>
                 <div>
-                  <span className="link" onClick={() => onUploadSupply(appointment)}>写留言</span>
+                  <span className="link" onClick={() => onUploadSupply(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>写留言</span>
                 </div>
                 <div className="note-list">
                   {appointment.supplyList.map(row => {
-                    return <Note user={this.props.user} teacher={data.teacher} data={row} reply={!row.userId} actionList={[row.userId && { key: 'edit', title: '编辑' }, row.userId && { key: 'delete', title: '删除' }]} onAction={(key) => {
+                    return <Note user={this.props.user} teacher={data.teacher} data={row} reply={!row.userId} actionList={row.userId ? [{ key: 'edit', label: '编辑' }, { key: 'delete', label: '删除' }] : null} onAction={(key) => {
                       switch (key) {
                         case 'edit':
                           onUploadSupply(appointment, row);
@@ -1329,7 +1347,7 @@ class TimeLineItem extends Component {
                           onDeleteSupply(appointment, row);
                           break;
                         case 'reply':
-                          onUploadSupply(appointment, { parentId: row.id });
+                          onUploadSupply(appointment, { parentId: row.id, appointmentId: appointment.id, recordId: appointment.recordId });
                           break;
                         default:
                       }

+ 50 - 13
front/project/www/routes/my/order/page.js

@@ -1,34 +1,60 @@
 import React from 'react';
 import './index.less';
 import Page from '@src/containers/Page';
+import { asyncSMessage } from '@src/services/AsyncTools';
 import { getMap, formatMoney, formatDate } from '@src/services/Tools';
 import UserLayout from '../../../layouts/User';
 import menu from '../index';
 import UserTable from '../../../components/UserTable';
 import { Order } from '../../../stores/order';
 import { RecordSource, ServiceKey } from '../../../../Constant';
+import More from '../../../components/More';
 
 const RecordSourceMap = getMap(RecordSource, 'value', 'label');
 const ServiceKeyMap = getMap(ServiceKey, 'value', 'label');
+function formatTitle(record) {
+  if (record.productType === 'course-package') {
+    return (record.coursePackage || {}).title;
+  }
+  if (record.productType === 'course') {
+    return (record.course || {}).title;
+  }
+  if (record.productType === 'data') {
+    return (record.data || {}).title;
+  }
+  if (record.productType === 'service') {
+    return `${ServiceKeyMap[record.service]}`;
+  }
+  return '';
+}
 const columns = [
-  { title: '订单编号', key: 'orderId' },
+  { title: '订单编号', key: 'id' },
   {
     title: '服务',
     key: 'title',
     render: (text, record) => {
-      if (record.productType === 'course-package') {
-        return (record.coursePackage || {}).title;
-      }
-      if (record.productType === 'course') {
-        return (record.course || {}).title;
+      const actionList = [];
+      if (record.canInvoice && !record.hasInvoice) {
+        actionList.push({ key: 'invoice', label: '开发票' });
       }
-      if (record.productType === 'data') {
-        return (record.data || {}).title;
+      actionList.push({ key: 'detail', label: '订单详情' });
+      const onAction = (key) => {
+        switch (key) {
+          case 'invoice':
+            this.setState({ showInvoice: true, invoice: { orderId: record.id, money: record.invoiceMoney } });
+            break;
+          case 'detail':
+            openLink(`/order/detail/${record.id}`);
+            break;
+          default:
+        }
+      };
+      if (record.checkouts.length > 3) {
+        return <span>{formatTitle(record.checkouts[0])}<br />等{record.checkouts.length}个商品<More actionList={actionList} onAction={onAction} /></span>;
       }
-      if (record.productType === 'service') {
-        return `${ServiceKeyMap[text]}`;
-      }
-      return '';
+      return record.checkouts.map(row => {
+        return formatTitle(row);
+      });
     },
   },
   {
@@ -40,7 +66,7 @@ const columns = [
   },
   {
     title: '付款方式',
-    key: 'source',
+    key: 'payMethod',
     render: (text) => {
       return RecordSourceMap[text];
     },
@@ -75,6 +101,17 @@ export default class extends Page {
     this.search({ page });
   }
 
+  submitInvoice(invoice) {
+    Order.openInvoice(invoice)
+      .then(() => {
+        this.refresh();
+        this.setState({ showFinish: true, showInvoice: false, invoice: {} });
+      })
+      .catch(e => {
+        asyncSMessage(e.message, 'error');
+      });
+  }
+
   renderView() {
     const { config } = this.props;
     return <UserLayout active={config.key} menu={menu} center={this.renderTable()} />;

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

@@ -69,6 +69,10 @@ export default class OrderStore extends BaseStore {
   useRecord(id, isSubscribe) {
     return this.apiPost('/order/record/use', { id, isSubscribe });
   }
+
+  openInvoice({ orderId, invoiceType, title, identity }) {
+    return this.apiPost('/order/invoice/open', { orderId, invoiceType, title, identity });
+  }
 }
 
 export const Order = new OrderStore({ key: 'order' });

+ 1 - 1
front/project/www/stores/user.js

@@ -20,7 +20,7 @@ export default class UserStore extends BaseStore {
     if (this.state.login || this.adminLogin) {
       this.refreshToken().then(() => {
         if (this.adminLogin) {
-          window.location.href = window.location.href.substr(0, window.location.href.indexOf('?'));
+          window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
         }
       });
     }

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

@@ -19,7 +19,7 @@
     select
     <include refid="Id_Column_List" />
     from `user_order` uo
-    where uo.is_speed = 0
+    where (uo.is_speed = 0 or (uo.is_speed = 1 and uo.pay_status>1)
     <if test="userId != null">
       and uo.`user_id` = #{userId,jdbcType=VARCHAR}
     </if>

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

@@ -632,11 +632,15 @@ public class CourseController {
     @ApiOperation(value = "添加vs学员", httpMethod = "POST")
     private Response<Boolean> addStudentVs(@RequestBody @Validated UserCourseRecordDto dto){
         UserOrderRecord entity = Transform.dtoToEntity(dto);
+        Course course = courseService.get(dto.getCourseId());
         entity.setProductType(ProductType.COURSE.key);
         entity.setOrderId(0);
         entity.setProductId(dto.getCourseId());
         entity.setTeacherId(dto.getTeacherId());
         entity.setSource(RecordSource.BACKEND.key);
+        entity.setNumber(dto.getNumber());
+        entity.setExpireDays(course.getExpireDays());
+        entity.setUseExpireDays(courseExtendService.computeExpire(dto.getNumber(), course));
         // 预约后开通: 有效期开通后计算
         orderFlowService.addRecord(entity);
 
@@ -648,11 +652,13 @@ public class CourseController {
     private Response<Boolean> editStudentVs(@RequestBody @Validated UserCourseRecordDto dto){
         UserOrderRecord entity = Transform.dtoToEntity(dto);
         UserOrderRecord in = userOrderRecordService.get(entity.getId());
-        if (in.getIsUsed() > 0){
+        if (in.getIsUsed() > 0 && !in.getNumber().equals(dto.getNumber())){
             // 已开通,重新计算有效期
             Course course = courseService.get(dto.getCourseId());
             Integer expireDay = courseExtendService.computeExpire(dto.getNumber(), course);
             entity.setEndTime(Tools.addDate(in.getStartTime(), expireDay));
+            entity.setNumber(dto.getNumber());
+            entity.setUseExpireDays(expireDay);
         }
         userOrderRecordService.edit(entity);
         return ResponseHelp.success(true);

+ 17 - 4
server/gateway-api/src/main/java/com/qxgmat/controller/admin/UserController.java

@@ -631,6 +631,10 @@ public class UserController {
         }
         UserCourseAppointment entity = Transform.dtoToEntity(dto);
         entity = userCourseAppointmentService.addAppointment(entity);
+        // 第一次预约,开通
+        if (entity.getNo() == 1){
+            orderFlowService.useRecord(record.getUserId(), record.getId());
+        }
         managerLogService.log(request);
         return ResponseHelp.success(Transform.convert(entity, CourseTime.class));
     }
@@ -810,14 +814,21 @@ public class UserController {
     }
 
     @RequestMapping(value = "/invoice/download", method = RequestMethod.PUT)
-    @ApiOperation(value = "下载资料", httpMethod = "PUT")
+    @ApiOperation(value = "下载发票", httpMethod = "PUT")
     public Response<Boolean> downloadInvoice(
             @RequestParam(required = false) Integer[] ids,
             HttpServletRequest request, HttpServletResponse response) throws IOException {
         managerLogService.log(request);
         userInvoiceService.download(ids);
-        List<UserInvoice> p = userInvoiceService.select(ids);
-        String columnNames[]={"ID","项目名","销售人","负责人","所用技术","备注"};//列名
+        List<UserInvoice> list = userInvoiceService.select(ids);
+        Collection userIds = Transform.getIds(list, UserInvoice.class, "userId");
+        List<User> userList = usersService.select(userIds);
+        Map userMap = Transform.getMap(userList, User.class, "id");
+        Collection orderIds = Transform.getIds(list, UserInvoice.class, "orderId");
+        List<UserOrder> orderList = userOrderService.select(orderIds);
+        Map orderMap = Transform.getMap(orderList, User.class, "id");
+
+        String columnNames[]={"申请时间","用户昵称","用户ID","用户手机号","开票今金额","开票内容", "发票抬头", "纳税人识别号", "收件邮箱"};//列名
         String filename = "发票";
         //生成一个Excel文件
         // 创建excel工作簿
@@ -832,8 +843,10 @@ public class UserController {
             cell.setCellValue(columnNames[i]);
         }
         int i = 0;
-        for(UserInvoice invoice : p){
+        for(UserInvoice invoice : list){
             i+=1;
+            User user = (User) userMap.get(invoice.getUserId());
+            UserOrder userOrder = (UserOrder) orderMap.get(invoice.getOrderId());
             Row r = sheet.createRow(i);
             Cell cell = r.createCell(0);
             cell.setCellValue(invoice.getId());

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

@@ -419,7 +419,7 @@ public class CourseController {
             userOrderRecordList = userOrderRecordService.listWithStudyAdmin(1, 1000, new String[]{CourseModule.VIDEO.key, CourseModule.ONLINE.key}, structId, courseId, user.getId(), null,null, null);
         } else if (module == CourseModule.VS){
             // 1v1课程:只有系统授课有作业
-            userOrderRecordList = userOrderRecordService.listWithVs(1, 1000, VsCourseType.COACH, courseId, user.getId(), null, null);
+            userOrderRecordList = userOrderRecordService.listWithVs(1, 1000, VsCourseType.SYSTEM, courseId, user.getId(), null, null);
         }else{
             throw new ParameterException("课程类型错误");
         }

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

@@ -1628,6 +1628,7 @@ public class MyController {
         Transform.combine(pr, progressMap, UserCourseDetailDto.class, "id", "progress", UserCourseProgressExtendDto.class);
         Map<Object, Collection<UserCourseRecord>> recordMap = userCourseRecordService.groupByRecordId(recordIds);
         for(UserCourseDetailDto dto : pr){
+            dto.setTotalDays(courseExtendService.computeCourseDay(map.get(dto.getId())));
             Collection<CourseNo> courseNos = courseNoMap.get(dto.getProductId());
             if (courseNos == null || courseNos.size() == 0) continue;
             Collection<UserCourseProgress> list = progressMap.get(dto.getId());
@@ -1635,7 +1636,6 @@ public class MyController {
             dto.setCurrentNo(courseExtendService.computeCourseNoCurrent(courseNos, list));
             Collection<UserCourseRecord> userCourseRecords = recordMap.get(dto.getId());
             dto.setTotalTime(courseExtendService.computeCourseTime(userCourseRecords));
-            dto.setTotalDays(courseExtendService.computeCourseDay(map.get(dto.getId()), userCourseRecords));
         }
 
         // 获取每个科目的所有作业
@@ -1652,7 +1652,7 @@ public class MyController {
                     finish += 1;
                 }
             }
-            dto.setPreviewProgress(finish * 100 / list.size());
+            dto.setPreviewProgress(list.size()> 0 ? finish * 100 / list.size(): 0);
         }
 
         // 绑定老师
@@ -1721,7 +1721,7 @@ public class MyController {
         List<UserCourseRecord> recordList = userCourseRecordService.allWithRecord(recordId);
         if(progressList != null)dto.setCurrentNo(courseExtendService.computeCourseNoCurrent(courseNoList, progressList));
         if(recordList != null)dto.setTotalTime(courseExtendService.computeCourseTime(recordList));
-        if(recordList != null)dto.setTotalDays(courseExtendService.computeCourseDay(record, recordList));
+        dto.setTotalDays(courseExtendService.computeCourseDay(record));
 
         // 获取每个科目的所有作业
         List<UserPreviewPaperRelation> previewList = previewService.list(1, 1000, recordId, user.getId(), null,null);
@@ -1734,7 +1734,7 @@ public class MyController {
                 finish += 1;
             }
         }
-        dto.setPreviewProgress(finish * 100 / previewList.size());
+        dto.setPreviewProgress(previewList.size() > 0 ? finish * 100 / previewList.size(): 0);
 
         // 绑定老师
         CourseTeacher teacher = courseTeacherService.get(record.getTeacherId());

+ 55 - 10
server/gateway-api/src/main/java/com/qxgmat/controller/api/OrderController.java

@@ -1,5 +1,6 @@
 package com.qxgmat.controller.api;
 
+import com.alibaba.fastjson.JSONArray;
 import com.alibaba.fastjson.JSONObject;
 import com.github.pagehelper.Page;
 import com.nuliji.tools.PageMessage;
@@ -19,10 +20,7 @@ import com.qxgmat.dto.extend.CourseDataExtendDto;
 import com.qxgmat.dto.extend.CourseExtendDto;
 import com.qxgmat.dto.extend.CoursePackageExtendDto;
 import com.qxgmat.dto.extend.UserOrderRecordExtendDto;
-import com.qxgmat.dto.request.OrderConfirmDto;
-import com.qxgmat.dto.request.PayOrderDto;
-import com.qxgmat.dto.request.RecordAddDto;
-import com.qxgmat.dto.request.RecordUseDto;
+import com.qxgmat.dto.request.*;
 import com.qxgmat.dto.response.UserOrderDetailDto;
 import com.qxgmat.dto.response.UserOrderRecordListDto;
 import com.qxgmat.help.ShiroHelp;
@@ -80,6 +78,9 @@ public class OrderController {
     @Autowired
     private CourseDataService courseDataService;
 
+    @Autowired
+    private UserInvoiceService userInvoiceService;
+
     @RequestMapping(value = "/checkout/all", method = RequestMethod.GET)
     @ApiOperation(value = "全部购物车", notes = "全部购物车", httpMethod = "GET")
     public Response<UserOrderDetailDto> allCheckout(HttpServletRequest request) throws Exception {
@@ -190,7 +191,7 @@ public class OrderController {
 
     @RequestMapping(value = "/list", method = RequestMethod.GET)
     @ApiOperation(value = "获取订单列表", notes = "获取订单列表", httpMethod = "GET")
-    public Response<PageMessage<UserOrderRecordListDto>> listOrder(
+    public Response<PageMessage<UserOrderDetailDto>> listOrder(
             @RequestParam(required = false, defaultValue = "1") int page,
             @RequestParam(required = false, defaultValue = "100") int size,
             @RequestParam(required = false, defaultValue = "id") String order,
@@ -199,8 +200,15 @@ public class OrderController {
         User user = (User) shiroHelp.getLoginUser();
 
         Page<UserOrder> p = userOrderService.list(page, size, user.getId(), order, DirectionStatus.ValueOf(direction));
+        Map<Integer, UserOrder> map = new HashMap<>();
 
-        List<UserOrderRecordListDto> pr = Transform.convert(p, UserOrderRecordListDto.class);
+        List<UserOrderDetailDto> pr = Transform.convert(p, UserOrderDetailDto.class);
+        Collection orderIds = Transform.getIds(p, UserOrder.class, "id");
+
+        List<UserOrderRecord> recordList = userOrderRecordService.allByUser(user.getId(), orderIds).stream().filter(row->row.getParentId()==0).collect(Collectors.toList());
+        List<UserOrderRecordListDto> records = Transform.convert(recordList, UserOrderRecordListDto.class);
+        Map<Object, List<UserOrderRecordListDto>> recordMap = Transform.getMapList(records, UserOrderRecordListDto.class, "orderId");
+        Transform.combine(pr, recordMap, UserOrderDetailDto.class, "id", "checkouts");
 
         // 绑定服务
         Map<Object, JSONObject> serviceList = new HashMap<Object, JSONObject>(){{
@@ -211,21 +219,33 @@ public class OrderController {
             Setting qxCatSetting = settingService.getByKey(SettingKey.SERVICE_QX_CAT);
             put(ServiceKey.QX_CAT.key, qxCatSetting.getValue());
         }};
-        List<UserOrderRecordListDto> prService = pr.stream().filter((row)-> row.getProductType().equals(ProductType.SERVICE.key)).collect(Collectors.toList());
+        List<UserOrderRecordListDto> prService = records.stream().filter((row)-> row.getProductType().equals(ProductType.SERVICE.key)).collect(Collectors.toList());
         Transform.combine(prService, serviceList, UserOrderRecordListDto.class, "service", "serviceInfo");
 
         // 绑定课程
-        List<UserOrderRecordListDto> prCourse = pr.stream().filter((row)-> row.getProductType().equals(ProductType.COURSE.key)).collect(Collectors.toList());
+        List<UserOrderRecordListDto> prCourse = records.stream().filter((row)-> row.getProductType().equals(ProductType.COURSE.key)).collect(Collectors.toList());
         Collection courseIds = Transform.getIds(prCourse, UserOrderRecordListDto.class, "productId");
         List<Course> courseList = courseService.select(courseIds);
         Transform.combine(prCourse, courseList, UserOrderRecordListDto.class, "productId", "course", Course.class, "id", CourseExtendDto.class);
 
         // 绑定资料
-        List<UserOrderRecordListDto> prData = pr.stream().filter((row)-> row.getProductType().equals(ProductType.DATA.key)).collect(Collectors.toList());
+        List<UserOrderRecordListDto> prData = records.stream().filter((row)-> row.getProductType().equals(ProductType.DATA.key)).collect(Collectors.toList());
         Collection dataIds = Transform.getIds(prData, UserOrderRecordListDto.class, "productId");
         List<CourseData> dataList = courseDataService.select(dataIds);
         Transform.combine(prData, dataList, UserOrderRecordListDto.class, "productId", "data", CourseData.class, "id", CourseDataExtendDto.class);
 
+        // 绑定发票
+        List<UserInvoice> userInvoiceList = userInvoiceService.listByOrder(user.getId(), orderIds);
+        Map invoiceMap = Transform.getMap(userInvoiceList, UserInvoice.class, "orderId", "id");
+
+        for(UserOrderDetailDto dto : pr){
+            dto.setHasInvoice(invoiceMap.containsKey(dto.getId()));
+            UserOrder userOrder = map.get(dto.getId());
+            JSONArray value = userOrder.getProductTypes();
+            if (value.contains(ProductType.COURSE.key)){
+                dto.setCanInvoice(true);
+            }
+        }
 
         return ResponseHelp.success(pr, page, size, p.getTotal());
     }
@@ -295,7 +315,7 @@ public class OrderController {
     }
 
     @RequestMapping(value = "/record/detail", method = RequestMethod.GET)
-    @ApiOperation(value = "获取订单记录", notes = "获取订单记录", httpMethod = "GET")
+    @ApiOperation(value = "获取订单记录详情", notes = "获取订单记录", httpMethod = "GET")
     public Response<UserOrderRecord> getOrderRecord(
             @RequestParam(required = true) Integer id
     )  {
@@ -318,6 +338,25 @@ public class OrderController {
         return ResponseHelp.success(record);
     }
 
+    @RequestMapping(value = "/invoice/open", method = RequestMethod.POST)
+    @ApiOperation(value = "申请发票", notes = "申请发票", httpMethod = "POST")
+    public Response<Boolean> openInvoice(@RequestBody @Validated OrderInvoiceDto dto)  {
+        User user = (User) shiroHelp.getLoginUser();
+        UserInvoice userInvoice = Transform.dtoToEntity(dto);
+        UserInvoice in = userInvoiceService.getByOrder(user.getId(), userInvoice.getOrderId());
+        if (in != null) {
+            throw new ParameterException("该订单已开发票");
+        }
+        UserOrder order = userOrderService.get(userInvoice.getOrderId());
+        JSONArray value = order.getProductTypes();
+        if (!value.contains(ProductType.COURSE.key)){
+            throw new ParameterException("该订单无法开发票");
+        }
+        userInvoice.setUserId(user.getId());
+        userInvoiceService.add(userInvoice);
+        return ResponseHelp.success(true);
+    }
+
     /**
      * 统一处理订单以及完整购物车返回信息
      * @param userId
@@ -350,6 +389,12 @@ public class OrderController {
         List<CoursePackage> packageList = coursePackageService.select(packageIds);
         dto.setPackages(Transform.convert(packageList, CoursePackageExtendDto.class));
 
+        // 发票
+        UserInvoice invoice = userInvoiceService.getByOrder(userId, order.getId());
+        dto.setHasInvoice(invoice != null);
+        if (courseCheckout.size() > 0){
+            dto.setCanInvoice(true);
+        }
         return dto;
     }
 }

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

@@ -139,7 +139,7 @@ public class TextbookController
                     UserOrderRecord record = userOrderRecordService.getUnUseService(user.getId(), ServiceKey.TEXTBOOK);
                     dto.setUnUseRecord(Transform.convert(record, UserServiceRecordExtendDto.class));
                 }
-                Collection questionNoIds = Transform.getIds(list, QuestionNo.class, "id");
+                Collection questionNoIds = Transform.getIds(list, TextbookQuestion.class, "id");
                 List<UserQuestion> userQuestionList = userQuestionService.listByQuestionNo(user.getId(), QuestionModule.TEXTBOOK, questionNoIds);
                 userQuestionStatMap = userQuestionService.statQuestionNoMap(userQuestionList);
 

+ 3 - 3
server/gateway-api/src/main/java/com/qxgmat/dto/admin/response/UserListDto.java

@@ -22,7 +22,7 @@ public class UserListDto {
 
     private Integer realStatus;
 
-    private Integer prepareStatus;
+    private String prepareStatus;
 
     private Integer inviteNumber;
 
@@ -86,11 +86,11 @@ public class UserListDto {
         this.inviteNumber = inviteNumber;
     }
 
-    public Integer getPrepareStatus() {
+    public String getPrepareStatus() {
         return prepareStatus;
     }
 
-    public void setPrepareStatus(Integer prepareStatus) {
+    public void setPrepareStatus(String prepareStatus) {
         this.prepareStatus = prepareStatus;
     }
 

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

@@ -15,6 +15,8 @@ public class CourseExtendDto {
 
     private String courseModule;
 
+    private String vsType;
+
     private String title;
 
     private String teacher;
@@ -106,4 +108,12 @@ public class CourseExtendDto {
     public void setExpireDays(Integer expireDays) {
         this.expireDays = expireDays;
     }
+
+    public String getVsType() {
+        return vsType;
+    }
+
+    public void setVsType(String vsType) {
+        this.vsType = vsType;
+    }
 }

+ 47 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/request/OrderInvoiceDto.java

@@ -0,0 +1,47 @@
+package com.qxgmat.dto.request;
+
+import com.nuliji.tools.annotation.Dto;
+import com.qxgmat.data.dao.entity.UserInvoice;
+
+@Dto(entity = UserInvoice.class)
+public class OrderInvoiceDto {
+    private Integer orderId;
+
+    private String invoiceType;
+
+    private String title;
+
+    private String identity;
+
+    public Integer getOrderId() {
+        return orderId;
+    }
+
+    public void setOrderId(Integer orderId) {
+        this.orderId = orderId;
+    }
+
+    public String getInvoiceType() {
+        return invoiceType;
+    }
+
+    public void setInvoiceType(String invoiceType) {
+        this.invoiceType = invoiceType;
+    }
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getIdentity() {
+        return identity;
+    }
+
+    public void setIdentity(String identity) {
+        this.identity = identity;
+    }
+}

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

@@ -19,6 +19,8 @@ public class UserCourseAppointmentCommentDto {
 
     private String file;
 
+    private String name;
+
     public Integer getId() {
         return id;
     }
@@ -74,4 +76,12 @@ public class UserCourseAppointmentCommentDto {
     public void setType(String type) {
         this.type = type;
     }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
 }

+ 10 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserCourseDetailDto.java

@@ -33,6 +33,8 @@ public class UserCourseDetailDto {
 
     private Date useEndTime;
 
+    private String cctalkName;
+
     private Integer isUsed;
 
     private Integer isStop;
@@ -330,4 +332,12 @@ public class UserCourseDetailDto {
     public void setProgress(Collection<UserCourseProgressExtendDto> progress) {
         this.progress = progress;
     }
+
+    public String getCctalkName() {
+        return cctalkName;
+    }
+
+    public void setCctalkName(String cctalkName) {
+        this.cctalkName = cctalkName;
+    }
 }

+ 52 - 0
server/gateway-api/src/main/java/com/qxgmat/dto/response/UserOrderDetailDto.java

@@ -12,6 +12,12 @@ import java.math.BigDecimal;
 import java.util.List;
 
 public class UserOrderDetailDto {
+    private Integer id;
+
+    private String payMethod;
+
+    private String transactionNo;
+
     private BigDecimal money;
 
     private BigDecimal originMoney;
@@ -20,6 +26,12 @@ public class UserOrderDetailDto {
 
     private JSONArray gift;
 
+    private BigDecimal invoiceMoney;
+
+    private Boolean hasInvoice;
+
+    private Boolean canInvoice;
+
     private List<UserOrderRecordExtendDto> checkouts;
 
     private List<CourseExtendDto> courses;
@@ -91,4 +103,44 @@ public class UserOrderDetailDto {
     public void setGift(JSONArray gift) {
         this.gift = gift;
     }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getPayMethod() {
+        return payMethod;
+    }
+
+    public void setPayMethod(String payMethod) {
+        this.payMethod = payMethod;
+    }
+
+    public String getTransactionNo() {
+        return transactionNo;
+    }
+
+    public void setTransactionNo(String transactionNo) {
+        this.transactionNo = transactionNo;
+    }
+
+    public Boolean getHasInvoice() {
+        return hasInvoice;
+    }
+
+    public void setHasInvoice(Boolean hasInvoice) {
+        this.hasInvoice = hasInvoice;
+    }
+
+    public Boolean getCanInvoice() {
+        return canInvoice;
+    }
+
+    public void setCanInvoice(Boolean canInvoice) {
+        this.canInvoice = canInvoice;
+    }
 }

+ 27 - 18
server/gateway-api/src/main/java/com/qxgmat/service/extend/CourseExtendService.java

@@ -42,7 +42,7 @@ public class CourseExtendService {
         // day / 10
         Integer expireDays = course.getExpirePreDays();
 
-        return Math.min(vsNumber / 10, 0)  * expireDays;
+        return Math.max(vsNumber / 10, 1) * expireDays;
     }
 
     /**
@@ -232,29 +232,38 @@ public class CourseExtendService {
     /**
      * 计算用户该课程的总学习天数
      * @param  record
-     * @param userCourseRecords
      * @return
      */
-    public int computeCourseDay(UserOrderRecord record, Collection<UserCourseRecord> userCourseRecords){
-        Date min = null;
-        Date max = null;
-        for(UserCourseRecord userCourseRecord:userCourseRecords){
-            if(min==null || min.after(userCourseRecord.getCreateTime())){
-                min = userCourseRecord.getCreateTime();
-            }
-            if (max == null || max.before(userCourseRecord.getCreateTime())){
-                max = userCourseRecord.getCreateTime();
-            }
+    public int computeCourseDay(UserOrderRecord record){
+        if(record.getUseEndTime() == null){
+            return 0;
         }
         int suspend = 0;
-//        if(record.getIsSuspend() > 0){
-//            if(record.getRestoreTime() != null){
-//
-//            }else{
-//                suspend = 0;
+        if(record.getIsSuspend() > 0){
+            if(record.getRestoreTime() == null){
+                suspend = (int)(Tools.day(new Date()).getTime() - Tools.day(record.getSuspendTime()).getTime())/86400000;
+            }else{
+                suspend = (int)(Tools.day(record.getRestoreTime()).getTime() - Tools.day(record.getSuspendTime()).getTime())/86400000;
+            }
+        }
+        if (record.getUseEndTime().before(new Date())){
+            return (int)(Tools.day(record.getUseEndTime()).getTime() - Tools.day(record.getUseStartTime()).getTime())/86400000 - suspend;
+        }else{
+            return (int)(Tools.day(new Date()).getTime() - Tools.day(record.getUseStartTime()).getTime())/86400000 - suspend;
+        }
+//        Date min = null;
+//        Date max = null;
+//        for(UserCourseRecord userCourseRecord:userCourseRecords){
+//            if(min==null || min.after(userCourseRecord.getCreateTime())){
+//                min = userCourseRecord.getCreateTime();
+//            }
+//            if (max == null || max.before(userCourseRecord.getCreateTime())){
+//                max = userCourseRecord.getCreateTime();
 //            }
 //        }
-        return (int)(Tools.day(max).getTime() - Tools.day(min).getTime()/86400000) - suspend;
+//        int suspend = 0;
+//        if (min == null) return 0;
+//        return (int)((Tools.day(max).getTime() - Tools.day(min).getTime())/86400000) - suspend;
     }
 
     /**

+ 26 - 21
server/gateway-api/src/main/java/com/qxgmat/service/extend/OrderFlowService.java

@@ -415,14 +415,14 @@ public class OrderFlowService {
             order.setMoney(money);
             order.setOriginMoney(originMoney);
             // 课程金额进行开票处理
-            order.setInvoiceMoney(courseMoney);
+            order.setInvoiceMoney(courseMoney.add(vsMoney));
         }));
 
         initRecordCallback.put(ProductType.COURSE, ((order, record) -> {
             Course course = courseService.get(record.getProductId());
 
             // 记录销售数量
-            courseService.accumulation(course.getId(), 0, record.getParentId() ==0 ? 1:0, record.getParentId() != 0 ? 1:0);
+            courseService.accumulation(course.getId(), 0, record.getParentId() == null || record.getProductId() ==0 ? 1:0, record.getParentId() != null && record.getProductId() != 0 ? 1:0);
 
             CourseModule courseModule = CourseModule.ValueOf(course.getCourseModule());
             // 小班课程不会存在记录,在线视频和1v1授课都有有效期
@@ -545,28 +545,31 @@ public class OrderFlowService {
                 // 设置结束有效期
                 endTime = Tools.addDate(startTime, expireDay);
             }
-            UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
-            if(userCourse == null){
-                userCourse = UserCourse.builder()
-                        .userId(record.getUserId())
-                        .courseId(course.getId())
-                        .recordId(record.getId())
-                        .startTime(startTime)
-                        .expireTime(endTime)
-                        .build();
-                userCourse = userCourseService.add(userCourse);
-            }else{
-                if (userCourse.getExpireTime().before(time)){
-                    // 已到期 - 续期
-                    userCourse.setStartTime(startTime);
-                    userCourse.setExpireTime(endTime);
-                    userCourse.setRecordId(record.getId());
+            if (course.getCourseModule().equals(CourseModule.VIDEO.key)){
+                UserCourse userCourse = userCourseService.getCourseBase(record.getUserId(), record.getProductId());
+                if(userCourse == null){
+                    userCourse = UserCourse.builder()
+                            .userId(record.getUserId())
+                            .courseId(course.getId())
+                            .recordId(record.getId())
+                            .startTime(startTime)
+                            .expireTime(endTime)
+                            .build();
+                    userCourse = userCourseService.add(userCourse);
                 }else{
-                    // 未到期 - 报错
-                    throw new ParameterException("已开通当前课程");
+                    if (userCourse.getExpireTime().before(time)){
+                        // 已到期 - 续期
+                        userCourse.setStartTime(startTime);
+                        userCourse.setExpireTime(endTime);
+                        userCourse.setRecordId(record.getId());
+                    }else{
+                        // 未到期 - 报错
+                        throw new ParameterException("已开通当前课程");
+                    }
+                    userCourse = userCourseService.edit(userCourse);
                 }
-                userCourse = userCourseService.edit(userCourse);
             }
+
             record.setUseStartTime(startTime);
             if (endTime!=null )record.setUseEndTime(endTime);
             return record;
@@ -915,6 +918,8 @@ public class OrderFlowService {
      */
     @Transactional
     public UserOrderRecord addRecord(UserOrderRecord record){
+        if (record.getExpireDays() == null) record.setExpireDays(0);
+        if (record.getUseExpireDays() == null) record.setUseExpireDays(0);
         InitRecord callback = initRecordCallback.get(ProductType.ValueOf(record.getProductType()));
         // 虚拟order
         callback.callback(UserOrder.builder().build(), record);

+ 34 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserInvoiceService.java

@@ -25,6 +25,40 @@ public class UserInvoiceService extends AbstractService {
     @Resource
     private UserInvoiceMapper userInvoiceMapper;
 
+    public UserInvoice getByOrder(Integer userId, Integer orderId){
+        Example example = new Example(UserInvoice.class);
+        if(userId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("userId", userId)
+            );
+        }
+        if(orderId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("orderId", orderId)
+            );
+        }
+        return one(userInvoiceMapper, example);
+    }
+
+    public List<UserInvoice> listByOrder(Integer userId, Collection orderIds){
+        Example example = new Example(UserInvoice.class);
+        if(userId != null){
+            example.and(
+                    example.createCriteria()
+                            .andEqualTo("userId", userId)
+            );
+        }
+        if(orderIds != null){
+            example.and(
+                    example.createCriteria()
+                            .andIn("orderId", orderIds)
+            );
+        }
+        return select(userInvoiceMapper, example);
+    }
+
     public Page<UserInvoice> listAdmin(int page, int size, Integer userId, Boolean isDownload, Boolean isFinish, String order, DirectionStatus direction){
         Example example = new Example(UserInvoice.class);
         if(userId != null){

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

@@ -51,6 +51,22 @@ public class UserOrderRecordService extends AbstractService {
     }
 
     /**
+     * 获取订单的所有记录
+     * @param userId
+     * @param orderIds
+     * @return
+     */
+    public List<UserOrderRecord> allByUser(Integer userId, Collection orderIds){
+        Example example = new Example(UserOrderRecord.class);
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("userId", userId)
+                        .andIn("orderId", orderIds)
+        );
+        return select(userOrderRecordMapper, example);
+    }
+
+    /**
      * 获取所有到期的未恢复记录
      * @param startTime
      * @param endTime

+ 13 - 0
server/gateway-api/src/main/java/com/qxgmat/service/inline/UserOrderService.java

@@ -36,6 +36,15 @@ public class UserOrderService extends AbstractService {
         put("", "uo");
     }};
 
+    /**
+     * 已支付列表
+     * @param page
+     * @param size
+     * @param userId
+     * @param order
+     * @param direction
+     * @return
+     */
     public Page<UserOrder> list(int page, int size, Integer userId, String order, DirectionStatus direction){
         Example example = new Example(UserOrder.class);
         if(userId != null){
@@ -44,6 +53,10 @@ public class UserOrderService extends AbstractService {
                             .andEqualTo("userId", userId)
             );
         }
+        example.and(
+                example.createCriteria()
+                        .andEqualTo("payStatus", 1)
+        );
 
         if(order == null || order.isEmpty()) order = "id";
         switch(direction){

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

@@ -283,7 +283,7 @@ public class ScheduledTask {
             List<UserCourseProgress> progressList = userCourseProgressService.listCourse(record.getId(), course.getId());
             List<UserCourseRecord> records = userCourseRecordService.allWithRecord(record.getId());
             Integer currentNo = courseExtendService.computeCourseNoCurrent(courseNoList, progressList);
-            Integer days = courseExtendService.computeCourseDay(record, records);
+            Integer days = courseExtendService.computeCourseDay(record);
             if (days/currentNo > 2){
                 continue;
             }