Bladeren bron

Merge branch 'master' of git.proginn.com:zaixianjiaoyu/sourcecode

Go 5 jaren geleden
bovenliggende
commit
8d557aa433

File diff suppressed because it is too large
+ 22 - 0
front/project/www/assets/course.svg


+ 17 - 0
front/project/www/assets/exit.svg

@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
+    <title>exit</title>
+    <desc>Created with Sketch.</desc>
+    <g id="题库搜索" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="菜单" transform="translate(-1050.000000, -306.000000)" fill="#303139">
+            <g id="课程-2" transform="translate(1030.000000, 47.000000)">
+                <g id="1备份-4" transform="translate(0.000000, 240.000000)">
+                    <g id="编组-2" transform="translate(20.000000, 19.000000)">
+                        <path d="M11,0 L11,2 L2,2 L2,10 L11,10 L11,12 L0,12 L0,0 L11,0 Z M8,3 L12,6 L8,9 L8,7 L3,7 L3,5 L8,5 L8,3 Z" id="形状结合"></path>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 19 - 0
front/project/www/assets/jijing.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
+    <title>jijing</title>
+    <desc>Created with Sketch.</desc>
+    <g id="题库搜索" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="菜单" transform="translate(-1050.000000, -123.000000)">
+            <g id="课程-2" transform="translate(1030.000000, 47.000000)">
+                <g id="1备份" transform="translate(0.000000, 60.000000)">
+                    <g id="jijing" transform="translate(20.000000, 16.000000)">
+                        <rect id="矩形" fill="#4292F0" x="1" y="0" width="10" height="12" rx="1"></rect>
+                        <rect id="矩形备份" fill="#FFFFFF" x="3" y="3" width="6" height="1.5" rx="0.75"></rect>
+                        <rect id="矩形备份-2" fill="#FFFFFF" x="3" y="7" width="4" height="1.5" rx="0.75"></rect>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 18 - 0
front/project/www/assets/massage.svg

@@ -0,0 +1,18 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
+    <title>massage</title>
+    <desc>Created with Sketch.</desc>
+    <g id="题库搜索" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="菜单" transform="translate(-1050.000000, -243.000000)">
+            <g id="课程-2" transform="translate(1030.000000, 47.000000)">
+                <g id="1备份-3" transform="translate(0.000000, 180.000000)">
+                    <g id="massage" transform="translate(20.000000, 16.000000)">
+                        <rect id="矩形" fill="#4292F0" x="0" y="2" width="12" height="8" rx="1"></rect>
+                        <path d="M1.24325986,2.62852654 C1.00816733,2.48366069 0.700150204,2.55680387 0.555284354,2.79189639 C0.410418504,3.02698892 0.483561678,3.33500605 0.718654206,3.4798719 L6.0017879,6.7353801 L11.2163008,3.47827001 C11.4505087,3.33197817 11.5217786,3.02352224 11.3754868,2.78931441 C11.229195,2.55510658 10.920739,2.48383658 10.6865312,2.63012843 L5.9982121,5.55856521 L1.24325986,2.62852654 Z" id="路径-2" fill="#FFFFFF" fill-rule="nonzero"></path>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 19 - 0
front/project/www/assets/yaoqing.svg

@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="12px" height="12px" viewBox="0 0 12 12" version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
+    <!-- Generator: Sketch 58 (84663) - https://sketch.com -->
+    <title>yaoqing</title>
+    <desc>Created with Sketch.</desc>
+    <g id="题库搜索" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="菜单" transform="translate(-1050.000000, -185.000000)" fill="#4292F0">
+            <g id="课程-2" transform="translate(1030.000000, 47.000000)">
+                <g id="1备份-2" transform="translate(0.000000, 120.000000)">
+                    <g id="编组-6" transform="translate(20.000000, 16.000000)">
+                        <g id="yaoqing" transform="translate(0.000000, 2.000000)">
+                            <path d="M4,-1 C5.65685425,-1 7,0.343145751 7,2 L7,2.999 L8,3 C9.65685425,3 11,4.34314575 11,6 C11,7.65685425 9.65685425,9 8,9 L7,8.999 L7,9 L1,9 L1,2 C1,0.343145751 2.34314575,-1 4,-1 Z" id="形状结合" transform="translate(6.000000, 4.000000) rotate(-45.000000) translate(-6.000000, -4.000000) "></path>
+                        </g>
+                    </g>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>

+ 50 - 4
front/project/www/components/Header/index.js

@@ -1,5 +1,6 @@
 import React from 'react';
 import { Link } from 'react-router-dom';
+import { Dropdown } from 'antd';
 import Assets from '@src/components/Assets';
 import Button from '../Button';
 import './index.less';
@@ -26,10 +27,55 @@ function Header(props) {
         </div>
         <div className="right">
           {user.login ? (
-            <Link to="/my/main" className="info">
-              <Assets src={user.info.avatar} />
-              <span className="t-2 f-s-12">{user.info.nickname}</span>
-            </Link>
+            <Dropdown
+              trigger="hover"
+              overlayClassName="header-user-overlay"
+              overlay={
+                <div className="list">
+                  <div className="item more">
+                    <div className="t-1">
+                      <Assets name="course" svg />
+                      课程
+                    </div>
+                    <div className="t-s-12 nowrap">
+                      <span className="t-4">3</span> 份作业待完成
+                    </div>
+                  </div>
+                  <div className="item more">
+                    <div className="t-1">
+                      <Assets name="jijing" svg />
+                      机经
+                    </div>
+                    <div className="t-s-12 nowrap">最近更新:2019-02-20</div>
+                  </div>
+                  <div className="item more">
+                    <div className="t-1">
+                      <Assets name="yaoqing" svg />
+                      邀请好友
+                    </div>
+                    <div className="t-s-12 nowrap">第 1 位好友加入</div>
+                  </div>
+                  <div className="item more">
+                    <div className="t-1">
+                      <Assets name="message" svg />
+                      消息
+                    </div>
+                    <div className="t-s-12 nowrap">到期提醒: 内容前6个字…</div>
+                  </div>
+                  <div className="item">
+                    <div className="t-1">
+                      <Assets name="exit" svg />
+                      退出
+                    </div>
+                  </div>
+                </div>
+              }
+            >
+              <Link to="/my/main" className="info">
+                <Assets src={user.info.avatar} />
+                <span className="t-2 f-s-12">{user.info.nickname}</span>
+              </Link>
+            </Dropdown>
           ) : (
             <Button
               onClick={() => {

+ 37 - 0
front/project/www/components/Header/index.less

@@ -100,4 +100,41 @@
   .body {
     width: 1200px;
   }
+}
+
+.header-user-overlay {
+  background: #fff;
+  box-shadow: 0px 4px 14px 0px rgba(189, 199, 215, 0.25);
+  width: 180px;
+
+  .list {
+    .item {
+      line-height: 14px;
+      padding: 20px;
+      border-bottom: 1px solid #D8D8D8FF;
+
+      .assets {
+        margin-right: 5px;
+
+        path {
+          fill: #4292F0FF;
+        }
+      }
+    }
+
+    .item.more {
+      line-height: 16px;
+      padding: 15px;
+
+      .assets {
+        path {
+          fill: #303139FF;
+        }
+      }
+    }
+
+    .item:last-child {
+      border-bottom: none;
+    }
+  }
 }

+ 86 - 43
front/project/www/components/Video/index.js

@@ -55,7 +55,7 @@ export default class Video extends Component {
   constructor(props) {
     super(props);
     this.ready = false;
-    this.state = { id: generateUUID(8), playing: false, fulling: false, progress: 0 };
+    this.state = { id: generateUUID(8), playing: false, fulling: false, progress: 0, speed: 1 };
   }
 
   componentDidMount() {
@@ -105,8 +105,8 @@ export default class Video extends Component {
 
   onChangeProgress(value) {
     if (!this.ready) return;
-    this.player.currentTime(this.player.duration() * value / 100);
-    this.setState({ progress: this.player.currentTime() * 100 / this.player.duration() });
+    this.player.currentTime((this.player.duration() * value) / 100);
+    this.setState({ progress: (this.player.currentTime() * 100) / this.player.duration() });
   }
 
   onPlay() {
@@ -137,6 +137,11 @@ export default class Video extends Component {
 
   onSpeed(speed) {
     this.player.playbackRate(speed);
+    this.setState({ selectSpeed: false, speed });
+  }
+
+  selectSpeed() {
+    this.setState({ selectSpeed: true });
   }
 
   onFullChange() {
@@ -155,7 +160,7 @@ export default class Video extends Component {
 
   render() {
     const { btnList = [], children, onAction, hideAction } = this.props;
-    const { playing, fulling, id } = this.state;
+    const { playing, fulling, id, selectSpeed, speed } = this.state;
     return (
       <div id={id} className={`video-item ${!hideAction ? 'action' : ''} ${fulling ? 'full' : ''}`}>
         <div className="video-wrapper">
@@ -163,7 +168,7 @@ export default class Video extends Component {
             ref={node => {
               this.videoNode = node;
             }}
-          // vjs-fluid
+            // vjs-fluid
           />
           {!playing && <Assets className="play" name="play" onClick={() => this.onPlay()} />}
           {playing && <Assets className="stop" name="stop" onClick={() => this.onPause()} />}
@@ -171,47 +176,81 @@ export default class Video extends Component {
         <div className="video-bottom">
           <div className="progress" />
           {/* {this.renderProgress()} */}
-          {!hideAction && <div className="action-bar">
-            <div className="d-i-b m-r-1">
-              <Assets name={!playing ? 'play2' : 'stop2'} onClick={() => (playing ? this.onPause() : this.onPlay())} />
-              {/* {playing && <Assets name="stop2" onClick={() => this.onPause()} />} */}
-            </div>
-            <div className="d-i-b m-r-1">
-              <Assets name="next2" onClick={() => this.onNext()} />
-            </div>
-            {/* <div className="m-r-1">{this.ready ? (formatMinuteSecond(this.player.currentTime())) : ('00:00')}</div>
+          {!hideAction && (
+            <div className="action-bar">
+              <div className="d-i-b m-r-1">
+                <Assets
+                  name={!playing ? 'play2' : 'stop2'}
+                  onClick={() => (playing ? this.onPause() : this.onPlay())}
+                />
+                {/* {playing && <Assets name="stop2" onClick={() => this.onPause()} />} */}
+              </div>
+              <div className="d-i-b m-r-1">
+                <Assets name="next2" onClick={() => this.onNext()} />
+              </div>
+              {/* <div className="m-r-1">{this.ready ? (formatMinuteSecond(this.player.currentTime())) : ('00:00')}</div>
             <div className="m-r-1">/{this.ready ? (formatMinuteSecond(this.player.duration())) : ('00:00')}</div> */}
-            <div className="flex-block" />
-            {btnList.map(btn => {
-              if (btn.full && !fulling) return '';
-              if (!btn.show) return '';
-              return (
-                <div className="d-i-b m-r-1">
-                  {btn.render ? (
-                    <div className="fix-btn-action d-i-b" onClick={() => {
-                      if (btn.pause) this.onPause();
-                      if (onAction) onAction(btn.key);
-                    }}>
-                      {btn.render(btn.active)}
-                    </div>
-                  ) : (<div
-                    className={`btn-action ${btn.active ? 'active' : ''}`}
-                    onClick={() => onAction && onAction(btn.key)}
-                  >
-                    {btn.title}
-                  </div>)}
+              <div className="flex-block" />
+              {btnList.map(btn => {
+                if (btn.full && !fulling) return '';
+                if (!btn.show) return '';
+                return (
+                  <div className="d-i-b m-r-1">
+                    {btn.render ? (
+                      <div
+                        className="fix-btn-action d-i-b"
+                        onClick={() => {
+                          if (btn.pause) this.onPause();
+                          if (onAction) onAction(btn.key);
+                        }}
+                      >
+                        {btn.render(btn.active)}
+                      </div>
+                    ) : (
+                      <div
+                        className={`btn-action ${btn.active ? 'active' : ''}`}
+                        onClick={() => onAction && onAction(btn.key)}
+                      >
+                        {btn.title}
+                      </div>
+                    )}
+                  </div>
+                );
+              })}
+              <div className="d-i-b m-r-1">
+                <div className={`btn-action ${selectSpeed ? 'active' : ''}`} onClick={() => this.selectSpeed()}>
+                  倍速
                 </div>
-              );
-            })}
-            <div className="d-i-b m-r-1">
-              <div className="btn-action">倍速</div>
+              </div>
+              <div className="d-i-b">
+                {!fulling && <Assets name="full2" onClick={() => this.onFull()} />}
+                {fulling && <Assets name="reduction2" onClick={() => this.onExitFull()} />}
+              </div>
             </div>
-            <div className="d-i-b">
-              {!fulling && <Assets name="full2" onClick={() => this.onFull()} />}
-              {fulling && <Assets name="reduction2" onClick={() => this.onExitFull()} />}
-            </div>
-          </div>}
+          )}
         </div>
+        {selectSpeed && (
+          <div className="select-speed">
+            <div className={`item ${speed === 0.5 ? 'active' : ''}`} onClick={() => this.onSpeed(0.5)}>
+              0.5
+            </div>
+            <div className={`item ${speed === 0.75 ? 'active' : ''}`} onClick={() => this.onSpeed(0.75)}>
+              0.75
+            </div>
+            <div className={`item ${speed === 1 ? 'active' : ''}`} onClick={() => this.onSpeed(1)}>
+              正常
+            </div>
+            <div className={`item ${speed === 1.25 ? 'active' : ''}`} onClick={() => this.onSpeed(1.25)}>
+              1.25
+            </div>
+            <div className={`item ${speed === 1.5 ? 'active' : ''}`} onClick={() => this.onSpeed(1.5)}>
+              1.5
+            </div>
+            <div className={`item ${speed === 2.0 ? 'active' : ''}`} onClick={() => this.onSpeed(2)}>
+              2.0
+            </div>
+          </div>
+        )}
         {children}
       </div>
     );
@@ -220,6 +259,10 @@ export default class Video extends Component {
   renderProgress() {
     const { hideProgress } = this.props;
     const { progress } = this.state;
-    return !hideProgress && <Slider value={progress || 0} tooltipVisible={false} onChange={(value) => this.onChangeProgress(value)} />;
+    return (
+      !hideProgress && (
+        <Slider value={progress || 0} tooltipVisible={false} onChange={value => this.onChangeProgress(value)} />
+      )
+    );
   }
 }

+ 21 - 0
front/project/www/components/Video/index.less

@@ -24,6 +24,27 @@
   //     display: none;
   //   }
   // }
+  .select-speed {
+    position: absolute;
+    bottom: 65px;
+    right: 10px;
+    width: 80px;
+    background: #3A3A3AFF;
+    border-radius: 4px;
+
+    .item {
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      font-size: 12px;
+      color: rgba(255, 255, 255, 0.6);
+      cursor: pointer;
+    }
+
+    .item.active {
+      color: #fff;
+    }
+  }
 
   .video-bottom {
     position: absolute;

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

@@ -2,7 +2,7 @@ export default {
   path: '/demo',
   key: 'demo',
   title: '首页',
-  needLogin: true,
+  needLogin: false,
   component() {
     return import('./page');
   },

+ 2 - 0
front/project/www/routes/page/demo/page.js

@@ -15,11 +15,13 @@ import Step from '../../../components/Step';
 import OtherAnswer from '../../../components/OtherAnswer';
 import QAList from '../../../components/QAList';
 import Select from '../../../components/Select';
+import Video from '../../../components/Video';
 
 export default class extends Page {
   renderView() {
     return (
       <div>
+        <Video src="/01.mp4" />
         <Continue date={'2019-04-29 16:30'} data={{}} />
         <div className="content">
           <Select list={[{ title: '123' }, { title: '321' }]} />

+ 93 - 0
front/project/www/routes/page/export/index.less

@@ -5,6 +5,7 @@
 
   .content {
     width: 1200px !important;
+    padding-bottom: 20px;
   }
 
   .head-layout {
@@ -22,5 +23,97 @@
       line-height: 80px;
       border-radius: 4px;
     }
+
+    .detail-item {
+      padding-top: 20px;
+      padding-bottom: 40px;
+    }
+
+    .detail-item-block {
+      margin-bottom: 40px;
+    }
+
+    .title-item {
+      border-left: 6px solid #7775CAFF;
+      padding-left: 10px;
+      font-size: 18px;
+      line-height: 16px;
+      font-weight: 600;
+      color: #303036FF;
+      margin-bottom: 20px;
+    }
+
+    .select-item {
+      width: 520px;
+
+      .select-icon {
+        left: 0;
+        top: 5px;
+        border-radius: 50%;
+        width: 15px;
+        height: 15px;
+        border: 1px solid #D5D5D5FF;
+      }
+    }
+
+    .ask-tag {
+      display: inline-block;
+      background: #4D4D4DFF;
+      padding: 2px 10px;
+      font-size: 10px;
+      color: #fff;
+      border-radius: 2px;
+      margin-bottom: 5px;
+    }
+
+    .note-item {
+      background: rgba(245, 245, 245, 1);
+      border-radius: 6px;
+      padding: 15px;
+
+      .t {
+        border-left: 5px solid rgba(179, 179, 179, 1);
+        padding-left: 15px;
+        line-height: 10px;
+      }
+    }
+
+    .hard-body {
+      border-top: 1px solid #ECEDEEFF;
+    }
+
+    .hard-row {
+      border-bottom: 1px solid #ECEDEEFF;
+      line-height: 60px;
+      height: 60px;
+      display: flex;
+
+      .label {
+        padding-left: 20px;
+        width: 90px;
+      }
+
+      .input {
+        padding-left: 20px;
+        flex: 1;
+
+        .hard-input {
+          display: inline-block;
+          border: none;
+          background: none;
+        }
+      }
+    }
+
+    .hard-row:nth-of-type(even) {
+      background: #FBFBFB;
+    }
+
+    .hard-select {
+      background: #FBFBFBFF;
+      border-bottom: 1px solid #ECEDEEFF;
+      border-top: 1px solid #ECEDEEFF;
+      padding: 15px 20px;
+    }
   }
 }

File diff suppressed because it is too large
+ 77 - 11
front/project/www/routes/page/export/page.js


+ 27 - 16
front/project/www/stores/user.js

@@ -5,15 +5,23 @@ import { getMap } from '@src/services/Tools';
 
 import { ServiceParamMap, OrderInfoMap, ServiceKey } from '../../Constant';
 
-const ServiceParamRelation = getMap(Object.keys(ServiceParamMap).map(key => {
-  return {
-    map: getMap(ServiceParamMap[key].map((row, index) => {
-      row.index = index;
-      return row;
-    }), 'value', 'index'),
-    key,
-  };
-}), 'key', 'map');
+const ServiceParamRelation = getMap(
+  Object.keys(ServiceParamMap).map(key => {
+    return {
+      map: getMap(
+        ServiceParamMap[key].map((row, index) => {
+          row.index = index;
+          return row;
+        }),
+        'value',
+        'index',
+      ),
+      key,
+    };
+  }),
+  'key',
+  'map',
+);
 function formatTitle(record) {
   if (record.productType === 'course_package') {
     return (record.coursePackage || {}).title;
@@ -27,7 +35,7 @@ function formatTitle(record) {
     return (record.data || {}).title;
   }
   if (record.productType === 'service') {
-    return record.info.label || ((record.serviceInfo || {}).title);
+    return record.info.label || (record.serviceInfo || {}).title;
   }
   return '';
 }
@@ -52,7 +60,8 @@ function formatCheckout(checkouts) {
     checkout.key = checkout.id;
     checkout.info = OrderInfoMap[checkout.productType];
     if (checkout.productType === 'service') {
-      const index = (ServiceParamRelation[checkout.service] && ServiceParamRelation[checkout.service][checkout.param]) || 0;
+      const index =
+        (ServiceParamRelation[checkout.service] && ServiceParamRelation[checkout.service][checkout.param]) || 0;
       checkout.info = Object.assign({}, checkout.info[checkout.service], checkout.serviceInfo.package[index]);
     }
     checkout.title = formatTitle(checkout);
@@ -76,11 +85,13 @@ export default class UserStore extends BaseStore {
   }
 
   initAfter() {
-    this.refreshToken().then(() => {
-      if (this.adminLogin) {
-        window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
-      }
-    });
+    if (this.getToken()) {
+      this.refreshToken().then(() => {
+        if (this.adminLogin) {
+          window.location.href = window.location.href.replace(`token=${this.adminLogin}`, '').replace('&&', '&');
+        }
+      });
+    }
   }
 
   needPay(order) {

+ 0 - 1
front/src/stores/base.js

@@ -27,7 +27,6 @@ export default class BaseStore {
 
   setState(state) {
     if (!this.store) throw new Error('store init error');
-    console.log('setState', state);
     this.store.dispatch({
       key: this.key,
       type: STORE_UPDATE,