瀏覽代碼

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

Go 5 年之前
父節點
當前提交
8e4e352beb

+ 46 - 8
front/project/www/app.less

@@ -42,18 +42,14 @@
   border-bottom: 1px solid #eee;
 }
 
-.f-s-16 {
-  font-size: 16px;
-}
-
-.f-s-12 {
-  font-size: 12px;
-}
-
 .t-d-l {
   text-decoration: underline;
 }
 
+.t-d-l-t {
+  text-decoration: line-through;
+}
+
 .f-w-b {
   font-weight: bold;
 }
@@ -234,6 +230,10 @@
   flex: 1;
 }
 
+.p-r {
+  position: relative;
+}
+
 .p-a {
   position: absolute;
 }
@@ -278,10 +278,30 @@
   color: #FF7C06 !important;
 }
 
+.t-8 {
+  color: #8897A8FF !important;
+}
+
+.t-9 {
+  color: #919FAEFF !important;
+}
+
+.t-10 {
+  color: #A2AAB5FF !important;
+}
+
 .b-c-1 {
   background: #F7F7F7;
 }
 
+.f-s-16 {
+  font-size: 16px;
+}
+
+.f-s-12 {
+  font-size: 12px;
+}
+
 .t-s-18 {
   font-size: 18px;
 }
@@ -302,10 +322,22 @@
   font-size: 20px;
 }
 
+.t-s-24 {
+  font-size: 24px;
+}
+
 .t-s-14 {
   font-size: 14px;
 }
 
+.l-h-20 {
+  line-height: 20px;
+}
+
+.l-h-16 {
+  line-height: 16px;
+}
+
 input,
 textarea {
   outline: none;
@@ -426,6 +458,12 @@ body,
     top: 0px;
     color: #EC6413FF;
   }
+
+  .close {
+    color: #D0D8E2FF;
+    cursor: pointer;
+    font-size: 16px;
+  }
 }
 
 #root {}

+ 2 - 2
front/project/www/components/CheckboxItem/index.js

@@ -2,10 +2,10 @@ import React from 'react';
 import './index.less';
 
 function CheckboxItem(props) {
-  const { checked, theme = 'default', onClick } = props;
+  const { className = '', checked, theme = 'default', onClick } = props;
   return (
     <div
-      className={`checkbox-item ${theme} ${checked ? 'checked' : ''}`}
+      className={`checkbox-item ${className} ${theme} ${checked ? 'checked' : ''}`}
       onClick={() => onClick && onClick(!checked)}
     />
   );

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

@@ -271,13 +271,15 @@ export class EditInfo extends Component {
   initState(props) {
     if (props.image && this.waitImage) {
       const { state } = this;
-      Common.upload(props.image).then(result => {
-        const { data } = this.state;
-        data.avatar = result.url;
-        this.setState({ data, uploading: false });
-      }).catch((e) => {
-        this.setState({ imageError: e.message });
-      });
+      Common.upload(props.image)
+        .then(result => {
+          const { data } = this.state;
+          data.avatar = result.url;
+          this.setState({ data, uploading: false });
+        })
+        .catch(e => {
+          this.setState({ imageError: e.message });
+        });
       state.uploading = true;
       this.waitImage = false;
       return state;
@@ -350,7 +352,8 @@ export class EditInfo extends Component {
                   this.waitImage = true;
                   onSelectImage(file);
                   return Promise.reject();
-                }} />
+                }}
+              />
               {this.state.imageError || ''}
             </div>
           </div>
@@ -415,12 +418,12 @@ export class EditAvatar extends Component {
       const reader = new FileReader();
       reader.readAsDataURL(file);
       // 渲染文件
-      reader.onload = (arg) => {
+      reader.onload = arg => {
         this.setState({ image: arg.target.result, fileName: file.name, zoomValue: 1 });
       };
     } else {
       const img = new Image();
-      img.onload = function () {
+      img.onload = function() {
         const canvas = document.createElement('canvas');
         canvas.height = img.height;
         canvas.width = img.width;
@@ -453,7 +456,7 @@ export class EditAvatar extends Component {
     const scaleCanvas = scale(this.props.crop, canvas);
     // let scaleCanvas = this.cropRef.getCroppedCanvas(this.props.crop)
 
-    scaleCanvas.toBlob((blob) => {
+    scaleCanvas.toBlob(blob => {
       const file = new File([blob], fileName);
       onConfirm(file);
     });
@@ -477,7 +480,9 @@ export class EditAvatar extends Component {
         <div className="edit-avatar-modal-wrapper">
           <div className="edit-avatar-o">
             <Cropper
-              ref={(ref) => { this.cropRef = ref; }}
+              ref={ref => {
+                this.cropRef = ref;
+              }}
               src={image}
               ready={() => {
                 this.computerZoom();
@@ -502,7 +507,8 @@ export class EditAvatar extends Component {
                 this.crop();
               }}
               toggleDragModeOnDblclick={false}
-              cropBoxResizable />
+              cropBoxResizable
+            />
           </div>
           <div className="edit-avatar-r">
             <div className="text">头像预览</div>

+ 185 - 0
front/project/www/components/PayModal/index.js

@@ -0,0 +1,185 @@
+import React, { Component } from 'react';
+import './index.less';
+import { Link } from 'react-router-dom';
+import { Checkbox, Icon } from 'antd';
+import Assets from '@src/components/Assets';
+import Tabs from '../Tabs';
+import Modal from '../Modal';
+
+export class PayMModal extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { pay: 'alipay' };
+  }
+
+  render() {
+    const { show, desc, onConfirm, onCancel } = this.props;
+    const { pay } = this.state;
+    return (
+      <Modal
+        className="pay-modal"
+        show={show}
+        width={760}
+        title="购买 千行-CAT 模考"
+        confirmText="支付成功"
+        cancelText="稍后开通"
+        onConfirm={onConfirm}
+        onCancel={onCancel}
+      >
+        <div className="pay-modal-wrapper">
+          <div className="info-layout">
+            <div className="desc">{desc}</div>
+            <div className="money">
+              <div className="t-2">应付金额:</div>
+              <div className="t-1 f-w-b t-s-24">¥ 8888.88</div>
+            </div>
+          </div>
+          <div className="pay-layout">
+            <Tabs
+              border
+              size="small"
+              active={pay}
+              width={80}
+              tabs={[{ key: 'alipay', title: '支付宝' }, { key: 'wechatpay', title: '微信' }]}
+              render={item => <Assets name={item.key} />}
+              onChange={key => this.setState({ pay: key })}
+            />
+            <div className="pay">
+              <div className="qrcode">
+                <Assets name="qrcode" />
+              </div>
+              <div className="t">请使用手机微信或支付宝扫码付款</div>
+              <div className="t">支付金额: ¥ 300</div>
+            </div>
+          </div>
+
+          <div style={{ bottom: 20, left: 0 }} className="p-a t-3 t-s-14">
+            *若在购买过程中遇到问题
+          </div>
+          <div style={{ bottom: 0, left: 0 }} className="p-a t-3 t-s-14">
+            请联系千行小助手:0193191safad 协助解决。
+          </div>
+        </div>
+      </Modal>
+    );
+  }
+}
+
+export class PayMEndModal extends Component {
+  render() {
+    const { show, onConfirm, onCancel } = this.props;
+    return (
+      <Modal
+        show={show}
+        width={630}
+        title="付款成功"
+        confirmText="立即开通"
+        cancelText="稍后开通"
+        onConfirm={onConfirm}
+        onCancel={onCancel}
+      >
+        <div className="t-2">
+          <Icon className="t-5 m-r-5" type="check" />
+          您已成功购买「千行-CAT模考(6套)」服务。
+        </div>
+        <div className="t-2">确认邮件已发送至您的邮箱:XXXXX,请注意查收。</div>
+        <div style={{ bottom: 10, left: 0 }} className="p-a t-3 t-s-14">
+          *您可至“我的-工具”开通。
+        </div>
+      </Modal>
+    );
+  }
+}
+
+export class PayKModal extends Component {
+  constructor(props) {
+    super(props);
+    this.state = { pay: 'alipay' };
+  }
+
+  render() {
+    const { show, desc, onConfirm, onCancel } = this.props;
+    const { pay } = this.state;
+    return (
+      <Modal
+        className="pay-modal"
+        show={show}
+        width={760}
+        title="购买 千行课堂"
+        confirmText={pay === 'bank' ? '确认' : '支付成功'}
+        onConfirm={onConfirm}
+        onCancel={onCancel}
+      >
+        <div className="pay-modal-wrapper">
+          <div className="info-layout">
+            <div className="desc">{desc}</div>
+            <div className="money">
+              <div className="t-2">应付金额:</div>
+              <div className="t-1 f-w-b t-s-24">¥ 8888.88</div>
+            </div>
+          </div>
+          <div className="pay-layout">
+            <Tabs
+              border
+              size="small"
+              active={pay}
+              width={80}
+              tabs={[
+                { key: 'alipay', title: '支付宝' },
+                { key: 'wechatpay', title: '微信' },
+                { key: 'bank', title: '银行转账' },
+              ]}
+              render={item => <Assets name={item.key} />}
+              onChange={key => this.setState({ pay: key })}
+            />
+            <div hidden={pay === 'bank'} className="pay">
+              <div className="qrcode">
+                <Assets name="qrcode" />
+              </div>
+              <div className="t">请使用手机微信或支付宝扫码付款</div>
+              <div className="t">支付金额: ¥ 300</div>
+            </div>
+            <div hidden={pay !== 'bank'} className="bank">
+              <div className="t">汇款银行:中国工商银行上海市浦东支行</div>
+              <div className="t">汇款账号:6100 0000 0000 000</div>
+            </div>
+            <div className="agree">
+              <Checkbox className="m-r-1" />
+              我已阅读并同意<Link to="">千行课程购买协议</Link>
+            </div>
+          </div>
+
+          <div style={{ bottom: 20, left: 0 }} className="p-a t-3 t-s-14">
+            *若在购买过程中遇到问题
+          </div>
+          <div style={{ bottom: 0, left: 0 }} className="p-a t-3 t-s-14">
+            请联系千行小助手:0193191safad 协助解决。
+          </div>
+        </div>
+      </Modal>
+    );
+  }
+}
+
+export class PayKBankModal extends Component {
+  render() {
+    const { show, onConfirm } = this.props;
+    return (
+      <Modal
+        show={show}
+        width={630}
+        title="购买千行课堂"
+        btnAlign="center"
+        confirmText="好的,知道了"
+        onConfirm={onConfirm}
+      >
+        <div style={{ width: 400 }} className="t-2 t-s-18 m-b-2">
+          汇款成功后,请添加微信号XXX或扫描二维码联系小助手,进行核实。
+        </div>
+        <div className="p-a" style={{ right: 0, top: 50 }}>
+          <Assets name="qrcode" />
+        </div>
+      </Modal>
+    );
+  }
+}

+ 60 - 0
front/project/www/components/PayModal/index.less

@@ -0,0 +1,60 @@
+.g-modal.pay-modal {
+  .pay-modal-wrapper {
+    display: flex;
+  }
+
+  .info-layout {
+    flex: 1;
+
+    .desc {
+      margin-bottom: 50px;
+    }
+  }
+
+  .pay-layout {
+    width: 240px;
+    margin-top: -10px;
+    margin-left: 60px;
+    margin-bottom: 20px;
+    text-align: center;
+
+    .pay {
+      overflow: hidden;
+
+      .qrcode {
+        margin-top: 15px;
+        margin-bottom: 15px;
+
+        .assets {
+          width: 140px;
+          height: 140px;
+        }
+      }
+
+      .t {
+        color: #8897A8FF;
+        font-size: 12px;
+      }
+    }
+
+    .bank {
+      margin-top: 25px;
+      background: rgba(250, 250, 250, 1);
+      border-radius: 4px;
+      margin-bottom: 110px;
+      height: 80px;
+      padding: 20px 10px;
+      text-align: left;
+
+      .t {
+        color: #5E677BFF;
+        font-size: 12px;
+      }
+    }
+
+    .agree {
+      margin-top: 10px;
+      font-size: 12px;
+    }
+  }
+}

+ 7 - 2
front/project/www/components/RadioItem/index.js

@@ -2,8 +2,13 @@ import React from 'react';
 import './index.less';
 
 function RadioItem(props) {
-  const { checked, onClick } = props;
-  return <div className={`radio-item ${checked ? 'checked' : ''}`} onClick={() => !checked && onClick && onClick()} />;
+  const { className = '', checked, theme = 'default', onClick } = props;
+  return (
+    <div
+      className={`radio-item ${className} ${theme} ${checked ? 'checked' : ''}`}
+      onClick={() => !checked && onClick && onClick()}
+    />
+  );
 }
 RadioItem.propTypes = {};
 export default RadioItem;

+ 20 - 4
front/project/www/components/RadioItem/index.less

@@ -5,15 +5,11 @@
   height: 16px;
   vertical-align: middle;
   border-radius: 8px;
-  border: 1px solid #C4C6CF;
-  background: #D8D8D8;
   display: inline-block;
   cursor: pointer;
 }
 
 .radio-item.checked {
-  background: #006DAA;
-  border-color: #006DAA;
   position: relative;
 }
 
@@ -27,4 +23,24 @@
   left: 50%;
   top: 50%;
   transform: translate(-50%, -50%);
+}
+
+.radio-item.default {
+  border: 1px solid #C4C6CF;
+  background: #D8D8D8;
+}
+
+.radio-item.checked.default {
+  background: #006DAA;
+  border-color: #006DAA;
+}
+
+.radio-item.white {
+  border: 1px solid #C4C6CF;
+  background: #fff;
+}
+
+.radio-item.checked.white {
+  background: #4292F0FF;
+  border-color: #4292F0FF;
 }

+ 10 - 0
front/project/www/routes/page/cart/index.js

@@ -0,0 +1,10 @@
+export default {
+  path: '/cart',
+  key: 'cart',
+  title: '购物车',
+  needLogin: true,
+  tab: 'main',
+  component() {
+    return import('./page');
+  },
+};

+ 108 - 0
front/project/www/routes/page/cart/index.less

@@ -0,0 +1,108 @@
+@charset "utf-8";
+
+#cart {
+  background: #fff;
+  height: 100%;
+  padding-bottom: 100px;
+  overflow: hidden;
+  overflow-y: auto;
+
+  .content {
+    width: 1140px !important;
+  }
+
+  .footer {
+    position: fixed;
+    height: 80px;
+    bottom: 0;
+    left: 0;
+    right: 0;
+    background: #fff;
+
+    .content {
+      border-top: 1px solid #eee;
+      padding-left: 20px;
+
+      .d-i-b {
+        vertical-align: top;
+      }
+
+      .f-r {
+
+        .button {
+          width: 160px;
+          height: 80px;
+          line-height: 80px;
+          font-size: 22px;
+          padding: 0;
+        }
+      }
+    }
+  }
+
+  .order-item {
+    background: #FAFAFAFF;
+    margin-bottom: 30px;
+
+    .order-item-info {
+      width: 980px;
+      margin-left: 100px;
+      margin-right: 60px;
+      height: 58px;
+      line-height: 58px;
+      position: relative;
+
+      .close {
+        position: absolute;
+        right: -40px;
+        top: 20px;
+      }
+
+      .select {
+        position: absolute;
+        left: -80px;
+        top: 20px;
+      }
+
+      .gift {
+        position: absolute;
+        right: -40px;
+        top: 25px;
+      }
+
+
+      .up {
+        cursor: pointer;
+        position: absolute;
+        left: 62px;
+        top: 20px;
+        font-size: 10px;
+        color: #D0D8E2;
+        transform: scale(0.8);
+
+      }
+
+      .down {
+        cursor: pointer;
+        position: absolute;
+        left: 62px;
+        top: 30px;
+        font-size: 10px;
+        color: #D0D8E2;
+        transform: scale(0.8);
+      }
+
+      input {
+        line-height: 32px;
+      }
+    }
+
+    .order-item-detail {
+      width: 980px;
+      margin-left: 100px;
+      margin-right: 60px;
+      border-top: 1px solid #eee;
+      padding: 20px 0;
+    }
+  }
+}

+ 186 - 0
front/project/www/routes/page/cart/page.js

@@ -0,0 +1,186 @@
+import React, { Component } from 'react';
+import './index.less';
+import { Icon, Radio } from 'antd';
+import Page from '@src/containers/Page';
+import CheckboxItem from '../../../components/CheckboxItem';
+import Button from '../../../components/Button';
+import { Order } from '../../../stores/order';
+
+export default class extends Page {
+  init() {
+
+  }
+
+  initData() {
+    Order.allCheckout()
+      .then(order => {
+        this.setState({ order });
+      });
+  }
+
+  renderView() {
+    const { _list = [{}, {}, {}] } = this.state;
+    return (
+      <div style={{ paddingTop: 50 }}>
+        <div className="content">
+          <div className="t-1 m-b-2 f-w-b t-s-24">购物车</div>
+        </div>
+        <div className="content">
+          <div className="m-b-1 t-8">您看中的课程已构成套餐,结算有优惠</div>
+        </div>
+        <div className="list content">
+          {_list.map(item => {
+            return <OrderItem data={item} />;
+          })}
+        </div>
+        <div className="footer">
+          <div className="content">
+            <div className="d-i-b m-t-1 m-r-2">
+              <CheckboxItem className="v-a-m m-r-5" theme="white" checked />
+              全选
+            </div>
+            <div style={{ marginRight: 50 }} className="d-i-b m-t-1">
+              <Button size="small" radius disabled={false}>
+                删除
+              </Button>
+            </div>
+            <div style={{ marginTop: 15 }} className="d-i-b t-9 t-s-12 m-r-5">
+              优惠活动:
+            </div>
+            <div style={{ marginTop: 15 }} className="d-i-b t-s-12">
+              <div>单项课程 2门9折,3门88折,4门及以上85折。</div>
+              <div>1VS1私教 满30课时享95折优惠。</div>
+            </div>
+            <div className="f-r">
+              <div className="d-i-b m-r-1 m-t-1">
+                <div className="t-1 t-s-16 f-w-b">
+                  实付<span className="m-l-5 t-7 t-s-20"> ¥ 15000</span>
+                </div>
+                <div className="t-1">
+                  原价<span className="m-l-5 t-8 t-d-l-t">¥15200</span>
+                  <span className="m-l-5  t-8">(优惠活动-¥200)</span>
+                </div>
+              </div>
+              <Button className="submit">立即付款</Button>
+            </div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}
+
+class OrderItem extends Component {
+  render() {
+    return (
+      <div className="order-item">
+        {this.renderInfo()}
+        {this.renderDetail()}
+      </div>
+    );
+  }
+
+  renderInfo() {
+    return (
+      <div className="order-item-info">
+        <CheckboxItem theme="white" className="select" />
+        <Icon className="close" type="close-circle" theme="filled" />
+        <div style={{ width: 360 }} className="d-i-b t-1 t-s-16">
+          OG 20 套餐
+        </div>
+        <div style={{ width: 400 }} className="d-i-b t-8 t-s-12">
+          实付金额满20000元赠送
+        </div>
+        <div style={{ width: 120 }} className="d-i-b t-8 t-s-12 p-r">
+          数量
+          <input style={{ width: 32 }} className="m-l-5 t-c" />
+          <Icon className="up" type="caret-up" />
+          <Icon className="down" type="caret-down" />
+        </div>
+        <div className="d-i-b t-7 t-s-16"> ¥ 15000</div>
+      </div>
+    );
+  }
+
+  renderDetail() {
+    return (
+      <div className="order-item-detail l-h-20">
+        <div className="contain">
+          <div style={{ width: 880 }} className="d-i-b t-1 t-s-12">
+            <span className="d-i-b f-w-b m-r-5">
+              包含
+              <Icon className="t-10 c-p" type="caret-up" />
+              <Icon className="t-10 c-p" type="caret-down" />
+            </span>
+            <span style={{ width: 300 }} className="d-i-b nowrap">
+              OG 20 语法 SC +OG 20 语法 SC +OG 20 语法 SC +OG 20 语法 SC +
+            </span>
+          </div>
+          <div className="d-i-b t-1 t-s-12 t-d-l-t"> ¥ 123022</div>
+        </div>
+        <div className="contain-list m-b-5 l-h-16">
+          <div>
+            <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+              <span className="d-i-b m-r-5">OG 20 语法 SC</span>
+            </div>
+            <div className="d-i-b t-8 t-s-12">
+              <span className="m-r-2">开通有效期: 3个月</span>
+              <span className="m-l-2">使用有效期: 3个月</span>
+            </div>
+          </div>
+          <div>
+            <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+              <span className="d-i-b m-r-5">OG 20 语法 SC</span>
+            </div>
+            <div className="d-i-b t-8 t-s-12">
+              <span className="m-r-2">开通有效期: 3个月</span>
+              <span className="m-l-2">使用有效期: 3个月</span>
+            </div>
+          </div>
+          <div>
+            <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+              <span className="d-i-b m-r-5">OG 20 语法 SC</span>
+            </div>
+            <div className="d-i-b t-8 t-s-12">
+              <span className="m-r-2">开通有效期: 3个月</span>
+              <span className="m-l-2">使用有效期: 3个月</span>
+            </div>
+          </div>
+        </div>
+        <div className="service">
+          <div className="d-i-b t-1 t-s-12">
+            <span className="d-i-b f-w-b m-r-5">赠送服务</span>
+            <span className="d-i-b">
+              机经券×1+VIP×3 月+模考×1
+              <Icon className="m-l-5 close" type="exclamation-circle" theme="filled" />
+            </span>
+          </div>
+        </div>
+        <div className="select">
+          <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+            <span className="d-i-b f-w-b m-r-5">请选择</span>
+          </div>
+          <div className="d-i-b t-1 t-s-12">可至「个人中心-课程」预约辅导时间。</div>
+        </div>
+        <div className="select-list m-b-5 l-h-16">
+          <div>
+            <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+              <span className="d-i-b m-r-5">
+                <Radio className="m-r-5" /> OG 20 语法 SC
+              </span>
+            </div>
+            <div className="d-i-b t-8 t-s-12">适合未参加过实战的考生</div>
+          </div>
+          <div>
+            <div style={{ width: 360 }} className="d-i-b t-1 t-s-12">
+              <span className="d-i-b m-r-5">
+                <Radio className="m-r-5" /> OG 20 语法 SC
+              </span>
+            </div>
+            <div className="d-i-b t-8 t-s-12">适合未参加过实战的考生</div>
+          </div>
+        </div>
+      </div>
+    );
+  }
+}

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

@@ -1,6 +1,7 @@
 import home from './home';
 import login from './login';
+import order from './order';
 import demo from './demo';
 import contract from './contract';
 
-export default [home, login, demo, contract];
+export default [home, login, order, demo, contract];