Browse Source

add card1

KaysonCui 5 years ago
parent
commit
45384e93f6

+ 34 - 0
front/project/h5/components/Item/index.js

@@ -0,0 +1,34 @@
+import React, { Component } from 'react';
+import './index.less';
+import Assets from '@src/components/Assets';
+
+export class FAQItem extends Component {
+  render() {
+    const { className = '', data = {} } = this.props;
+    return (
+      <div className={`g-faq-item ${className}`}>
+        <div className="g-faq-item-title">{data.title}</div>
+        <div className="g-faq-item-desc">{data.desc}</div>
+      </div>
+    );
+  }
+}
+export class CommentItem extends Component {
+  render() {
+    const { className = '', data = {} } = this.props;
+    return (
+      <div className={`g-comment-item ${className}`}>
+        <div className="g-comment-item-left">
+          <Assets name="d_b" src={data.avatar} />
+        </div>
+        <div className="g-comment-item-right">
+          <div className="g-comment-item-right-info">
+            <div className="g-comment-item-right-info-name">{data.name}</div>
+            <div className="g-comment-item-right-info-date">{data.date}</div>
+          </div>
+          <div className="g-comment-item-right-desc">{data.desc}</div>
+        </div>
+      </div>
+    );
+  }
+}

+ 58 - 0
front/project/h5/components/Item/index.less

@@ -0,0 +1,58 @@
+@import '../../app.less';
+
+.g-faq-item {
+  padding-top: 10px;
+  margin-bottom: 10px;
+
+  .g-faq-item-title {
+    color: #292929;
+    font-size: 12px;
+  }
+
+  .g-faq-item-desc {
+    color: #686872;
+    font-size: 12px;
+  }
+}
+
+.g-comment-item {
+  position: relative;
+
+  .g-comment-item-left {
+    position: absolute;
+    top: 5px;
+    width: 32px;
+    height: 32px;
+    overflow: hidden;
+    border-radius: 16px;
+  }
+
+  .g-comment-item-right {
+    padding: 10px 0;
+    margin-left: 40px;
+    border-bottom: 1px solid #eee;
+
+    .g-comment-item-right-info {
+      margin-bottom: 5px;
+
+      .g-comment-item-right-info-name {
+        color: #686872;
+        font-size: 12px;
+        display: inline-block;
+        line-height: 25px;
+      }
+
+      .g-comment-item-right-info-date {
+        float: right;
+        color: #A7A7B7;
+        font-size: 12px;
+        line-height: 25px;
+      }
+    }
+
+    .g-comment-item-right-desc {
+      color: #303036;
+      font-size: 12px;
+    }
+  }
+}

+ 17 - 8
front/project/h5/routes/product/dataDetail/page.js

@@ -10,6 +10,7 @@ import Tag from '../../../components/Tag';
 import { Course } from '../../../stores/course';
 import { Order } from '../../../stores/order';
 import { DataType } from '../../../../Constant';
+import { FAQItem, CommentItem } from '../../../components/Item';
 
 const DataTypeMap = getMap(DataType, 'value', 'label');
 
@@ -20,10 +21,9 @@ export default class extends Page {
 
   initData() {
     const { id } = this.state;
-    Course.getData(id)
-      .then((data) => {
-        this.setState({ data });
-      });
+    Course.getData(id).then(data => {
+      this.setState({ data });
+    });
   }
 
   buy() {
@@ -58,18 +58,27 @@ export default class extends Page {
             { title: 'FAQs', key: 'faq' },
             { title: '用户评价', key: 'comment' },
           ]}
-          onChange={(value) => {
+          onChange={value => {
             this.setState({ tab: value.key });
           }}
         />
         <div dangerouslySetInnerHTML={{ __html: data[tab] }} />
+        <FAQItem data={{ title: '123', desc: '12312312321321' }} />
+        <FAQItem data={{ title: '123', desc: '12312312321321' }} />
+        <CommentItem data={{ name: '123', desc: '12312312321', date: '1231231231' }} />
+        <CommentItem data={{ name: '123', desc: '12312312321', date: '1231231231' }} />
         <div className="fixed">
           <div className="fee">
             总额: <Money value={data.price} size="lager" />
           </div>
-          <Button width={110} className="f-r" radius onClick={() => {
-            this.buy();
-          }}>
+          <Button
+            width={110}
+            className="f-r"
+            radius
+            onClick={() => {
+              this.buy();
+            }}
+          >
             立即购买
           </Button>
         </div>

+ 2 - 3
front/project/www/components/Button/index.less

@@ -22,9 +22,8 @@
 }
 
 .button.lager {
-  font-size: 18px;
-  font-weight: 600;
-  line-height: 28px;
+  font-size: 14px;
+  line-height: 24px;
   padding: 8px 16px;
 }
 

+ 133 - 0
front/project/www/components/Card/index.js

@@ -2,6 +2,7 @@ import React, { Component } from 'react';
 import './index.less';
 import { Link } from 'react-router-dom';
 import { Checkbox } from 'antd';
+import Assets from '@src/components/Assets';
 import Module from '../Module';
 import Progress from '../Progress';
 import IconButton from '../IconButton';
@@ -120,3 +121,135 @@ export default class Card extends Component {
     );
   }
 }
+
+export class Card1 extends Component {
+  getEndBody() {
+    return (
+      <div className="body">
+        <div className="text">
+          <div className="t-1">课程已经结束啦</div>
+        </div>
+      </div>
+    );
+  }
+
+  getStopBody() {
+    return (
+      <div className="body">
+        <div className="text">
+          <div className="t-1">停课中</div>
+          <div className="t-2">您可至「我的-课程」恢复学习</div>
+        </div>
+      </div>
+    );
+  }
+
+  getOpenBody() {
+    const { data } = this.props;
+    const { qrCode } = data;
+    return !qrCode ? (
+      <div className="body">
+        <div className="text">
+          <Checkbox />
+          <span>
+            我已阅读并同意<Link to="">《千行课程协议》</Link>
+          </span>
+        </div>
+        <div className="btn">
+          <Button size="lager" radius>
+            开通作业
+          </Button>
+        </div>
+      </div>
+    ) : (
+      <div className="body">
+        <div className="t-1">请尽快与老师预约上课时间</div>
+        <div className="t-2">请于 2019-07-25 前开通课程</div>
+        <div className="qr-code">
+          <Assets name="qrcode" />
+        </div>
+      </div>
+    );
+  }
+
+  getIngBody() {
+    const { data, previewAction } = this.props;
+    const { list = [] } = data;
+    return (
+      <div className="body">
+        {list.length > 0 && <div className="title">近期待完成</div>}
+        {list.length === 0 ? (
+          <div className="text">
+            <div className="t-1">好棒!</div>
+            <div className="t-2">近期的作业都完成啦</div>
+          </div>
+        ) : (
+          <div className="list">
+            {list.map(item => {
+              return (
+                <div className="item">
+                  <div className="top">
+                    <div className="title">{item.title}</div>
+                  </div>
+                  <div className="detail">
+                    <Progress size="small" progress={item.progress} />
+                    <div className="action">
+                      {item.status === 'start' && (
+                        <IconButton
+                          type="start"
+                          tip="Start"
+                          onClick={() => previewAction && previewAction('start', item)}
+                        />
+                      )}
+                      {item.status === 'continue' && (
+                        <IconButton
+                          type="continue"
+                          onClick={() => previewAction && previewAction('continue', item)}
+                          tip="Continue"
+                        />
+                      )}
+                      {item.status === 'restart' && (
+                        <IconButton
+                          type="restart"
+                          onClick={() => previewAction && previewAction('restart', item)}
+                          tip="Restart"
+                        />
+                      )}
+                    </div>
+                  </div>
+                </div>
+              );
+            })}
+          </div>
+        )}
+        <div className="bottom">
+          有效期: 2019-08-20至2020-01-01 <Link to="">全部作业></Link>
+        </div>
+      </div>
+    );
+  }
+
+  getBody() {
+    const { data } = this.props;
+    const { status } = data;
+    if (status === 'end') return this.getEndBody();
+    if (status === 'stop') return this.getStopBody();
+    if (status === 'open') return this.getOpenBody();
+    if (status === 'ing') return this.getIngBody();
+    return <div />;
+  }
+
+  render() {
+    const { style, data, title, tag } = this.props;
+    const { status } = data;
+    return (
+      <Module style={style} className={`card1 ${status}`}>
+        <div className="header">
+          {tag && <div className="tag">{tag}</div>}
+          {title}
+        </div>
+        {this.getBody()}
+      </Module>
+    );
+  }
+}

+ 183 - 0
front/project/www/components/Card/index.less

@@ -129,4 +129,187 @@
   .header {
     background: #c8d1da;
   }
+}
+
+.module.card1 {
+  min-height: 314px;
+  position: relative;
+
+  .header {
+    text-align: center;
+
+    .tag {
+      vertical-align: top;
+      margin-top: 12px;
+      display: inline-block;
+      padding: 0 7px;
+      background: #6865FD;
+      height: 18px;
+      line-height: 18px;
+      margin-right: 5px;
+      font-size: 10px;
+      color: #fff;
+      border-radius: 8px;
+    }
+  }
+
+  .header {
+    color: @night-blue;
+    background: @theme_bg_color;
+    font-size: 18px;
+    height: 44px;
+    line-height: 44px;
+    padding-left: 36px;
+    padding-right: 32px;
+  }
+
+  .body {
+    padding: 24px;
+  }
+}
+
+.module.card1.open {
+  .header {
+    .sub-title {
+      color: @holder_color;
+    }
+  }
+
+  .body {
+    .t-1 {
+      margin-top: 20px;
+      font-size: 16px;
+      color: #5E677B;
+      text-align: center;
+    }
+
+    .t-2 {
+      font-size: 12px;
+      color: #8897A8;
+      text-align: center;
+      margin-bottom: 20px;
+    }
+
+    .qr-code {
+      text-align: center;
+    }
+
+    .text {
+      margin-top: 50px;
+      line-height: 25px;
+      padding-left: 30px;
+      padding-right: 5px;
+      position: relative;
+      font-size: 12px;
+      margin-bottom: 30px;
+
+      .ant-checkbox-wrapper {
+        margin-right: 2px;
+      }
+    }
+
+    .btn {
+      margin: 0 auto;
+      width: 110px;
+      text-align: center;
+
+      .button {
+        width: 110px;
+        display: inline-block;
+      }
+    }
+  }
+}
+
+.module.card1.ing {
+  .body {
+    .text {
+      padding-top: 50px;
+      padding-left: 100px;
+
+      .t-1 {
+        font-size: 20px;
+        color: #5E677B;
+      }
+
+      .t-2 {
+        font-size: 14p;
+        color: #5E677B;
+      }
+    }
+
+    .title {
+      margin-bottom: 10px;
+      font-size: 14px;
+      color: #5E677B;
+    }
+
+    .list {
+      .item {
+        margin-bottom: 15px;
+
+        .top {
+
+          .title {
+            color: #050930;
+            font-size: 16px;
+          }
+        }
+
+        .detail {
+          height: 25px;
+          line-height: 25px;
+
+          .progress {
+            display: inline-block;
+            width: 160px;
+          }
+
+          .action {
+            display: inline-block;
+
+            .icon-button {
+              margin-left: 22px;
+            }
+          }
+        }
+      }
+    }
+
+    .bottom {
+      color: #8897A8;
+      font-size: 12px;
+      position: absolute;
+      bottom: 20px;
+    }
+  }
+}
+
+.module.card1.end {
+  .text {
+    padding-top: 70px;
+    text-align: center;
+
+    .t-1 {
+      font-size: 20px;
+      color: #5E677B;
+    }
+  }
+}
+
+.module.card1.stop {
+  .text {
+    padding-top: 50px;
+    text-align: center;
+
+    .t-1 {
+      font-size: 20px;
+      color: #5E677B;
+    }
+
+    .t-2 {
+      font-size: 14p;
+      color: #5E677B;
+    }
+  }
 }

+ 12 - 2
front/project/www/components/Login/index.js

@@ -16,7 +16,17 @@ const BIND_WX_ERROR = 'BIND_WX_ERROR';
 export default class Login extends Component {
   constructor(props) {
     super(props);
-    this.state = { type: LOGIN_PHONE };
+    this.state = { type: LOGIN_WX };
+    window.addEventListener(
+      'message',
+      event => {
+        if (typeof event.data === 'string' && event.data.indexOf('code:') === 0) {
+          const code = event.data.split(':')[1];
+          console.log(code);
+        }
+      },
+      false,
+    );
   }
 
   close() {
@@ -99,7 +109,7 @@ export default class Login extends Component {
       <div className="body">
         <div className="title">微信扫码登录</div>
         <div className="qr-code">
-          <Assets name="qrcode" />
+          <iframe frameBorder="0" src="/login.html" width="300" height="300" />
           <div className="text">请使用微信扫描二维码登录</div>
         </div>
         <Tooltip overlayClassName="gray" placement="left" title="手机号登录">

+ 45 - 3
front/project/www/components/QAList/index.js

@@ -1,8 +1,49 @@
-import React from 'react';
+import React, { Component } from 'react';
 import './index.less';
 import Module from '../Module';
 import Tabs from '../Tabs';
-import OtherAnswer from '../OtherAnswer';
+import Icon from '../Icon';
+
+class QAItem extends Component {
+  constructor(props) {
+    super(props);
+    this.Text = null;
+    this.state = { show: false, more: false };
+    this.checkHeight();
+  }
+
+  checkHeight() {
+    if (this.Text != null) {
+      if (this.Text.offsetHeight > 80) {
+        this.setState({ more: true });
+      }
+    } else {
+      setTimeout(() => {
+        this.checkHeight();
+      }, 1);
+    }
+  }
+
+  render() {
+    const { data } = this.props;
+    const { show, more } = this.state;
+    return (
+      <div className={`qa-item ${more ? 'more' : ''} ${!show ? 'hide' : ''}`}>
+        <div className="title">Q: {data.content}</div>
+        <div
+          ref={ref => {
+            this.Text = ref;
+          }}
+          className="desc"
+        >
+          A: {data.answer}
+        </div>
+        {more && show && <Icon name="up" onClick={() => this.setState({ show: false })} />}
+        {more && !show && <Icon name="down" onClick={() => this.setState({ show: true })} />}
+      </div>
+    );
+  }
+}
 
 function QAList(props) {
   const { style, data = [] } = props;
@@ -16,10 +57,11 @@ function QAList(props) {
         tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
       />
       {data.map(item => {
-        return <OtherAnswer data={item} />;
+        return <QAItem data={item} />;
       })}
     </Module>
   );
 }
+
 QAList.propTypes = {};
 export default QAList;

+ 51 - 0
front/project/www/components/QAList/index.less

@@ -6,4 +6,55 @@
   .tabs {
     border-bottom: 1px solid #eee;
   }
+
+  .qa-item {
+    border-bottom: 1px solid rgba(239, 243, 247, 1);
+    position: relative;
+
+    .title {
+      color: #303036;
+      font-size: 16px;
+      margin-bottom: 10px;
+    }
+
+    .small-tag {
+      display: inline-block;
+      background: rgb(172, 206, 251);
+      padding: 0 5px;
+      border-radius: 5px;
+      color: #fff;
+      margin-bottom: 5px;
+      font-size: 10px;
+    }
+
+    .desc {
+      color: #686872;
+      font-size: 16px;
+      margin-bottom: 20px;
+      overflow: hidden;
+    }
+
+    .icon {
+      position: absolute;
+      bottom: -18px;
+      left: 50%;
+      transform: translateX(-50%);
+      display: none;
+    }
+  }
+
+  .other-answer.more.hide {
+    .desc {
+      height: 80px;
+      background: linear-gradient(360deg, rgba(161, 161, 171, 0) 0%, rgba(104, 104, 114, 1) 100%);
+      -webkit-background-clip: text;
+      -webkit-text-fill-color: transparent;
+    }
+  }
+
+  .other-answer.more:hover {
+    .icon {
+      display: block;
+    }
+  }
 }

+ 6 - 4
front/project/www/components/Tabs/index.js

@@ -16,12 +16,14 @@ function getItem(props, item, onChange) {
 }
 
 function Tabs(props) {
-  const { tabs = [], type = 'line', theme = 'default', border, onChange } = props;
+  const { tabs = [], type = 'line', theme = 'default', border, space, onChange } = props;
   return (
     <div className={`tabs ${type} ${theme} ${border ? 'border' : ''}`}>
-      {tabs.map(item => {
-        return item.path ? <Link to={item.path}>{getItem(props, item)}</Link> : getItem(props, item, onChange);
-      })}
+      <div className="tabs-warpper" style={{ marginLeft: space * -1 || '', marginRight: space * -1 || '' }}>
+        {tabs.map(item => {
+          return item.path ? <Link to={item.path}>{getItem(props, item)}</Link> : getItem(props, item, onChange);
+        })}
+      </div>
     </div>
   );
 }

+ 39 - 6
front/project/www/components/Tabs/index.less

@@ -44,15 +44,18 @@
 }
 
 .tabs.card {
-  display: flex;
   text-align: center;
   height: 44px;
   line-height: 44px;
   background: @theme_bg_color;
 
-  a {
-    display: inline-block;
-    flex: 1;
+  .tabs-warpper {
+    display: flex;
+
+    a {
+      display: inline-block;
+      flex: 1;
+    }
   }
 
   .tab {
@@ -87,6 +90,34 @@
   }
 }
 
+.tabs.tag {
+  height: 24px;
+  line-height: 24px;
+
+  .tabs-warpper {
+
+    a {
+      display: inline-block;
+    }
+  }
+
+  .tab {
+    padding: 0 20px;
+    display: inline-block;
+    position: relative;
+    text-align: center;
+    color: #fff;
+    cursor: pointer;
+    background: #B9C1C9;
+    border-radius: 12px;
+  }
+
+  .tab:hover,
+  .tab.active {
+    background: @theme_color;
+  }
+}
+
 .tabs.text {
   height: 44px;
   line-height: 44px;
@@ -126,11 +157,13 @@
 
 .tabs.division {
 
-  display: flex;
   text-align: center;
   height: 44px;
   line-height: 44px;
-  margin: 0 -5px;
+
+  .tabs-warpper {
+    display: flex;
+  }
 
   a {
     display: inline-block;

+ 32 - 1
front/project/www/routes/page/demo/page.js

@@ -6,7 +6,7 @@ import Tabs from '../../../components/Tabs';
 import Module from '../../../components/Module';
 import Division from '../../../components/Division';
 import Panel, { TotalPanel, WaitPanel, BuyPanel } from '../../../components/Panel';
-import Card from '../../../components/Card';
+import Card, { Card1 } from '../../../components/Card';
 import List from '../../../components/List';
 import ListTable from '../../../components/ListTable';
 import ProgressText from '../../../components/ProgressText';
@@ -31,6 +31,19 @@ export default class extends Page {
             <BuyPanel title="千行 CAT" />
           </Division>
           <QAList data={[]} />
+          <Tabs
+            type="tag"
+            active="main"
+            space={5}
+            tabs={[
+              { key: 'main', name: '首页', path: '/' },
+              { key: 'ready', name: 'GetReady', path: '/' },
+              { key: 'exercise', name: '练习', path: '/' },
+              { key: 'cat', name: 'CAT模考', path: '/' },
+              { key: 'item', name: '题库', path: '/' },
+              { key: 'machine', name: '换库&机经', path: '/' },
+            ]}
+          />
           <Module className="m-t-2">
             <Tabs
               type="card"
@@ -108,6 +121,24 @@ export default class extends Page {
             />
           </Division>
           <Division col="3">
+            <Card1 title="句改 SC" data={{ status: 'open', qrCode: '123' }} />
+            <Card1 title="句改 SC" tag="视频课程" data={{ status: 'stop' }} />
+            <Card1 title="句改 SC" tag="视频课程" data={{ status: 'open' }} />
+            <Card1
+              title="句改 SC"
+              tag="视频课程"
+              data={{
+                status: 'ing',
+                list: [
+                  { progress: 30, title: '课时5:掌握语法结构', status: 'start' },
+                  { progress: 40, title: '课时5:掌握语法结构', status: 'ing' },
+                ],
+              }}
+            />
+            <Card1 title="句改 SC" tag="视频课程" data={{ status: 'ing', list: [] }} />
+            <Card1 title="句改 SC" tag="视频课程" data={{ status: 'end' }} />
+          </Division>
+          <Division col="3">
             <Card title="句改 SC" data={{ status: 'buy', desc: ['名师讲解', '精进学习', '提升成绩'] }} />
             <Card title="句改 SC" data={{ status: 'open' }} />
             <Card

+ 83 - 64
front/project/www/routes/paper/process/sentence/index.js

@@ -91,17 +91,17 @@ export default class extends Component {
     const show = !!answer;
     answer = answer || {};
     userAnswer = userAnswer || {};
-    Object.keys(userAnswer).forEach((key) => {
+    Object.keys(userAnswer).forEach(key => {
       if (key === 'options') return;
       const u = userAnswer[key];
       const a = answer[key] && answer[key].length > 0 ? answer[key][0] : [];
       const map = {};
-      a.forEach((row) => {
+      a.forEach(row => {
         if (!uuidMap[row.uuid]) uuidMap[row.uuid] = [];
         uuidMap[row.uuid].push('true');
         map[row.uuid] = row;
       });
-      u.forEach((row) => {
+      u.forEach(row => {
         if (!uuidMap[row.uuid]) uuidMap[row.uuid] = [];
         uuidMap[row.uuid].push('user');
         if (show && !map[row.uuid]) uuidMap[row.uuid].push('false');
@@ -116,32 +116,44 @@ export default class extends Component {
   render() {
     const { flow, paper, userQuestion, singleTime } = this.props;
     return (
-      <div id='paper-process-sentence'>
+      <div id="paper-process-sentence">
         <div className="layout">
           <div className="layout-header">
             <div className="left">
               <div className="title">{paper.title}</div>
             </div>
             <div className="right">
-              <div className="text"><Assets name='timecost_icon' />Time cost {formatSecond(userQuestion.userTime || singleTime)}</div>
+              <div className="text">
+                <Assets name="timecost_icon" />
+                Time cost {formatSecond(userQuestion.userTime || singleTime)}
+              </div>
               <Icon name="star" active={userQuestion.collect} onClick={() => flow.toggleCollect()} />
             </div>
           </div>
           {this.renderBody()}
           <div className="layout-footer">
             <div className="left">
-              <Icon name={this.props.isFullscreenEnabled ? 'sceen-restore' : 'sceen-full'} onClick={() => flow.toggleFullscreen()} />
+              <Icon
+                name={this.props.isFullscreenEnabled ? 'sceen-restore' : 'sceen-full'}
+                onClick={() => flow.toggleFullscreen()}
+              />
             </div>
             <div className="center">
               <div className="p">
                 <Progress theme="theme" progress={formatPercent(userQuestion.no, paper.questionNumber)} />
               </div>
-              <div className="t">{userQuestion.no}/{paper.questionNumber}</div>
+              <div className="t">
+                {userQuestion.no}/{paper.questionNumber}
+              </div>
             </div>
             <div className="right">
-              <Button size="lager" radius onClick={() => {
-                this.next();
-              }}>
+              <Button
+                size="lager"
+                radius
+                onClick={() => {
+                  this.next();
+                }}
+              >
                 Next <Assets name="next_icon" />
               </Button>
             </div>
@@ -167,10 +179,17 @@ export default class extends Component {
     const { focusKey, answer = {}, stem } = this.state;
     return (
       <div className="layout-body">
-        <div className="title"><Icon name="question" />请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。</div>
-        <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} onClick={(e) => {
-          this.addTarget(e.target);
-        }} />
+        <div className="title">
+          <Icon name="question" />
+          请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。
+        </div>
+        <div
+          className="desc"
+          dangerouslySetInnerHTML={{ __html: stem }}
+          onClick={e => {
+            this.addTarget(e.target);
+          }}
+        />
         <div className="label">主语</div>
         <div className="input">
           <HardInput
@@ -179,7 +198,7 @@ export default class extends Component {
             onClick={() => {
               this.setState({ focusKey: 'subject' });
             }}
-            onDelete={(item) => {
+            onDelete={item => {
               this.removeTarget('subject', item);
             }}
           />
@@ -192,7 +211,7 @@ export default class extends Component {
             onClick={() => {
               this.setState({ focusKey: 'predicate' });
             }}
-            onDelete={(item) => {
+            onDelete={item => {
               this.removeTarget('predicate', item);
             }}
           />
@@ -205,17 +224,21 @@ export default class extends Component {
             onClick={() => {
               this.setState({ focusKey: 'object' });
             }}
-            onDelete={(item) => {
+            onDelete={item => {
               this.removeTarget('object', item);
             }}
           />
         </div>
         <div className="select">
           <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
-          <AnswerCheckbox list={SentenceOption} selected={answer.options} onChange={(values) => {
-            answer.options = values;
-            this.setState({ answer });
-          }} />
+          <AnswerCheckbox
+            list={SentenceOption}
+            selected={answer.options}
+            onChange={values => {
+              answer.options = values;
+              this.setState({ answer });
+            }}
+          />
         </div>
       </div>
     );
@@ -225,49 +248,43 @@ export default class extends Component {
     const { analysisTab, question, userQuestion, stem } = this.state;
     const { userAnswer = {} } = userQuestion;
     const { answer } = question;
-    return <div className="layout-body">
-      <div className="title"><Icon name="question" />请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。</div>
-      <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} />
-      <div className="label">主语</div>
-      <div className="input">
-        <HardInput
-          show
-          list={userAnswer.subject || []}
-          answer={answer.subject}
-        />
-      </div>
-      <div className="label">谓语</div>
-      <div className="input">
-        <HardInput
-          show
-          list={userAnswer.predicate || []}
-          answer={answer.predicate}
-        />
-      </div>
-      <div className="label">宾语</div>
-      <div className="input">
-        <HardInput
-          show
-          list={userAnswer.object || []}
-          answer={answer.object}
-        />
-      </div>
-      <div className="select">
-        <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
-        <AnswerCheckbox show list={SentenceOption} selected={userAnswer.options} answer={answer.options} />
-      </div>
-      <div className="analysis">
-        <Tabs
-          type="division"
-          active={analysisTab}
-          tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
-          onChange={(key) => {
-            this.setState({ analysisTab: key });
-          }}
-        />
-        {this.renderText()}
+    return (
+      <div className="layout-body">
+        <div className="title">
+          <Icon name="question" />
+          请分别找出句子中的主语,谓语和宾语,并做出逻辑关系判断。
+        </div>
+        <div className="desc" dangerouslySetInnerHTML={{ __html: stem }} />
+        <div className="label">主语</div>
+        <div className="input">
+          <HardInput show list={userAnswer.subject || []} answer={answer.subject} />
+        </div>
+        <div className="label">谓语</div>
+        <div className="input">
+          <HardInput show list={userAnswer.predicate || []} answer={answer.predicate} />
+        </div>
+        <div className="label">宾语</div>
+        <div className="input">
+          <HardInput show list={userAnswer.object || []} answer={answer.object} />
+        </div>
+        <div className="select">
+          <div className="select-title">本句存在以下哪种逻辑关系?(可多选)</div>
+          <AnswerCheckbox show list={SentenceOption} selected={userAnswer.options} answer={answer.options} />
+        </div>
+        <div className="analysis">
+          <Tabs
+            type="division"
+            active={analysisTab}
+            space={3}
+            tabs={[{ key: 'qx', name: '解析详情' }, { key: 'chinese', name: '中文语意' }]}
+            onChange={key => {
+              this.setState({ analysisTab: key });
+            }}
+          />
+          {this.renderText()}
+        </div>
       </div>
-    </div>;
+    );
   }
 
   renderText() {
@@ -275,7 +292,9 @@ export default class extends Component {
     let content;
     switch (analysisTab) {
       case 'chinese':
-        content = <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: questionNo.chineseContent }} />;
+        content = (
+          <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: questionNo.chineseContent }} />
+        );
         break;
       case 'qx':
         content = <div className="detail-block text-block" dangerouslySetInnerHTML={{ __html: question.qxContent }} />;

+ 0 - 5
front/project/www/routes/paper/process/sentence/index.less

@@ -156,11 +156,6 @@
 
       .tabs {
         width: 320px;
-        margin: 0 -2px;
-
-        .tab {
-          margin: 0 2px;
-        }
 
         .tab.active,
         .tab:hover {

+ 0 - 8
front/project/www/routes/paper/question/index.less

@@ -235,14 +235,6 @@
           display: flex;
           flex-direction: column;
 
-          .tabs.division {
-            margin: 0 -2px;
-
-            .tab {
-              margin: 0 2px;
-            }
-          }
-
           .block-answer {
             padding: 38px 50px;
           }

+ 1 - 0
front/project/www/routes/paper/question/page.js

@@ -321,6 +321,7 @@ export default class extends Page {
         <Tabs
           type="division"
           active={analysisTab}
+          space={2}
           tabs={[
             { key: 'official', name: '官方解析' },
             { key: 'qx', name: '千行解析' },

+ 210 - 0
front/project/www/static/login.html

@@ -0,0 +1,210 @@
+<!DOCTYPE html>
+<html lang="zh">
+  <head>
+    <meta charset="utf-8" />
+    <script src="http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js"></script>
+  </head>
+  <style type="text/css">
+    body {
+      margin: 0;
+      overflow: hidden;
+      width: 300px;
+    }
+    #root {
+      overflow: hidden;
+      margin-top: -45px;
+      height: 350px;
+    }
+    .loading-bg {
+      background: #fff;
+      position: fixed;
+      top: 0;
+      left: 0;
+      right: 0;
+      bottom: 0;
+      z-index: 1;
+      opacity: 0.9;
+    }
+    .page-loading-warp {
+      padding: 130px;
+      display: flex;
+      justify-content: center;
+      align-items: center;
+      position: absolute;
+      top: 0;
+      left: 0;
+      position: fixed;
+      z-index: 2;
+    }
+    .ant-spin {
+      -webkit-box-sizing: border-box;
+      box-sizing: border-box;
+      margin: 0;
+      padding: 0;
+      color: rgba(0, 0, 0, 0.65);
+      font-size: 14px;
+      font-variant: tabular-nums;
+      line-height: 1.5;
+      list-style: none;
+      -webkit-font-feature-settings: 'tnum';
+      font-feature-settings: 'tnum';
+      position: absolute;
+      display: none;
+      color: #1890ff;
+      text-align: center;
+      vertical-align: middle;
+      opacity: 0;
+      -webkit-transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+      transition: -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+      transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+      transition: transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86),
+        -webkit-transform 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);
+    }
+
+    .ant-spin-spinning {
+      position: static;
+      display: inline-block;
+      opacity: 1;
+    }
+
+    .ant-spin-dot {
+      position: relative;
+      display: inline-block;
+      font-size: 20px;
+      width: 20px;
+      height: 20px;
+    }
+
+    .ant-spin-dot-item {
+      position: absolute;
+      display: block;
+      width: 9px;
+      height: 9px;
+      background-color: #1890ff;
+      border-radius: 100%;
+      -webkit-transform: scale(0.75);
+      -ms-transform: scale(0.75);
+      transform: scale(0.75);
+      -webkit-transform-origin: 50% 50%;
+      -ms-transform-origin: 50% 50%;
+      transform-origin: 50% 50%;
+      opacity: 0.3;
+      -webkit-animation: antSpinMove 1s infinite linear alternate;
+      animation: antSpinMove 1s infinite linear alternate;
+    }
+
+    .ant-spin-dot-item:nth-child(1) {
+      top: 0;
+      left: 0;
+    }
+
+    .ant-spin-dot-item:nth-child(2) {
+      top: 0;
+      right: 0;
+      -webkit-animation-delay: 0.4s;
+      animation-delay: 0.4s;
+    }
+
+    .ant-spin-dot-item:nth-child(3) {
+      right: 0;
+      bottom: 0;
+      -webkit-animation-delay: 0.8s;
+      animation-delay: 0.8s;
+    }
+
+    .ant-spin-dot-item:nth-child(4) {
+      bottom: 0;
+      left: 0;
+      -webkit-animation-delay: 1.2s;
+      animation-delay: 1.2s;
+    }
+
+    .ant-spin-dot-spin {
+      -webkit-transform: rotate(45deg);
+      -ms-transform: rotate(45deg);
+      transform: rotate(45deg);
+      -webkit-animation: antRotate 1.2s infinite linear;
+      animation: antRotate 1.2s infinite linear;
+    }
+
+    .ant-spin-lg .ant-spin-dot {
+      font-size: 32px;
+      width: 32px;
+      height: 32px;
+    }
+
+    .ant-spin-lg .ant-spin-dot i {
+      width: 14px;
+      height: 14px;
+    }
+
+    @media all and (-ms-high-contrast: none), (-ms-high-contrast: active) {
+      .ant-spin-blur {
+        background: #fff;
+        opacity: 0.5;
+      }
+    }
+
+    @-webkit-keyframes antSpinMove {
+      to {
+        opacity: 1;
+      }
+    }
+
+    @keyframes antSpinMove {
+      to {
+        opacity: 1;
+      }
+    }
+
+    @-webkit-keyframes antRotate {
+      to {
+        -webkit-transform: rotate(405deg);
+        transform: rotate(405deg);
+      }
+    }
+
+    @keyframes antRotate {
+      to {
+        -webkit-transform: rotate(405deg);
+        transform: rotate(405deg);
+      }
+    }
+  </style>
+  <body>
+    <div id="root"></div>
+    <div id="loading">
+      <div class="loading-bg"></div>
+      <div class="page-loading-warp">
+        <div class="ant-spin ant-spin-lg ant-spin-spinning">
+          <span class="ant-spin-dot ant-spin-dot-spin">
+            <i class="ant-spin-dot-item"></i>
+            <i class="ant-spin-dot-item"></i>
+            <i class="ant-spin-dot-item"></i>
+            <i class="ant-spin-dot-item"></i>
+          </span>
+        </div>
+      </div>
+    </div>
+  </body>
+  <script>
+    function getQuery(name) {
+      var reg = new RegExp(`(^|\\?|&)${name}=([^&]*)(&|$)`);
+      var r = window.location.href.substr(1).match(reg);
+      if (r != null) return unescape(r[2]);
+      return null;
+    }
+    var code = getQuery('code');
+    if (code) {
+      window.parent.postMessage('code:' + code, '*');
+    } else {
+      document.getElementById('loading').style.display = 'none';
+    }
+    new WxLogin({
+      id: 'root',
+      appid: 'wx8fa48dfc3752f0ce',
+      scope: 'snsapi_login',
+      redirect_uri: encodeURIComponent('http://www.scigou.com'),
+    });
+  </script>
+</html>

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

@@ -20,16 +20,16 @@ export default class UserStore extends BaseStore {
     if (this.state.login || this.adminLogin) {
       this.refreshToken().then(() => {
         if (this.adminLogin) {
-          this.linkTo(window.location.href.substr(0, window.location.href.indexOf('?') + 1));
+          window.location.href = window.location.href.substr(0, window.location.href.indexOf('?'));
         }
       });
     }
   }
 
   needLogin() {
-    if (this.state.login) {
-      return Promise.resolve();
-    }
+    // if (this.state.login) {
+    //   return Promise.resolve();
+    // }
     return new Promise(resolve => {
       this.loginCB = resolve;
       this.setState({ needLogin: true });
@@ -52,7 +52,7 @@ export default class UserStore extends BaseStore {
   }
 
   infoHandle(result) {
-    this.setToken(result.token);
+    if (result.token) this.setToken(result.token);
     this.setState({ login: true, needLogin: false, info: result, username: result.username });
     if (this.loginCB) this.loginCB();
     this.loginCB = null;

+ 1 - 1
front/src/stores/user.js

@@ -50,7 +50,7 @@ export default class UserStore extends BaseStore {
   }
 
   infoHandle(result) {
-    this.setToken(result.token);
+    if (result.token) this.setToken(result.token);
     this.setState({ login: true, needLogin: false, info: result, username: result.username });
     if (this.loginCB) this.loginCB();
     this.loginCB = null;