KaysonCui vor 5 Jahren
Ursprung
Commit
9cd37e3270

+ 33 - 0
front/project/www/app.less

@@ -274,6 +274,10 @@
   color: #A7A7A7 !important;
 }
 
+.t-7 {
+  color: #FF7C06 !important;
+}
+
 .b-c-1 {
   background: #F7F7F7;
 }
@@ -393,6 +397,35 @@ body,
       flex: 1;
     }
   }
+
+  .dot {
+    position: relative;
+  }
+
+  .dot::after {
+    content: '';
+    position: absolute;
+    left: -10px;
+    top: 10px;
+    width: 5px;
+    height: 5px;
+    border-radius: 50%;
+    background: rgba(252, 95, 95, 1);
+  }
+
+  .require {
+    position: relative;
+    margin-right: 10px;
+  }
+
+  .require::after {
+    content: '*';
+    position: absolute;
+    font-size: 14px;
+    right: -8px;
+    top: 0px;
+    color: #EC6413FF;
+  }
 }
 
 #root {}

BIN
front/project/www/assets/up - 副本.png


+ 36 - 23
front/project/www/components/UserTable/index.js

@@ -77,30 +77,16 @@ export default class UserTable extends Component {
           )}
 
           <tbody style={{ maxHeight }}>
-            {data.map(row => {
+            {data.map((row, i) => {
               const checked = selectList.indexOf(row[rowKey]) >= 0;
-              return (
-                <tr>
-                  {columns.map((item, i) => {
-                    return (
-                      <td
-                        className={`${item.className || ''} ${i === 0 && select ? 'check' : ''}`}
-                        width={item.width}
-                        align={item.align}
-                      >
-                        {i === 0 && select && (
-                          <CheckboxItem
-                            theme="white"
-                            checked={checked}
-                            onClick={value => this.onSelect(value, row[rowKey])}
-                          />
-                        )}
-                        {item.render ? item.render(row[item.key], row) : row[item.key]}
-                      </td>
-                    );
-                  })}
-                </tr>
-              );
+              const isEven = i % 2;
+              if (row.children) {
+                return [
+                  this.renderTr(row, checked, i, -1, isEven),
+                  ...row.children.map((item, index) => this.renderTr(item, checked, i, index, isEven)),
+                ];
+              }
+              return this.renderTr(row, checked, i, -1, isEven);
             })}
           </tbody>
         </table>
@@ -109,4 +95,31 @@ export default class UserTable extends Component {
       </div>
     );
   }
+
+  renderTr(row, checked, rowIndex, childIndex, isEven) {
+    const { columns } = this.props;
+    return (
+      <tr hidden={row.disabled} className={`${isEven ? 'even' : 'odd'}`}>
+        {columns.map((item, i) => {
+          return this.renderTd(row, checked, item, rowIndex, childIndex, i);
+        })}
+      </tr>
+    );
+  }
+
+  renderTd(row, checked, item, index, childIndex, columnIndex) {
+    const { select, rowKey } = this.props;
+    return (
+      <td
+        className={`${item.className || ''} ${columnIndex === 0 && select ? 'check' : ''}`}
+        width={item.width}
+        align={item.align}
+      >
+        {childIndex === -1 && columnIndex === 0 && select && (
+          <CheckboxItem theme="white" checked={checked} onClick={value => this.onSelect(value, row[rowKey])} />
+        )}
+        {item.render ? item.render(row[item.key], row, index, childIndex) : row[item.key]}
+      </td>
+    );
+  }
 }

+ 18 - 4
front/project/www/components/UserTable/index.less

@@ -6,6 +6,11 @@
     margin-bottom: 10px;
     line-height: 20px;
 
+    tbody {
+      overflow-y: auto;
+      background: #fff;
+    }
+
     .check {
       padding-left: 15px;
       text-align: left;
@@ -82,7 +87,6 @@
 
 .user-table.even {
   tbody {
-    overflow-y: auto;
 
     tr:nth-of-type(even) {
       background: #FBFBFB;
@@ -92,7 +96,6 @@
 
 .user-table.odd {
   tbody {
-    overflow-y: auto;
 
     tr:nth-of-type(odd) {
       background: #FBFBFB;
@@ -101,7 +104,18 @@
 }
 
 .user-table.dark {
-  tr {
-    background: #ECEDEE;
+  tbody {
+
+    tr {
+      background: #ECEDEE;
+    }
+  }
+}
+
+.user-table.children {
+  tbody {
+    tr.even {
+      background: #FBFBFB;
+    }
   }
 }

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

@@ -25,7 +25,11 @@ const columns = [
     render(text, row) {
       return row.group ? (
         <div className="group">
-          <Link to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}>{QuestionTypeMap[text]}</Link>
+          <Link
+            to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}
+          >
+            {QuestionTypeMap[text]}
+          </Link>
         </div>
       ) : (
         <div className="sub">{QuestionTypeMap[text]}</div>
@@ -39,12 +43,17 @@ const columns = [
     render(text, row) {
       return row.group ? (
         <div className="group">
-          <Link to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}>{text}</Link>
+          <Link
+            to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}
+          >
+            {text}
+          </Link>
+        </div>
+      ) : (
+        <div className="sub">
+          <div className="date">{text.split(' ')[0]}</div>
+          <div className="date">{text.split(' ')[1]}</div>
         </div>
-      ) : (<div className="sub">
-        <div className="date">{text.split(' ')[0]}</div>
-        <div className="date">{text.split(' ')[1]}</div>
-      </div>
       );
     },
   },
@@ -55,7 +64,11 @@ const columns = [
     render(text, row) {
       return row.group ? (
         <div className="group text-hidden">
-          <Link to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}>{text}</Link>
+          <Link
+            to={row.userQuestionId ? `/paper/question/${row.userQuestionId}` : `/question/detail/${row.questionNoId}`}
+          >
+            {text}
+          </Link>
         </div>
       ) : (
         <div className="sub">{text}</div>
@@ -148,7 +161,7 @@ export default class extends Page {
     this.search({ page });
   }
 
-  onAction() { }
+  onAction() {}
 
   onSelect(selectList) {
     this.setState({ selectList });
@@ -260,9 +273,11 @@ export default class extends Page {
                   <OpenText>{item.content}</OpenText>
                 </div>
                 {item.answerStatus > 0 && <div className="small-tag">回答</div>}
-                {item.answerStatus > 0 && <div className="desc">
-                  <OpenText>{item.answer}</OpenText>
-                </div>}
+                {item.answerStatus > 0 && (
+                  <div className="desc">
+                    <OpenText>{item.answer}</OpenText>
+                  </div>
+                )}
               </div>
             </div>
           );

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

@@ -1,7 +1,7 @@
 import React, { Component } from 'react';
 import { Link } from 'react-router-dom';
 import './index.less';
-import { Icon, Dropdown } from 'antd';
+import { Icon, Popover } from 'antd';
 import FileUpload from '@src/components/FileUpload';
 import Page from '@src/containers/Page';
 import Assets from '@src/components/Assets';
@@ -131,7 +131,7 @@ export default class extends Page {
     });
   }
 
-  onAction() { }
+  onAction() {}
 
   onTabChange(tab) {
     const data = { tab };
@@ -332,7 +332,13 @@ export default class extends Page {
           onChange={key => this.onStatusChange(key)}
         />
         {this[`renderTab${tab}`]()}
-        <Modal show={showTime} className="clock-modal" title="打卡表" width={460} onClose={() => this.setState({ showTime: false })}>
+        <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>
@@ -361,8 +367,8 @@ export default class extends Page {
           <DatePlane
             hideInput
             show={showTime}
-            onChange={() => { }}
-            disabledDate={(current) => {
+            onChange={() => {}}
+            disabledDate={current => {
               const date = current.format('YYYY-MM-DD');
               return data.stopTimeMap[date];
             }}
@@ -463,7 +469,9 @@ 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">{note.file ? `上传文件:${note.name} 成功` : '支持 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">放开文件立刻上传</span>
             </div>
@@ -471,11 +479,13 @@ export default class extends Page {
               type="none"
               onDragEnter={() => this.setState({ draging: true })}
               onDragLeave={() => this.setState({ draging: false })}
-              onUpload={({ file }) => Common.upload(file).then(result => {
-                note.file = result.url;
-                note.name = file.name;
-                this.setState({ note });
-              })}
+              onUpload={({ file }) => {
+                Common.upload(file).then(result => {
+                  note.file = result.url;
+                  note.name = file.name;
+                  this.setState({ note });
+                });
+              }}
             />
           </div>
           <div className="b-b m-t-2" />
@@ -524,7 +534,9 @@ 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">{supply.file ? `上传文件:${supply.name} 成功` : '支持 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">放开文件立刻上传</span>
             </div>
@@ -532,11 +544,13 @@ export default class extends Page {
               type="none"
               onDragEnter={() => this.setState({ draging: true })}
               onDragLeave={() => this.setState({ draging: false })}
-              onUpload={({ file }) => Common.upload(file).then(result => {
-                supply.file = result.url;
-                supply.name = file.name;
-                this.setState({ supply });
-              })}
+              onUpload={({ file }) => {
+                Common.upload(file).then(result => {
+                  supply.file = result.url;
+                  supply.name = file.name;
+                  this.setState({ supply });
+                });
+              }}
             />
           </div>
           <div className="b-b m-t-2" />
@@ -576,23 +590,44 @@ export default class extends Page {
   renderTabvs() {
     const { list = [] } = this.state;
     return list.map(item => {
-      return <CourseVs data={item} user={this.props.user} refreshDetail={(recordId) => {
-        this.refreshDetail(recordId);
-      }} onRestore={() => {
-        this.setState({ showRestore: true, restore: item });
-      }} onSuspend={() => {
-        this.setState({ showSuspend: true, suspend: item });
-      }} onComment={() => {
-        this.setState({ showComment: true, comment: { channel: 'course-vs', position: item.course.id } });
-      }} closeCommentTips={() => this.closeCommentTips(item.id)}
-        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)}
-        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)} />;
+      return (
+        <CourseVs
+          data={item}
+          user={this.props.user}
+          refreshDetail={recordId => {
+            this.refreshDetail(recordId);
+          }}
+          onRestore={() => {
+            this.setState({ showRestore: true, restore: item });
+          }}
+          onSuspend={() => {
+            this.setState({ showSuspend: true, suspend: item });
+          }}
+          onComment={() => {
+            this.setState({ showComment: true, comment: { channel: 'course-vs', position: item.course.id } });
+          }}
+          closeCommentTips={() => this.closeCommentTips(item.id)}
+          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)}
+          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)}
+        />
+      );
     });
   }
 }
@@ -611,38 +646,64 @@ class CourseOnline extends Component {
       {
         title: '预习作业',
         key: 'paper',
-        render: (text) => {
+        render: text => {
           const progress = text.report ? formatPercent(text.report.userNumber, text.report.questionNumber) : 0;
           const times = text.paper ? text.paper.times : 0;
-          return <div>
-            <div className="v-a-m d-i-b">
-              <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
+          return (
+            <div>
+              <div className="v-a-m d-i-b">
+                <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
+              </div>
+              {!text.report && (
+                <IconButton
+                  className="m-l-2"
+                  type="start"
+                  tip="Start"
+                  onClick={() => {
+                    User.needLogin().then(() => {
+                      Question.startLink('preview', text);
+                    });
+                  }}
+                />
+              )}
+              {text.report && !text.report.isFinish && (
+                <IconButton
+                  className="m-l-2"
+                  type="continue"
+                  tip="Continue"
+                  onClick={() => {
+                    User.needLogin().then(() => {
+                      Question.continueLink('preview', text);
+                    });
+                  }}
+                />
+              )}
+              {text.report && !!text.report.isFinish && (
+                <IconButton
+                  className="m-l-2"
+                  type="restart"
+                  tip="Restart"
+                  onClick={() => {
+                    User.needLogin().then(() => {
+                      Question.restart('preview', text);
+                    });
+                  }}
+                />
+              )}
+              {text.report && !!text.report.isFinish && (
+                <IconButton
+                  className="m-l-5"
+                  type="report"
+                  tip="Report"
+                  onClick={() => {
+                    User.needLogin().then(() => {
+                      Question.reportLink('preview', text);
+                    });
+                  }}
+                />
+              )}
             </div>
-            {!text.report && <IconButton className="m-l-2" type="start" tip="Start" onClick={() => {
-              User.needLogin()
-                .then(() => {
-                  Question.startLink('preview', text);
-                });
-            }} />}
-            {text.report && !text.report.isFinish && <IconButton className="m-l-2" type="continue" tip="Continue" onClick={() => {
-              User.needLogin()
-                .then(() => {
-                  Question.continueLink('preview', text);
-                });
-            }} />}
-            {text.report && !!text.report.isFinish && <IconButton className="m-l-2" type="restart" tip="Restart" onClick={() => {
-              User.needLogin()
-                .then(() => {
-                  Question.restart('preview', text);
-                });
-            }} />}
-            {text.report && !!text.report.isFinish && <IconButton className="m-l-5" type="report" tip="Report" onClick={() => {
-              User.needLogin()
-                .then(() => {
-                  Question.reportLink('preview', text);
-                });
-            }} />}
-          </div>;
+          );
         },
       },
       {
@@ -651,7 +712,8 @@ class CourseOnline extends Component {
         render: (text, record) => {
           const { paper = {} } = record;
           return `${paper.paper && paper.paper.times > 0 ? `${paper.paper.times}次+` : ''}${
-            paper.report ? formatPercent(paper.report.userNumber, paper.report.questionNumber, false) : '0%'}`;
+            paper.report ? formatPercent(paper.report.userNumber, paper.report.questionNumber, false) : '0%'
+          }`;
         },
       },
       {
@@ -845,7 +907,10 @@ class CourseOnline extends Component {
               <div className="t1">授课老师</div>
               <div className="t2">{data.course.teacher}</div>
               <div className="t1">有效期</div>
-              <div className="t-s-12">{formatDate(data.useStartTime, 'YYYY-MM-DD')}<br />至{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">
@@ -996,18 +1061,18 @@ const statusMap = {
     // if (new Date(appointment.endTime).getTime() > new Date()) return 'not';
     return '';
   },
-  4: (appointment) => {
+  4: appointment => {
     if (!appointment.noteList || appointment.noteList.length === 0) return 'not';
     return '';
   },
-  5: (appointment) => {
+  5: appointment => {
     if (!appointment.supplyList || appointment.supplyList.length === 0) return 'not';
     return '';
   },
   6: () => {
     return '';
   },
-  7: (appointment) => {
+  7: appointment => {
     const { paper = {} } = appointment;
     if (!paper.report || formatPercent(paper.report.userNumber, paper.report.questionNumber) < 100) return 'not';
     return '';
@@ -1022,38 +1087,64 @@ class CourseVs extends Component {
         {
           title: '预习作业',
           key: 'paper',
-          render: (text) => {
+          render: text => {
             const progress = text.report ? formatPercent(text.report.userNumber, text.report.questionNumber) : 0;
             const times = text.paper ? text.paper.times : 0;
-            return <div>
-              <div className="v-a-m d-i-b">
-                <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
+            return (
+              <div>
+                <div className="v-a-m d-i-b">
+                  <ProgressText width={50} size="small" times={times} progress={progress} unit="次" />
+                </div>
+                {!text.report && (
+                  <IconButton
+                    className="m-l-2"
+                    type="start"
+                    tip="Start"
+                    onClick={() => {
+                      User.needLogin().then(() => {
+                        Question.startLink('preview', text);
+                      });
+                    }}
+                  />
+                )}
+                {text.report && !text.report.isFinish && (
+                  <IconButton
+                    className="m-l-2"
+                    type="continue"
+                    tip="Continue"
+                    onClick={() => {
+                      User.needLogin().then(() => {
+                        Question.continueLink('preview', text);
+                      });
+                    }}
+                  />
+                )}
+                {text.report && !!text.report.isFinish && (
+                  <IconButton
+                    className="m-l-2"
+                    type="restart"
+                    tip="Restart"
+                    onClick={() => {
+                      User.needLogin().then(() => {
+                        Question.restart('preview', text);
+                      });
+                    }}
+                  />
+                )}
+                {text.report && !!text.report.isFinish && (
+                  <IconButton
+                    className="m-l-5"
+                    type="report"
+                    tip="Report"
+                    onClick={() => {
+                      User.needLogin().then(() => {
+                        Question.reportLink('preview', text);
+                      });
+                    }}
+                  />
+                )}
               </div>
-              {!text.report && <IconButton className="m-l-2" type="start" tip="Start" onClick={() => {
-                User.needLogin()
-                  .then(() => {
-                    Question.startLink('preview', text);
-                  });
-              }} />}
-              {text.report && !text.report.isFinish && <IconButton className="m-l-2" type="continue" tip="Continue" onClick={() => {
-                User.needLogin()
-                  .then(() => {
-                    Question.continueLink('preview', text);
-                  });
-              }} />}
-              {text.report && !!text.report.isFinish && <IconButton className="m-l-2" type="restart" tip="Restart" onClick={() => {
-                User.needLogin()
-                  .then(() => {
-                    Question.restart('preview', text);
-                  });
-              }} />}
-              {text.report && !!text.report.isFinish && <IconButton className="m-l-5" type="report" tip="Report" onClick={() => {
-                User.needLogin()
-                  .then(() => {
-                    Question.reportLink('preview', text);
-                  });
-              }} />}
-            </div>;
+            );
           },
         },
         {
@@ -1173,10 +1264,12 @@ class CourseVs extends Component {
             />
           </div>
         </div>
-        {showTips && <div className="continue">
-          <Icon className='close m-r-5 t-3' type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
-          课程已过半,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
-        </div>}
+        {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">
           <div className="left">
             <Assets name="sun_blue" src={data.course.cover} />
@@ -1205,16 +1298,18 @@ class CourseVs extends Component {
             <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
           </div>
         </div>
-        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
-          className="t-l"
-          type="line"
-          theme="theme"
-          size="small"
-          width={80}
-          active={tab}
-          tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
-          onChange={key => this.setState({ tab: key })}
-        />}
+        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && (
+          <Tabs
+            className="t-l"
+            type="line"
+            theme="theme"
+            size="small"
+            width={80}
+            active={tab}
+            tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
+            onChange={key => this.setState({ tab: key })}
+          />
+        )}
         {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
       </div>
     );
@@ -1289,10 +1384,12 @@ class CourseVs extends Component {
             />
           </div>
         </div>
-        {showTips && <div className="continue">
-          <Icon className='close m-r-5 t-3' type="close-circle" theme="filled" onClick={() => closeCommentTips()} />
-          课程已结束,可以来写写评价啦<a onClick={() => onComment()}>去写评价 ></a>
-        </div>}
+        {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">
           <div className="left">
             <Assets name="sun_blue" src={data.course.cover} />
@@ -1321,16 +1418,18 @@ class CourseVs extends Component {
             <GIcon name={open ? 'up' : 'down'} onClick={() => this.setState({ open: !open })} />
           </div>
         </div>
-        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && <Tabs
-          className="t-l"
-          type="line"
-          theme="theme"
-          size="small"
-          width={80}
-          active={tab}
-          tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
-          onChange={key => this.setState({ tab: key })}
-        />}
+        {open && (data.course.vsType === 'system' || data.course.vsType === 'answer') && (
+          <Tabs
+            className="t-l"
+            type="line"
+            theme="theme"
+            size="small"
+            width={80}
+            active={tab}
+            tabs={[{ key: 'ing', title: '授课中' }, { key: 'end', title: '已结课' }]}
+            onChange={key => this.setState({ tab: key })}
+          />
+        )}
         {open && (tab === 'ing' ? this.renderTimeLine() : this.renderTable())}
       </div>
     );
@@ -1404,13 +1503,22 @@ class CourseVs extends Component {
     let status = '';
     return [
       <div className="class-hour">
-        {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>}
+        {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 className="time-line">
         {list.map(item => {
@@ -1421,7 +1529,19 @@ class CourseVs extends Component {
             // 上一阶段未完成
             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>,
     ];
@@ -1430,7 +1550,9 @@ class CourseVs extends Component {
   renderTable() {
     const { data = {} } = this.props;
     const { appointments = [] } = data;
-    return <UserTable size="small" columns={this.columns[data.course.vsType]} data={appointments.filter(row => row.id)} />;
+    return (
+      <UserTable size="small" columns={this.columns[data.course.vsType]} data={appointments.filter(row => row.id)} />
+    );
   }
 }
 class TimeLineItem extends Component {
@@ -1482,11 +1604,11 @@ class TimeLineItem extends Component {
             return (
               <span>
                 请尽快与老师预约上课时间,老师微信:{data.teacher.wechat}扫码加微信{' '}
-                <Dropdown overlay={<Assets name="qrcode" src={data.teacher.qr} />}>
+                <Popover content={<Assets name="qrcode" src={data.teacher.qr} />}>
                   <span>
                     <Assets className="m-l-1" name="erweima" />
                   </span>
-                </Dropdown>
+                </Popover>
               </span>
             );
           default:
@@ -1502,9 +1624,15 @@ class TimeLineItem extends Component {
           case 'end':
             return <span className="link">点此上传</span>;
           case 'not':
-            return <FileUpload onUpload={(file) => {
-              return Common.upload({ file }).then((result => onUploadQuestion(appointment, result.url, file.name)));
-            }}><span className="link">点此上传</span></FileUpload>;
+            return (
+              <FileUpload
+                onUpload={file => {
+                  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">
@@ -1515,19 +1643,57 @@ class TimeLineItem extends Component {
       case '3':
         switch (status) {
           case 'end':
-            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>;
+            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 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>;
+            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>
@@ -1543,30 +1709,60 @@ class TimeLineItem extends Component {
           case 'end':
             return <span className="link">点此上传</span>;
           case 'not':
-            return <span className="link" onClick={() => onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>点此上传</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, { appointmentId: appointment.id, recordId: appointment.recordId })}>点此上传</span>
+                  <span
+                    className="link"
+                    onClick={() => {
+                      onUploadNote(appointment, { appointmentId: appointment.id, recordId: appointment.recordId });
+                    }}
+                  >
+                    点此上传
+                  </span>
                 </div>
                 <div className="note-list">
                   {appointment.noteList.map(row => {
-                    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);
-                          break;
-                        case 'delete':
-                          onDeleteNote(appointment, row);
-                          break;
-                        case 'reply':
-                          onUploadNote(appointment, { parentId: row.id, appointmentId: appointment.id, recordId: appointment.recordId });
-                          break;
-                        default:
-                      }
-                    }} />;
+                    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);
+                              break;
+                            case 'delete':
+                              onDeleteNote(appointment, row);
+                              break;
+                            case 'reply':
+                              onUploadNote(appointment, {
+                                parentId: row.id,
+                                appointmentId: appointment.id,
+                                recordId: appointment.recordId,
+                              });
+                              break;
+                            default:
+                          }
+                        }}
+                      />
+                    );
                   })}
                 </div>
               </div>
@@ -1577,29 +1773,60 @@ class TimeLineItem extends Component {
           case 'end':
             return <span className="link">写留言</span>;
           case 'not':
-            return <span className="link" onClick={() => onUploadSupply(appointment, { appointmentId: appointment.id, recordId: appointment.recordId })}>写留言</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, { appointmentId: appointment.id, recordId: appointment.recordId })}>写留言</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', label: '编辑' }, { key: 'delete', label: '删除' }] : null} onAction={(key) => {
-                      switch (key) {
-                        case 'edit':
-                          onUploadSupply(appointment, row);
-                          break;
-                        case 'delete':
-                          onDeleteSupply(appointment, row);
-                          break;
-                        case 'reply':
-                          onUploadSupply(appointment, { parentId: row.id, appointmentId: appointment.id, recordId: appointment.recordId });
-                          break;
-                        default:
-                      }
-                    }} />;
+                    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);
+                              break;
+                            case 'delete':
+                              onDeleteSupply(appointment, row);
+                              break;
+                            case 'reply':
+                              onUploadSupply(appointment, {
+                                parentId: row.id,
+                                appointmentId: appointment.id,
+                                recordId: appointment.recordId,
+                              });
+                              break;
+                            default:
+                          }
+                        }}
+                      />
+                    );
                   })}
                 </div>
               </div>

+ 0 - 11
front/project/www/routes/my/main/index.less

@@ -283,17 +283,6 @@
           font-size: 12px;
         }
 
-        .dot::after {
-          content: '';
-          position: absolute;
-          left: -10px;
-          top: 10px;
-          width: 5px;
-          height: 5px;
-          border-radius: 50%;
-          background: rgba(252, 95, 95, 1);
-        }
-
         .icon {
           position: absolute;
           right: 0;

+ 25 - 14
front/project/www/routes/my/order/page.js

@@ -41,7 +41,7 @@ const columns = [
         actionList.push({ key: 'invoice', label: '开发票' });
       }
       actionList.push({ key: 'detail', label: '订单详情' });
-      const onAction = (key) => {
+      const onAction = key => {
         switch (key) {
           case 'invoice':
             this.setState({ showInvoice: true, invoice: { orderId: record.id, money: record.invoiceMoney } });
@@ -54,18 +54,29 @@ const columns = [
       };
       let content = '';
       if (record.checkouts.length > 3) {
-        content = [<div className="flex-block">{formatTitle(record.checkouts[0])}<br />等{record.checkouts.length}个商品</div>];
+        content = [
+          <div className="flex-block">
+            {formatTitle(record.checkouts[0])}
+            <br />等{record.checkouts.length}个商品
+          </div>,
+        ];
       } else {
-        content = record.checkouts.map(row => {
-          return formatTitle(row);
-        }).join(<br />);
+        content = record.checkouts
+          .map(row => {
+            return formatTitle(row);
+          })
+          .join(<br />);
       }
-      return <div className="t-2">
-        <div className="flex-layout m-b-5">
-          {content}
-          <More actionList={actionList} onAction={onAction} ><IconButton type="more" /></More>
+      return (
+        <div className="t-2">
+          <div className="flex-layout m-b-5">
+            {content}
+            <More actionList={actionList} onAction={onAction}>
+              <IconButton type="more" />
+            </More>
+          </div>
         </div>
-      </div>;
+      );
     },
   },
   {
@@ -78,7 +89,7 @@ const columns = [
   {
     title: '付款方式',
     key: 'payMethod',
-    render: (text) => {
+    render: text => {
       return RecordSourceMap[text];
     },
   },
@@ -99,7 +110,7 @@ export default class extends Page {
 
   initState() {
     return {
-      list: [{}],
+      list: [],
     };
   }
 
@@ -141,7 +152,7 @@ export default class extends Page {
           total={total}
           current={page}
         />
-        <Modal title="开发票" width={630} btnType="link" confirmText="申请" onConfirm={() => { }} onCancel={() => { }}>
+        <Modal title="开发票" width={630} btnType="link" confirmText="申请" onConfirm={() => {}} onCancel={() => {}}>
           <div className="input-layout m-b-2 t-2 t-s-16">
             <div className="label m-r-5">发票类型:</div>
             <div className="input-block">
@@ -186,7 +197,7 @@ export default class extends Page {
             <div className="input-block">¥ 210010.0</div>
           </div>
         </Modal>
-        <Modal title="申请成功" width={630} confirmText="好的,知道了" btnAlign="center" onConfirm={() => { }}>
+        <Modal title="申请成功" width={630} confirmText="好的,知道了" btnAlign="center" onConfirm={() => {}}>
           <div className="t-2 t-s-18">
             <Icon className="t-5 m-r-5" type="check" />
             我们会在三个工作日内将电子发票发送至您的绑定邮箱:

+ 10 - 40
front/project/www/routes/my/report/index.less

@@ -27,10 +27,6 @@
         margin: 0;
         font-size: 12px;
 
-        th.select {
-          padding-left: 45px;
-        }
-
         th {
           color: #686872;
           font-weight: 500;
@@ -42,47 +38,21 @@
 
         td {
           padding: 20px 15px;
-          background: #FBFBFB;
-          border-bottom: 1px solid #eee;
-        }
-
-        .group {
-          display: inline-block;
-        }
-
-        .sub {
-          display: inline-block;
         }
       }
     }
+  }
+}
 
-    .answer-layout {
-      border-bottom: 1px solid #eee;
-      padding-top: 20px;
-      padding-left: 15px;
-
-      .title {
-        font-size: 14px;
-        line-height: 14px;
-        margin-bottom: 20px;
-        color: #303139;
-      }
+.user-report-history-overlay {
+  margin: -10px;
 
-      .small-tag {
-        display: inline-block;
-        height: 16px;
-        background: rgba(163, 207, 255, 1);
-        border-radius: 2px;
-        color: #fff;
-        line-height: 16px;
-        font-size: 10px;
-        padding: 0 9px;
-      }
+  tr {
+    padding: 0 3px;
+  }
 
-      .desc {
-        color: #303139;
-        margin-bottom: 20px;
-      }
-    }
+  td {
+    font-size: 12px;
+    padding: 3px 5px;
   }
 }

+ 160 - 66
front/project/www/routes/my/report/page.js

@@ -1,7 +1,9 @@
 import React from 'react';
 import './index.less';
+import { Tooltip, Popover, Checkbox } from 'antd';
 import Page from '@src/containers/Page';
 import { timeRange } from '@src/services/Tools';
+import Assets from '@src/components/Assets';
 import UserLayout from '../../../layouts/User';
 import UserAction from '../../../components/UserAction';
 import UserTable from '../../../components/UserTable';
@@ -11,25 +13,70 @@ import Tabs from '../../../components/Tabs';
 import { TimeRange } from '../../../../Constant';
 import { My } from '../../../stores/my';
 
-const columns = [
-  { key: 'title', title: '练习册名称', fixSort: true },
-  { key: 'create_time', title: '做题时间', fixSort: true },
-  { key: 'correct', title: '正确率', sort: true },
-  { key: 'time', title: '平均耗时', sort: true },
-  { key: 'progress', title: '完成度' },
-  {
-    key: 'report',
-    title: '报告',
-    render() {
-      return <IconButton type="report" tip="report" />;
-    },
-  },
-];
-
 export default class extends Page {
   constructor(props) {
     props.size = 10;
     super(props);
+    this.columns = [
+      { key: 'title', title: '练习册名称', fixSort: true },
+      {
+        key: 'create_time',
+        title: '做题时间',
+        fixSort: true,
+        render: (text, row, index) => {
+          return (
+            <div>
+              <div className="t-2">
+                2019-12-12
+                {row.children && (
+                  <Popover
+                    trigger="click"
+                    content={
+                      <table className="user-report-history-overlay">
+                        <tbody>
+                          {row.children.map((child, i) => {
+                            return (
+                              <tr>
+                                <td>{row.children.length - i}</td>
+                                <td>2019-12-12 13:13:13</td>
+                                <td>3/20</td>
+                                <td>
+                                  <Checkbox
+                                    checked={!child.disabled}
+                                    onChange={e => this.onChangeShowHistory(index, i, e.target.checked)}
+                                  />
+                                </td>
+                              </tr>
+                            );
+                          })}
+                        </tbody>
+                      </table>
+                    }
+                  >
+                    <Tooltip overlayClassName="gray" title="历史数据">
+                      <span>
+                        <Assets className="m-l-5" name="down_normal" />
+                      </span>
+                    </Tooltip>
+                  </Popover>
+                )}
+              </div>
+              <div className="t-6">13:13:13</div>
+            </div>
+          );
+        },
+      },
+      { key: 'correct', title: '正确率', sort: true },
+      { key: 'time', title: '平均耗时', sort: true },
+      { key: 'progress', title: '完成度' },
+      {
+        key: 'report',
+        title: '报告',
+        render() {
+          return <IconButton type="report" tip="report" />;
+        },
+      },
+    ];
   }
 
   initState() {
@@ -38,7 +85,7 @@ export default class extends Page {
       timerange: 'today',
       filterMap: {},
       sortMap: {},
-      data: [{}, {}],
+      list: [{ children: [{}, {}] }, {}, {}, {}],
       selectList: [],
       allChecked: false,
     };
@@ -57,35 +104,57 @@ export default class extends Page {
     switch (data.tab) {
       case 'error':
       case 'collect':
-        My.listReport(Object.assign({ origin: data.tab, startTime, endTime }, this.state.search, {
-          order: Object.keys(data.sortMap).map(key => {
-            return `${key} ${data.sortMap[key]}`;
-          }).join(','),
-        })).then(result => {
+        My.listReport(
+          Object.assign({ origin: data.tab, startTime, endTime }, this.state.search, {
+            order: Object.keys(data.sortMap)
+              .map(key => {
+                return `${key} ${data.sortMap[key]}`;
+              })
+              .join(','),
+          }),
+        ).then(result => {
           this.setState({ list: result.list, total: result.total, page: data.page });
         });
         break;
       case 'exercise':
       case 'examination':
       default:
-        refreshQuestionType(this, data.subject, data.questionType, { all: true, needSentence: true, allSubject: true })
-          .then(({ questionTypes, courseModules }) => {
-            return refreshStruct(this, data.tab, data.one, data.two, {
-              all: true, needPreview: true, needTextbook: true,
-            })
-              .then(({ structIds, latest, year }) => {
-                My.listReport(Object.assign({ module: data.tab, questionTypes, structIds, latest, year, courseModules, startTime, endTime }, this.state.search, {
-                  order: Object.keys(data.sortMap).map(key => {
-                    return `${key} ${data.sortMap[key]}`;
-                  }).join(','),
-                })).then(result => {
-                  this.setState({ list: result.list, total: result.total, page: data.page });
-                });
-              });
+        refreshQuestionType(this, data.subject, data.questionType, {
+          all: true,
+          needSentence: true,
+          allSubject: true,
+        }).then(({ questionTypes, courseModules }) => {
+          return refreshStruct(this, data.tab, data.one, data.two, {
+            all: true,
+            needPreview: true,
+            needTextbook: true,
+          }).then(({ structIds, latest, year }) => {
+            My.listReport(
+              Object.assign(
+                { module: data.tab, questionTypes, structIds, latest, year, courseModules, startTime, endTime },
+                this.state.search,
+                {
+                  order: Object.keys(data.sortMap)
+                    .map(key => {
+                      return `${key} ${data.sortMap[key]}`;
+                    })
+                    .join(','),
+                },
+              ),
+            ).then(result => {
+              this.setState({ list: result.list, total: result.total, page: data.page });
+            });
           });
+        });
     }
   }
 
+  onChangeShowHistory(index, childIndex, show) {
+    const { list } = this.state;
+    list[index].children[childIndex].disabled = !show;
+    this.setState({ list });
+  }
+
   onTabChange(tab) {
     const data = { tab };
     this.refreshQuery(data);
@@ -113,7 +182,16 @@ export default class extends Page {
   }
 
   renderTable() {
-    const { tab, questionSubjectSelect, questionSubjectMap = {}, oneSelect, twoSelectMap = {}, filterMap = {}, sortMap = {}, list = [] } = this.state;
+    const {
+      tab,
+      questionSubjectSelect,
+      questionSubjectMap = {},
+      oneSelect,
+      twoSelectMap = {},
+      filterMap = {},
+      sortMap = {},
+      list = [],
+    } = this.state;
     const { selectList = [], page, total } = this.state;
     return (
       <div className="table-layout">
@@ -125,45 +203,61 @@ export default class extends Page {
           space={2.5}
           width={100}
           active={tab}
-          tabs={[{ key: 'exercise', title: '练习' }, { key: 'examination', title: '模考' }, { key: 'error', title: '错误组卷' }, { key: 'collect', title: '收藏组卷' }]}
+          tabs={[
+            { key: 'exercise', title: '练习' },
+            { key: 'examination', title: '模考' },
+            { key: 'error', title: '错误组卷' },
+            { key: 'collect', title: '收藏组卷' },
+          ]}
           onChange={key => this.onTabChange(key)}
         />
         <UserAction
           search
-          selectList={[{
-            children: [{
-              key: 'subject',
-              placeholder: '学科',
-              select: questionSubjectSelect,
-            }, {
-              placeholder: '题型',
-              key: 'questionType',
-              be: 'subject',
-              selectMap: questionSubjectMap,
-            }],
-          }, {
-            label: '范围',
-            children: [{
-              key: 'one',
-              placeholder: '全部',
-              select: oneSelect,
-            }, {
-              key: 'two',
-              be: 'one',
-              placeholder: '全部',
-              selectMap: twoSelectMap,
-            }],
-          }, {
-            right: true,
-            key: 'timerange',
-            select: TimeRange,
-          }]}
+          selectList={[
+            {
+              children: [
+                {
+                  key: 'subject',
+                  placeholder: '学科',
+                  select: questionSubjectSelect,
+                },
+                {
+                  placeholder: '题型',
+                  key: 'questionType',
+                  be: 'subject',
+                  selectMap: questionSubjectMap,
+                },
+              ],
+            },
+            {
+              label: '范围',
+              children: [
+                {
+                  key: 'one',
+                  placeholder: '全部',
+                  select: oneSelect,
+                },
+                {
+                  key: 'two',
+                  be: 'one',
+                  placeholder: '全部',
+                  selectMap: twoSelectMap,
+                },
+              ],
+            },
+            {
+              right: true,
+              key: 'timerange',
+              select: TimeRange,
+            },
+          ]}
           filterMap={filterMap}
           onFilter={value => this.onFilter(value)}
           onChange={key => this.onChangeTab(key)}
         />
         <UserTable
-          columns={columns}
+          even="children"
+          columns={this.columns}
           sortMap={sortMap}
           data={list}
           current={page}