Commit 1f963c13 by FE

merge

parents 2ad8665d 03246bfe
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -14199,9 +14199,9 @@
}
},
"swiper": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-4.5.0.tgz",
"integrity": "sha512-jRCd/CGet9kaHwthHdd/sL/YU8CI157PWLyItnIcn/o/jP4haVky3zTF6f9F3JDpmQIw7jdWihISiYx0/oTHsg==",
"version": "4.5.1",
"resolved": "https://registry.npmjs.org/swiper/-/swiper-4.5.1.tgz",
"integrity": "sha512-se6I7PWWu950NAMXXT+ENtF/6SVb8mPyO+bTfNxbQBILSeLqsYp3Ndap+YOA0EczOIUlea274PKejT6gKZDseA==",
"requires": {
"dom7": "^2.1.3",
"ssr-window": "^1.0.1"
......
......@@ -78,7 +78,7 @@
"sass-resources-loader": "^2.0.0",
"socket.io": "^2.2.0",
"style-loader": "0.23.1",
"swiper": "^4.5.0",
"swiper": "^4.5.1",
"terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2",
"video.js": "^7.6.5",
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -3,7 +3,8 @@ import Routes from './router'
import cookie from 'js-cookie'
import { connect } from "react-redux"
import { setCurrentUser, startFetchUser } from "@/store/userAction"
import { withRouter } from 'react-router-dom'
import {initialState} from "@/store/userReducer"
import { withRouter, Link } from 'react-router-dom'
import { compose } from 'redux'
import { getParam, http, browser } from "@/utils"
import { Toast } from "antd-mobile"
......@@ -63,7 +64,7 @@ class App extends Component {
if (cookie.get('uid') && this.props.user.hasError) {
this.getUser()
}
if(location.pathname==='/passport'){
if (location.pathname === '/passport') {
window.localStorage.setItem('binding_redirect', JSON.stringify(this.previousLocation))
}
const {pathname, state} = location
......@@ -101,10 +102,15 @@ class App extends Component {
setNavigationRecord = (location, action) => {
const {pathname, search, hash} = location
let isLastRecord = location.pathname === (this.records.length && this.records[this.records.length - 1].pathname)
let needHistoryMutation = location.pathname !== this.previousLocation.pathname
switch (action) {
case 'POP':
if (needHistoryMutation) {
this.firstLoad ? this.records.push({pathname, search, hash}) : this.records.pop()
} else {
this.records[this.records.length - 1] = location
}
break
case 'REPLACE':
this.records.length > 1 && (this.records[this.records.length - 1] = {pathname, search, hash})
......@@ -148,16 +154,19 @@ class App extends Component {
getUser = () => {
//获取用户信息
this.props.startFetchUser()
http.get(`${API.home}/m/user_info`).then(res => {
this.props.setCurrentUser(this.transformUser(res))
})
//微信
let code = getParam('code')
let oid = getParam('oid')
if (code && !oid) {
http.get(`${API['home']}/m/wx_loginInfo/code/${code}?redirect=${encodeURIComponent(window.location.href)}`)
//针对2019双旦活动特殊处理,活动结束后删掉
//treasure_code=3538333139312c31&origin=2&aa=bb&code=0211aiYB1VVOL60rmWWB1367YB11aiY7&state=STATE
if (getParam('treasure_code') == '3538333139312c31' && code == '0211aiYB1VVOL60rmWWB1367YB11aiY7') {
return
}
http.get(`${API["passport-api"]}/m/wx_loginInfo/code/${code}?redirect=${encodeURIComponent(window.location.href)}`)
.then(res => {
let data = res.data
if (data.errno == 200) {
......@@ -174,11 +183,17 @@ class App extends Component {
}
} else {
Toast.info(data.msg)
this.props.setCurrentUser(initialState)
}
})
} else {
http.get(`${API.home}/m/user_info`).then(res => {
this.props.setCurrentUser(this.transformUser(res))
})
}
}
componentDidUpdate() {
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
.captcha-container {
position: relative;
width: 100%;
height: 40px;
// height: 40px;
}
.captcha-animation {
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import './index.scss';
const Root = document.querySelector('body');
const events = ['touchmove', 'mousewheel'];
class Mask extends Component {
constructor(props) {
super(props);
if(!this.el) {
this.el = document.createElement('div');
}
}
componentDidMount() {
events.forEach(item => {
this.el.addEventListener(item, this.preventEvent, {
passive: false
})
})
Root.appendChild(this.el);
}
componentWillUnmount() {
Root.removeChild(this.el);
}
preventEvent = e => {
e.preventDefault();
}
render() {
const { visible, handleToHide, className } = this.props;
if(visible) {
return ReactDOM.createPortal(
(
<div className="mask">
<div className={classnames("mask-content", className)}>
{this.props.children}
</div>
<div className="mask-footer">
<i className="mask-button__close" onClick={handleToHide}></i>
</div>
</div>
),
this.el
);
}else {
return null;
}
}
}
export default Mask;
\ No newline at end of file
.mask {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
color:#fff;
background-color: rgba(0, 0, 0, .5);
z-index: 999;
}
.mask-content {
min-width: 200px;
min-height: 100px;
padding: 10px 0;
border-radius: 5px;
box-sizing: border-box;
background-color: #fff;
}
.mask-footer {
margin-top: 33px;
}
.mask-button__close {
display: inline-block;
width: 33px;
height: 33px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png');
}
\ No newline at end of file
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
import React, { Component } from 'react';
import { http } from '@/utils';
import { Formik, Form, Field } from 'formik';
import { Toast } from "antd-mobile";
import './index.scss';
class AddressPopup extends Component {
constructor(props) {
super(props)
this.state = {
isLoading: false,
addressInfo: {
name: '',
phone: '',
address: '',
},
}
}
componentDidMount() {
this.fetchUserAddress();
}
// 获取收货信息
fetchUserAddress = () => {
const { addressInfo } = this.state;
http.get(`${API.home}/sys/user_address_info`).then(res => {
const {code, data, msg} = res.data;
if (code === 200) {
this.setState({
addressInfo: Object.assign({}, addressInfo, {
name: data.name,
phone: data.phone,
address: data.address,
}),
isLoading: true,
});
}
});
}
handleToSubmit = (params = {}) => {
const { successBindAddress } = this.props;
http.post(`${API.home}/sys/update_address`, {
act_type: 'treasure',
...params
}).then(res => {
const {code, msg} = res.data;
if (code === 200) {
successBindAddress();
} else {
Toast.info(msg, 2, null, false);
}
});
}
render() {
const { isLoading, addressInfo } = this.state;
const {tip, prize, skip = 'default'} = this.props;
return (
<>
{
isLoading &&
<Formik
initialValues={{
...addressInfo
}}
validate={({name, phone, address}) => {
const errors = {};
if (!name) {
errors.name = '请输入收件人';
}
if(!/^1[3-9]\d{9}$/.test(phone)) {
errors.phone = '请填写正确格式的手机号';
}
if (!address) {
errors.address = '请输入收货地址';
}
return errors;
}}
validateOnBlur={false}
validateOnChange={false}
onSubmit={(values) => {
this.handleToSubmit(values);
}}
render={({errors}) => (
<Form className="address-form" data-skip={skip}>
<h2 className="address-form__title">收货信息</h2>
{
prize ? (
<p className='address__prize'>
您抽中了
<span style={{'color': '#FF4000'}}>{prize}</span>
</p>
) : (null)
}
{
tip ? (<div className="address-form__subtitle">{tip}</div>) : (<p className="address-form__desc">请及时填写收货信息,获得实物奖品后将第一时间为您邮寄</p>)
}
<Field
name="name"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收件人"
/>
{
errors.name &&
<p className="address-form__tip">{errors.name}</p>
}
</div>
)}
/>
<Field
name="phone"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="联系方式"
/>
{
errors.phone &&
<p className="address-form__tip">{errors.phone}</p>
}
</div>
)}
/>
<Field
name="address"
render={({ field }) => (
<div className="address-form__item">
<input
{...field}
className="address-form__ipt"
type="text"
placeholder="收货地址"
/>
{
errors.address &&
<p className="address-form__tip">{errors.address}</p>
}
</div>
)}
/>
<button
className="address-form__submit"
data-status="do"
type="submit"
>提交</button>
</Form>
)}
/>
}
</>
);
}
}
export default AddressPopup;
\ No newline at end of file
// 地址弹窗
[data-skip="default"] {
.address-form__item {
width: 250px;
}
.address-form__submit {
width: 120px;
height: 34px;
margin: 8px auto 0;
border-style: none;
border-radius: 17px;
color: rgba(255, 255, 255, 1);
background-color: rgba(82, 92, 101, 0.3);
&[data-status="do"] {
background-color: #0099FF;
}
}
}
[data-skip="year"] {
.address-form__title {
margin: 10px 0 0;
font-size: 18px;
color: #111;
text-align: center;
line-height: 1;
}
.address-form__subtitle {
margin: 0 15px;
}
.address-form__item {
width: 270px;
margin: 0 15px 10px;
}
.address-form__ipt {
border-radius: 3px;
}
.address-form__submit {
width: 270px;
height: 44px;
margin: 15px auto 0;
border: 1px solid #090909;
border-radius: 5px;
color: #090909;
background-color: #FFE319;
}
}
.address-form__desc {
// width: 238px;
margin: 16px auto 15px;
font-size: 12px;
color: #999;
}
.address-form__item {
position: relative;
width: 250px;
margin: 0 auto 16px;
}
.address-form__ipt {
display: block;
width: 100%;
height: 40px;
border: 1px solid rgba(221, 221, 221, 1);
font-size: 14px;
font-weight: 400;
color: rgba(153, 153, 153, 1);
text-indent: 10px;
}
.address-form__tip {
position: absolute;
bottom: -14px;
width: 100%;
font-size: 12px;
color: #ff0000;
line-height: 14px;
}
.address-form__submit {
display: block;
font-size: 15px;
font-weight: 500;
cursor: pointer;
outline: none;
}
\ No newline at end of file
import React, { Component } from 'react';
import { Formik, Form, Field } from 'formik';
import { Toast } from 'antd-mobile';
import { isEmpty } from 'lodash';
import Captcha from '@/common/Captcha';
import { http, getParam } from '@/utils';
import './index.scss';
class BindPhone extends Component {
captchaInstance = null;
constructor(props) {
super(props),
this.state = {
validate: '',
seconds: 60,
isFirst: true,
timer: null,
isTimer: false, // 是否开始倒计时
accountInfo: {},
bindInfo: {},
country: {
num: '86'
}
}
}
componentDidMount() {
this.initCountryInfo();
}
initCountryInfo = () => {
const { country } = this.props;
this.setState({
country
});
}
toFetchCountryNum = () => {
const { history, hideBindPhone } = this.props;
hideBindPhone();
history.push('/country?from=bind');
}
getCaptchaInstance = instance => {
this.captchaInstance = instance;
}
onVerify = (err, data) => {
if (err) {
console.log(err);
} else {
this.setState({
validate: data.validate
});
}
}
// 获取手机号验证码
handleToSend = ({tel, code}) => {
let { validate, seconds, isFirst, isTimer, country: {num = '86'} } = this.state;
if(validate) {
if (!isFirst) {
Toast.info('请重新进行滑块验证', 2, null, false);
this.captchaInstance.refresh();
this.setState({
isFirst: true
});
return
}
if(!isTimer) {
if (!tel) {
Toast.info('手机号码不能为空', 2, null, false);
}else if(!/^\d+$/.test(tel)) {
Toast.info('请输入正确格式的手机号码', 2, null, false);
}else {
// 获取验证码
http.post(
`${API['passport-api']}/m/personal/bindPhoneSendCode`,
{
area_code: `00${num}`,
phone_num: tel
}
).then(res => {
const { errno, msg } = res.data;
if(errno === 200) {
Toast.info('验证码发送成功', 2, null, false);
// 倒计时
this.timer = window.setInterval(() => {
if (seconds <= 0) {
window.clearInterval(this.timer);
this.setState({
isTimer: false,
seconds: 60
});
}else {
this.setState({
isTimer: true,
seconds: --seconds
});
}
}, 1000);
// 滑块
this.setState({
isFirst: false
})
}else {
Toast.info(msg, 2, null, false);
}
})
}
}
}
return false;
}
// 绑定手机
toBindPhone = () => {
const { accountInfo: { tel, code }, country: {num = '86'} } = this.state;
const { handleToConfirmPhone, successBindPhone } = this.props;
const params = {
area_code: `00${num}`,
mobile: tel,
code: code,
act_type: 'treasure', // 宝箱
};
http.post(
`${API.home}/sys/v2/user/bindMobile`,
{
...params,
type: 1, // 1:绑定,2:修改绑定
is_valid: 1, // is_valid 是否验证 1:验证(默认),0不验证
}
).then(res => {
const { code, data, msg } = res.data;
if(code === 200 ) {
if(data.tip_info) {
handleToConfirmPhone(params, data.tip_info);
}else {
successBindPhone();
}
}else {
Toast.info(msg, 2, null, false);
}
});
}
render() {
const { desc, skip = 'year' } = this.props;
const { country, validate, isTimer, seconds } = this.state;
return (
<Formik
initialValues={{
tel: '',
code: ''
}}
validate={({tel, code}) => {
const errors = {};
// if (!validateTel(tel)) {
if(!/^\d+$/.test(tel)) {
errors.tel = '请填写正确格式的手机号';
}
if (!/[0-9]{6}/.test(code)) {
errors.code = '请输入验证码';
}
return errors;
}}
onSubmit={(values, { setStatus, setSubmitting }) => {
this.setState({
accountInfo: {
...values
}
});
this.toBindPhone();
}}
render={({values: {tel, code}, errors}) => (
<Form className="popup-form" data-skip={skip}>
<h2 className="popup-form__title">绑定手机号</h2>
{
desc &&
<div className="poup-form__desc">{desc}</div>
}
<div className="popup-form__item">
<a className="popup-form__button--num" onClick={this.toFetchCountryNum}>
+{country.num}
<i className="iconfont iconiconfront-69"/>
</a>
<Field
name="tel"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt"
data-type="tel"
type="text"
placeholder="请填写手机号"
/>
);
}}
/>
</div>
<Captcha
getInstance={this.getCaptchaInstance}
onVerify={this.onVerify}
/>
<div className="popup-form__item">
<Field
name="code"
render={({field}) => {
return (
<input
{...field}
className="popup-form__ipt popup-form__ipt--left"
type="text"
placeholder="输入验证码"
/>
);
}}
/>
<button
className="popup-form__button--code"
data-status={(validate && !isTimer)? 'do': ''}
type="button"
onClick={() => this.handleToSend({tel, code})}
>
{
isTimer? `重新发送${seconds}s` : '发送验证码'
}
</button>
</div>
<button
className="popup-form__button--bundle"
data-status={(tel && code && isEmpty(errors))? 'do': 'done'}
type="submit"
>
完成绑定
</button>
</Form>
)}
/>
)
}
}
export default BindPhone;
\ No newline at end of file
// form
// .popup-form {
// text-align: center;
.popup-packet__button--bundle {
margin-top: 5px;
}
// }
[data-skip="default"] {
.popup-form__item {
height: 36px;
}
.popup-form__button--num {
border: 1px solid #99D6FF;
border-right-style: none;
border-radius: 6px 0 0 6px;
}
.popup-form__button--code {
border-radius: 6px;
}
.popup-form__button--bundle {
width: 161px;
height: 30px;
border-radius: 15px;
font-size: 13px;
}
.popup-form__ipt {
border: 1px solid #99D6FF;
border-radius: 6px;
&[data-type="tel"] {
border-left-style: none;
border-radius: 0 6px 6px 0;
}
}
}
[data-skip="year"] {
.popup-form__title {
margin: 10px 0 0;
font-size: 18px;
color: #111;
text-align: center;
line-height: 1;
}
.popup-form__item {
width: 269px;
height: 40px;
}
.popup-form__button--num {
border: 1px solid #CDCDCD;
border-right-style: none;
border-radius: 3px 0 0 3px;
}
.popup-form__button--code {
border-radius: 3px;
}
.popup-form__button--bundle {
width: 270px;
height: 44px;
margin-bottom: 14px;
border-radius: 5px;
font-size: 16px;
}
.popup-form__ipt {
border: 1px solid #CDCDCD;
border-radius: 3px;
&[data-type="tel"] {
border-left-style: none;
border-radius: 0 3px 3px 0;
}
}
}
.captcha-container {
width: 269px;
height: 40px;
margin: 0 auto 15px;
}
.popup-form {
// width: 290px;
// height: 257px;
// padding: 20px 20px 0;
box-sizing: border-box;
}
.popup-form__item {
display: flex;
align-items: center;
justify-content: center;
margin: 0 auto 15px;
.popup-form__ipt {
flex: 1;
}
.popup-form__ipt--left {
width: 130px;
}
.popup-form__button--code {
margin-left: 10px;
}
}
.popup-form__button--num {
display: block;
position: relative;
height: 36px;
padding: 0 8px;
box-sizing: border-box;
font-size: 14px;
color: #333;
line-height: 36px;
&::after {
display: block;
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
width: 1px;
height: 14px;
margin: auto 0;
background-color: #AAAAAA;
}
.iconfont {
font-size: 12px;
color: #333;
}
}
.popup-form__ipt {
height: 36px;
padding: 0 8px;
box-sizing: border-box;
font-size: 12px;
color: #999;
line-height: 36px;
outline: none;
&[data-type="tel"] {
border-left-style: none;
}
}
.popup-form__tip {
margin: 0;
font-size: 12px;
color: #FF3131;
.iconfont {
font-size: 15px;
color: #FF3131;
}
}
.popup-form__button--code {
width: 110px;
height: 36px;
padding: 0;
border: 1px solid #E5E5E5;
box-sizing: border-box;
font-size: 13px;
color: #999;
text-align: center;
line-height: 36px;
background-color: transparent;
&[data-status='do'] {
border-color: #0099FF;
color: #0099FF;
}
}
.popup-form__button--bundle {
display: block;
padding: 0;
margin: 0 auto;
border-style: none;
color: #2B2B2B;
background-color: #F9DB4A;
cursor: pointer;
&[data-status="done"] {
color: #fff;
background-color: #ABABAB;
}
&[data-status='do'] {
color: #fff;
background-color: #0099FF;
}
}
\ No newline at end of file
......@@ -3,11 +3,25 @@ import ReactDOM from 'react-dom'
import './index.scss'
import classnames from 'classnames'
const re = /(https?|ftp):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/
function ClosablePopup({
title, content, className, closable = true, close = function () {
title,
content,
className,
closable = true,
close = function () {
},
clickMaskClose = true,
closeIcon = 'iconiconfront-2',
afterClose = function () {
},
remove = function () {
}
} = {}) {
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
......@@ -20,22 +34,36 @@ function ClosablePopup({
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
afterClose()
})
} else {
unmountComponent()
afterClose()
}
}
function clickMask() {
if (closable) {
return
}
if (!clickMaskClose) {
return
}
_close()
}
const closablePopup = (
<div className={'closable-popup-mask'}>
<div className={'closable-popup-mask'} onClick={clickMask}>
<div className={classnames(['popup-container', className])}>
<div className="title">{title}</div>
<div className="content">
{content}
</div>
{
closable && <i className={'close iconfont iconiconfront-2'} onClick={_close}/>
closable &&
(re.test(closeIcon)
? <img src={closeIcon} alt="" className={'close-icon'} onClick={_close}/>
: <i className={`close iconfont ${closeIcon}`} onClick={_close}/>)
}
</div>
</div>
......@@ -47,7 +75,8 @@ function ClosablePopup({
ReactDOM.render(closablePopup, div)
return {
close: _close
close: _close,
remove: unmountComponent
}
}
......
......@@ -31,5 +31,16 @@
font-size: 36px;
color: #fff;
}
.close-icon {
position: absolute;
bottom: -66px;
left: 50%;
width: 33px;
height: 33px;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
}
}
import React, { Component } from 'react';
import { Toast } from 'antd-mobile';
import { http } from '@/utils';
import './index.scss';
class ConfirmPhone extends Component {
continueBindPhone = () => {
const { data, successBindPhone } = this.props;
http.post(
`${API.home}/sys/v2/user/bindMobile`,
{
...data,
type: 1, // 1:绑定,2:修改绑定
is_valid: 0, // is_valid 是否验证 1:验证(默认),0不验证
}
).then(res => {
const { code, msg } = res.data;
if(code === 200 ) {
successBindPhone();
}else {
Toast.info(msg, 2, null, false);
}
});
}
render() {
const {
bindInfo = { },
desc,
skip = 'year',
handleToCancle
} = this.props;
return (
<div className="popup-bind" data-skip={skip}>
<h2 className="popup-bind__title">绑定手机号</h2>
{
desc
? <div className="popup-bind__desc">{desc}</div>
: <p className="popup-bind__desc">该手机号已绑定到以下账号,继续绑定将解除以下绑定状态</p>
}
<ul className="popup-bind__list">
{
bindInfo['email'] &&
<li className="popup-bind__account">
{/* 邮箱 */}
<i className="popup-bind__icon" data-plat="mail"></i>
<p className="popup-bind__account--name">{bindInfo['email']}</p>
</li>
}
{
bindInfo['wechat_nickname'] &&
<li className="popup-bind__account">
{/* wechat */}
<i className="popup-bind__icon" data-plat="wachat"></i>
<p className="popup-bind__account--name">{bindInfo['wechat_nickname']}</p>
</li>
}
{
bindInfo['qq_nickname'] &&
<li className="popup-bind__account">
{/* qq */}
<i className="popup-bind__icon" data-plat="qq"></i>
<p className="popup-bind__account--name">{bindInfo['qq_nickname']}</p>
</li>
}
{
bindInfo['sina_nickname'] &&
<li className="popup-bind__account">
{/* 微博 */}
<i className="popup-bind__icon" data-plat="sina"></i>
<p className="popup-bind__account--name">{bindInfo['sina_nickname']}</p>
</li>
}
</ul>
<div className="popup-bind__footer">
<button
className="popup-bind__button popup-bind__button--cancle"
onClick={handleToCancle}>取消</button>
<button
className="popup-bind__button popup-bind__button--confirm"
onClick={this.continueBindPhone}>继续绑定</button>
</div>
</div>
)
}
}
export default ConfirmPhone;
\ No newline at end of file
[data-skip="default"] {
.popup-bind__desc {
width: 249px;
font-size: 15px;
color: #666;
line-height: 21px;
}
.popup-bind__account {
padding: 4px;
}
.popup-bind__account--name {
padding-left: 7px;
font-size: 12px;
color: #999;
}
.popup-bind__icon {
width: 22px;
height: 22px;
}
.popup-bind__footer {
padding: 0 18px;
}
.popup-bind__button {
width: 105px;
height: 30px;
border-radius: 15px;
font-size: 14px;
}
.popup-bind__button--cancle {
border: 1px solid #0099FF;
color: #0099FF;
}
.popup-bind__button--confirm {
border-style: none;
color: #fff;
background-color: #0099FF;
}
}
[data-skip="year"] {
.popup-bind__title {
margin: 10px 0 0;
font-size: 18px;
color: #111;
line-height: 1;
text-align: center;
}
.popup-bind__desc {
width: 269px;
font-size: 12px;
color: #FF2121;
line-height: 18px;
}
.popup-bind__account {
padding: 14px 4px;
}
.popup-bind__account--name {
padding-left: 12px;
font-size: 15px;
color: #090909;
}
.popup-bind__icon {
width: 33px;
height: 33px;
}
.popup-bind__footer {
padding: 0 15px;
margin-bottom: 14px;
}
.popup-bind__button {
width: 130px;
height: 44px;
border-radius: 5px;
font-size: 16px;
}
.popup-bind__button--cancle {
border: 1px solid #090909;
color: #090909;
}
.popup-bind__button--confirm {
border: 1px solid #090909;
color: #090909;
background-color: #FFE319;
}
}
.popup-bind {
text-align: center;
}
.popup-bind__desc {
margin: 10px 15px 0;
text-align: left;
}
.popup-bind__list {
padding: 0 0 10px;
}
.popup-bind__account {
display: flex;
align-items: center;
margin: 0 52px;
text-align: left;
&:nth-child(n+2) {
border-top: 1px solid #E5E5E5;
}
}
.popup-bind__account--name {
margin: 0;
}
.popup-bind__icon {
display: inline-block;
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center;
&[data-plat="mail"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-mail.png');
}
&[data-plat="sina"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-sina.png');
}
&[data-plat="qq"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-qq.png');
}
&[data-plat="wachat"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-wechat.png');
}
}
.popup-bind__footer {
display: flex;
align-items: center;
justify-content: space-between;
}
.popup-bind__button {
box-sizing: border-box;
cursor: pointer;
outline: none;
}
.popup-bind__button--cancle {
background-color: transparent;
}
\ No newline at end of file
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -740,6 +740,10 @@
// //}
}
.index-box + .nav-bar + .year19-index{
display: none;
}
.borderTop {
width: 100%;
height: 8px;
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -6,13 +6,13 @@
.banner__con {
width: 100%;
height: 170px;
background: url('./images/formal-banner.png') center center no-repeat;
background: url('images/formal-banner.png') center center no-repeat;
background-size: 100% 100%;
}
.content__con {
width: 100%;
height: 454px;
background: url('./images/dalibao_bj.png') center center no-repeat;
background: url('images/dalibao_bj.png') center center no-repeat;
background-size: 100% 100%;
position: relative;
......@@ -55,7 +55,7 @@
.img__con {
width: 88px;
height: 16px;
background: url('./images/value.png') center center no-repeat;
background: url('images/value.png') center center no-repeat;
background-size: 100% 100%;
margin-left: 4px;
}
......@@ -186,7 +186,7 @@
font-weight:400;
color:rgba(255,255,255,1);
width: 240px;
background: url('./images/yaoqh_bj.png') center center no-repeat;
background: url('images/yaoqh_bj.png') center center no-repeat;
background-size: 100% 50%;
text-align: center;
text-align-last: center;
......@@ -292,7 +292,7 @@
.share__row {
width: 60px;
height: 44px;
background: url('./images/throw_icon.png') center center no-repeat;
background: url('images/throw_icon.png') center center no-repeat;
background-size: 100% 100%;
position: absolute;
right: 15px;
......
.box-container {
position: relative;
background: #327443 url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/sd_nr_bj2.png") repeat-y;
background-size: 100% auto;
padding: 14px 0;
.image-box {
height: 100%;
}
@mixin common-deco($bg) {
content: '';
position: absolute;
left: 0;
width: 100%;
height: 14px;
display: block;
background: url($bg) no-repeat;
background-size: 375px auto;
}
&::before {
@include common-deco("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/sd_nr_bj1.png");
top: 0;
}
&::after {
@include common-deco("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/sd_nr_bj3.png");
bottom: 0;
}
}
import React, { Component } from 'react'
import './box-container.scss'
class Container extends Component {
render() {
return (
<div className={'box-container'}>
<div className="image-box">
{this.props.children}
</div>
</div>
)
}
}
export default Container
import React, { Component } from 'react'
import './index.scss'
export default class CommonContainer extends Component {
constructor(props) {
super(props)
}
render() {
const { id } = this.props;
return (
<div className='common_container' id={id}>
<div className='container_top'></div>
<div className='container_content'>
{
this.props.title &&
<div className='title_container'>
<i></i>
<p>{this.props.title}</p>
<i></i>
</div>
}
{
React.Children.map(this.props.children, function (child) {
return <>{child}</>;
})
}
</div>
<div className='container_bottom'></div>
</div>
)
}
}
.common_container {
margin-bottom: 35px;
.title_container {
width: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-content: center;
i {
width: 230px;
height: 2px;
margin: auto;
background: linear-gradient(
90deg,
rgba(254, 228, 29, 0) 0%,
rgba(254, 228, 29, 0.98) 48%,
rgba(254, 228, 29, 0) 100%
);
margin: 0 auto;
}
p {
font-size: 18px;
line-height: 18px;
font-weight: 500;
color: rgba(254, 228, 29, 1);
margin: 8px auto;
background: linear-gradient(
0deg,
rgba(254, 228, 29, 1) 23.9013671875%,
rgba(255, 204, 0, 1) 50.146484375%,
rgba(254, 228, 29, 1) 75%
);
background-clip: text;
-webkit-text-fill-color: transparent;
}
}
.container_top {
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_top_bj.png")
center center no-repeat;
background-size: 100% 100%;
width: 100%;
height: 18px;
}
.container_bottom {
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_bottom_bj.png")
center center no-repeat;
background-size: 100% 100%;
width: 100%;
height: 22px;
}
.container_content {
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_middle_bj.png");
background-size: contain;
width: 100%;
min-height: 25px;
margin: -1px 0;
padding: 6px 15px;
}
}
import React, { Component } from 'react';
import './index.scss';
export default class index extends Component {
constructor(props) {
super(props);
}
computedStyle = () => {
return {
'top': `${this.props.top}px`,
'width': `${this.props.width}px`
}
}
// 控制点击空白处是否关闭弹窗 需要传递一个boolean属性 mark
closePopup = () => {
if(this.props.mark) {
this.props.closePopup();
}
}
render() {
return (
<div className='popup__container' onClick={this.closePopup}>
<div className='content__container' style={this.computedStyle()} onClick={(e) => {e.stopPropagation()}}>
<img className="close__btn" onClick={this.props.closePopup} src='https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png' alt="" />
{
React.Children.map(this.props.children, function (child) {
return <>{child}</>;
})
}
</div>
</div>
)
}
}
.popup__container {
position: fixed;
left: 0;
top: 0;
width: 100vw;
height: 100vh;
background: rgba(0, 0, 0, 0.6);
z-index: 99;
.content__container {
width: 320px;
min-height: 240px;
border-radius: 5px;
background: rgba(255,255,255,1);
position: absolute;
left: 50%;
transform: translateX(-50%);
top: 160px;
.close__btn {
position: absolute;
left: 50%;
transform: translateX(-50%);
width: 33px;
height: 33px;
bottom: -57px
}
}
}
\ No newline at end of file
import React from 'react';
import './index.scss';
export default (props) => {
console.log(props);
const {
data: {
team_num = 1,
lack_member = 4,
member = [],
},
handleToInvite
} = props;
const members = new Array(5).fill({});
return (
<div className="team-success">
<h2 className="team-success__title">创建成功</h2>
<p className="team-success__tip">
{<span>{team_num}</span>}号队伍 还差{<span>{lack_member}</span>}名队员即可获得宝箱哦~
</p>
<i className="team-success__icon"></i>
<ul className='team-success__member members'>
{
members.map((item, index) => {
const _member = member[index]
return (
<li className="member-item" key={index}>
{
_member && _member['is_captain'] && <sup className="member-item__captain">队长</sup>
}
<img
className="member-item__avatar"
src={
_member
? _member['head_img']
: "https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/not-joined-placeholder.png"
}
alt=""/>
</li>
);
})
}
</ul>
<button type={'button'} className="team-success__button" onClick={handleToInvite}>邀请好友加入队伍</button>
</div>
)
}
\ No newline at end of file
.team-success__title {
margin: 10px 0 0;
font-size: 18px;
color: #111;
text-align: center;
line-height: 1;
}
.team-success__tip {
margin: 12px 0 0;
font-size: 15px;
color: #666;
text-align: center;
line-height: 1;
span {
color: #FF2121;
}
}
.team-success__icon {
display: block;
width: 120px;
height: 72px;
margin: 20px auto;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/treasure-box-icon.png');
}
.team-success__member {
display: flex;
padding: 0 12px;
.member-item {
position: relative;
margin: 0 8px;
}
.member-item__captain {
position: absolute;
top: -13px;
right: -10px;
width: 30px;
height: 16px;
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 8px 8px 8px 0;
color: #0E7442;
font-size: 10px;
text-align: center;
line-height: 16px;
background: rgba(255, 227, 0, 1);
}
.member-item__avatar {
width: 44px;
height: 44px;
border-radius: 50%;
}
}
.team-success__button {
display: block;
width: 270px;
height: 44px;
margin: 20px auto;
padding: 0;
border: 1px solid #090909;
border-radius: 5px;
box-sizing: border-box;
font-size: 16px;
color: #090909;
line-height: 44px;
background-color: #FFE319;
}
\ No newline at end of file
import React, { Component } from 'react'
import { http } from "@/utils"
import './prizes.scss'
import { Popup } from "@common/index"
import { Toast } from "antd-mobile"
import Loadable from '@loadable/component'
const SystemBulletScreen = Loadable(() => import(/* webpackChunkName: 'system-notices' */'@components/activity/newyear-2019/common/system-bullet-screen'))
class Prizes extends Component {
prizeBox
prizeList
bg
innerBox
closeIcon = 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png'
state = {
prizes: [],
notices: [],
rule: [],
unfoldList: false,
}
componentDidMount() {
this.getPrizes()
}
getPrizes = () => {
http.get(`${API.home}/sys/prize_data`)
.then(res => {
const {code, data, msg} = res.data
if (code == 200) {
this.setState({
prizes: data['prize_data'],
notices: data['notices'],
rule: data['rule']
})
} else {
Toast.info(msg, 2, null, false)
}
})
}
showRules = () => {
Popup({
title: '组队开宝箱活动规则',
className: 'landing-treasure-rules',
content: <div dangerouslySetInnerHTML={{__html: this.state.rule}}/>,
closeIcon: this.closeIcon
})
}
showMore = () => {
this.setState(prev => {
if (this.state.unfoldList) {
this.bg.style = this.innerBox.style = this.prizeBox.style = ''
} else {
let headHeight = parseFloat(getComputedStyle(this.prizeBox, ':before').getPropertyValue('height')),
footerHeight = parseFloat(getComputedStyle(this.prizeBox, ':after').getPropertyValue('height')),
innerOffsetTop = 0.12458,
footerOffsetTop = 0.595,
h = this.prizeList.scrollHeight,
scrollListHeight = headHeight + h - (innerOffsetTop * headHeight) - (footerOffsetTop * footerHeight) + footerHeight,
bottomOffset = 27
this.prizeBox.style.height = `${scrollListHeight + bottomOffset}px`
this.innerBox.style.height = `${h}px`
this.bg.style.height = `${h - footerHeight + innerOffsetTop * headHeight + bottomOffset}px`
}
return {unfoldList: !prev.unfoldList}
})
}
render() {
const {
showSystemNotices
} = this.props
const {notices} = this.state
return (
<>
{(showSystemNotices && notices && notices.length) ? <SystemBulletScreen bullets={notices}/> : null}
<div className={'prizes-box'} ref={el => this.prizeBox = el}>
<a href="javascript:;" className='rule-btn' onClick={this.showRules}>活动规则 > </a>
<div className={`bg`} ref={el => this.bg = el}/>
<div className={`inner-box`} ref={el => this.innerBox = el}>
<ul className='prize-list' ref={el => this.prizeList = el}>
{
this.state.prizes.map((item, index) => {
return (
<li key={index}>
{
item.img_name
? <i className="prize-list__image" style={{
backgroundImage: `url(${item.img_name})`
}}/>
: <i className="prize-list__image"/>
}
{/* <img src={item.img_name} alt=""/> */}
{
item.is_captain != 0 && <span className='captain top-tag'>队长专属</span>
}
{
item.mode === 2 && <span className='stage top-tag'>{item.stage_no}个必中</span>
}
{
item.grant_max
?
<div className='bottom-bar'>
<div className="progress-bar"><span className={'progress'}/></div>
<span>限量{item.grant_max}</span>
</div>
: <span className='no-limit'>不限量</span>
}
</li>
)
})
}
<li>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/prize-placeholder.png" alt=""/>
</li>
</ul>
</div>
<div className="show-more" onClick={this.showMore}>
{
this.state.unfoldList
? <div>
收起
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/fold-icon.png" alt=""/>
</div>
: <div>
查看全部奖品
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/unfold-icon.png" alt=""/>
</div>
}
</div>
</div>
</>
)
}
}
export default Prizes
.trans-height {
transition: height .25s ease-in-out;
}
.prizes-box {
@extend .trans-height;
position: relative;
height: 348px;
background-size: 100% auto;
.show-more {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
width: 125px;
height: 27px;
background: #FF2121;
border: 2px solid rgba(255, 33, 33, 1);
border-radius: 5px 5px 0 0;
font-size: 13px;
color: #fff;
line-height: 27px;
text-align: center;
z-index: 20;
img {
margin-left: 4.5px;
width: 10.05px;
}
}
.rule-btn {
position: absolute;
top: 32.5px;
left: 50%;
transform: translateX(-50%);
color: #FFDD1D;
font-size: 12px;
text-decoration: underline;
}
@mixin common-deco($bg) {
content: '';
display: block;
width: 100%;
background: url($bg) no-repeat;
background-size: 100% auto;
}
&::before {
@include common-deco('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/landing-box-head.png');
height: 148.5px;
}
&::after {
@include common-deco('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/landing-box-footer.png');
height: 85px;
margin-top: -1px;
}
.bg {
@extend .trans-height;
width: 100%;
height: 115px;
margin-top: -1px;
overflow: hidden;
z-index: 10;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/landing-box-bg.png") repeat-y;
background-size: 100% auto;
}
.inner-box {
@extend .trans-height;
position: absolute;
top: 130px;
left: 0;
width: 100%;
z-index: 20;
height: 187px;
overflow: hidden;
}
.prize-list {
display: flex;
flex-flow: wrap;
padding: 0 57px;
& li:nth-of-type(2n) {
margin-right: 0;
}
li {
position: relative;
width: 125px;
height: 99px;
background: rgba(255, 255, 255, 1);
border: 2px solid rgba(255, 227, 0, 1);
box-shadow: 0 2px 4px 0 rgba(0, 0, 0, 0.1);
border-radius: 1px;
margin-right: 10.5px;
margin-bottom: 6.5px;
.prize-list__image {
display: block;
width: 100%;
height: 100%;
background-position: center;
background-size: cover;
}
img {
width: 90px;
object-fit: contain;
}
}
& li:last-child {
display: flex;
align-items: center;
justify-content: center;
}
.top-tag {
position: absolute;
top: 0;
right: 0;
border-radius: 0 0 0 4px;
font-size: 12px;
line-height: 16px;
text-align: center;
padding: 0 4px;
color: #fff;
}
.captain {
background: linear-gradient(270deg, rgba(255, 93, 0, 1) 0%, rgba(255, 23, 0, 1) 100%);
}
.stage {
background: linear-gradient(-90deg, rgba(0, 75, 251, 1) 0%, rgba(0, 156, 255, 1) 100%);
}
.no-limit {
position: absolute;
bottom: 0;
right: 0;
background: rgba(0, 0, 0, .8);
font-size: 12px;
color: #fff;
padding: 0 4px;
border-radius: 6px 0 0 0;
}
.bottom-bar {
position: absolute;
bottom: 0;
left: 0;
width: 100%;
//height: 18px;
padding: 0 5px;
display: flex;
justify-content: space-between;
align-items: center;
background: rgba(0, 0, 0, .8);
font-size: 12px;
color: #fff;
.progress-bar {
position: relative;
flex: 0 1 45px;
height: 2px;
background: #fff;
border-radius: 1px;
.progress {
position: absolute;
right: 0;
top: 0;
width: 80%;
height: 100%;
background: linear-gradient(-90deg, rgba(255, 140, 0, 1) 0%, rgba(255, 23, 0, 1) 100%);
border-radius: 1px;
}
}
}
}
}
.common_container {
.container_content {
.prizes-box {
margin: 0 -15px;
}
}
}
.landing-treasure-rules {
width: 320px;
&.popup-container {
top: 50%;
transform: translate(-50%, -50%);
.title {
font-size: 18px;
color: #111111;
}
}
.content {
padding: 0 19px 15px;
margin-top: 22px;
color: #666666;
font-size: 14px;
li {
margin-bottom: 5px;
}
}
}
import React, { Component } from 'react';
import { http } from '@/utils';
import './index.scss';
class SplitSuccess extends Component {
computedBg = (val) => {
return val? {
backgroundImage: `url(${val})`
} : {};
}
continueSplitTreasure = () => {
const { ids, successSplitTreasure, handleToBindPhone, handleToBindAddress } = this.props;
const params = ids[0];
http.post(`${API.home}/sys/split_treasure`, params).then(res => {
const { code, data } = res.data;
if(code === 200) {
successSplitTreasure(data);
if(data.bind_phone) {
setTimeout(() => {
handleToBindPhone(data.id);
}, 500);
}else if(data.bind_address) {
setTimeout(() => {
handleToBindAddress(data.id, data.prize_name);
}, 500);
}
}else if(code === 12000) {
// 请先绑定手机号再拆宝箱
handleToBindPhone();
}else if(code === 12001) {
// 请先填写收货地址再拆宝箱
handleToBindAddress();
}
});
}
render() {
const {
ids,
data: {
member = [],
prize_img,
prize_name,
},
handleToInvite,
children,
} = this.props;
return (
<div data-skip="split">
<h2 className="split-success__title">恭喜你获得</h2>
<div className="split-success__image">
<img src={prize_img} alt=""/>
</div>
<p className="split-success__prize">{prize_name}</p>
{children}
<div className="split-success__member">
{
member.map((item, index) => (
<div className="member-item" key={index}>
<span className="member-item__avatar" style={this.computedBg(item.avatar)}>
{
item.is_captain && <i className="member-item__captain">队长</i>
}
</span>
{
item.prize
? <span className="member-item__prize">{item.prize}</span>
: <span className="member-item__prize">尚未开宝箱</span>
}
</div>
))
}
</div>
{
ids.length > 0
? <button className="split-success__jump" onClick={this.continueSplitTreasure}>继续开宝箱</button>
: <button className="split-success__jump" onClick={handleToInvite}>继续组队开宝箱</button>
}
</div>
);
}
}
export default SplitSuccess;
\ No newline at end of file
[data-skip="split"] {
text-align: center;
.split-success__title {
margin: 10px 0 0;
font-size: 18px;
color: #111;
line-height: 1;
}
.split-success__image {
width: 130px;
height: 103px;
margin: 12px auto 0;
border: 2px solid #CDCDCD;
box-sizing: border-box;
overflow: hidden;
img {
display: block;
width: 100%;
}
}
.split-success__prize {
margin: 8px 0 0;
font-size: 15px;
font-weight: 500;
color: #FF232D;
text-align: center;
line-height: 1;
}
.team-result {
display: inline-block;
margin: 8px 0 0;
font-size: 12px;
color: #666;
text-align: center;
line-height: 1;
span {
text-decoration: underline;
}
}
.split-success__member {
margin: 18px 18px 0;
padding: 4px 12px;
border-radius: 6px;
background-color: #EFEFEF;
}
.member-item {
display: flex;
align-items: center;
margin: 8px 0;
}
.member-item__avatar {
display: inline-block;
position: relative;
width: 25px;
height: 25px;
border-radius: 50%;
background-color: #fff;
background-size: cover;
}
.member-item__captain {
position: absolute;
top: -14px;
right: -18px;
width: 30px;
height: 18px;
border: 1px solid #fff;
border-radius: 9px 9px 9px 0;
font-size: 12px;
font-style: normal;
color: #0B7B45;
text-align: center;
background-color: #FFE319;
}
.member-item__prize {
padding-left: 8px;
font-size: 12px;
color: #090909;
}
.split-success__jump {
width: 270px;
height: 44px;
margin: 18px 25px 8px;
border: 1px solid #090909;
border-radius: 5px;
box-sizing: border-box;
font-size: 16px;
color: #090909;
text-align: center;
line-height: 44px;
background-color: #FFE319;
}
}
\ No newline at end of file
import React, { Component } from 'react'
import Swiper from 'swiper'
import 'swiper/dist/css/swiper.min.css'
import './system-bullet-screen.scss'
class SystemBulletScreen extends Component {
swiper
count = 0
sysNotice
state = {
showNotices: true
}
componentDidMount() {
this.initializeSwiper()
}
componentWillUnmount() {
this.swiper && this.swiper.destroy()
}
initializeSwiper = () => {
const _this = this
this.swiper = new Swiper('.sys-bullet-screen-swiper-container', {
allowTouchMove: false,
direction: 'vertical',
loop: true,
on: {
init() {
Array.from(this.slides).forEach(item => {
item.querySelector('span').addEventListener('transitionend', _this.transitionEnd)
})
},
slideChangeTransitionEnd() {
_this.slideHorizontal(this)
},
transitionEnd() {
const el = this.slides[this.previousIndex].querySelector('span')
el.style.transition = 'unset'
el.style.transform = 'translate3d(0,0,0)'
}
}
})
}
slideHorizontal = (swiper) => {
let el = swiper.slides[swiper.activeIndex],
content = el.querySelector('span'),
contentWidth = content.offsetWidth,
wrapperWidth = el.clientWidth
const co = 131.25
if (contentWidth > wrapperWidth) {
content.style.transition = `transform ${contentWidth / co}s linear`
setTimeout(() => {
content.style.transform = `translate3d(${-(contentWidth - wrapperWidth) - 10}px,0,0)`
}, 1000)
} else {
const {bullets} = this.props
const len = bullets.length * 3
setTimeout(() => {
if (++this.count === len) {
this.sysNotice.style.height = `0px`
}
(swiper && !swiper.destroyed) && swiper.slideNext()
}, 3000)
}
}
transitionEnd = () => {
const {bullets} = this.props
const len = bullets.length * 3
if (++this.count === len) {
setTimeout(() => {
this.sysNotice.style.height = `0px`
}, 2000)
} else {
setTimeout(() => {
this.swiper && this.swiper.slideNext()
}, 1000)
}
}
removeSystemNotices = e => {
e.persist()
if (e.target === this.sysNotice) {
this.setState({
showNotices: false
})
}
}
render() {
const {
bullets
} = this.props
return (
this.state.showNotices &&
<div id="system-bullet-screen" onTransitionEnd={this.removeSystemNotices} ref={el => this.sysNotice = el}>
<img className='avatar'
src='https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/system-notice-icon.png' alt=""/>
<div className='sys-bullet-screen-swiper-container'>
<ul className="swiper-wrapper">
{
(bullets && bullets.length) ? bullets.map((item, index) => {
return (
<li className="swiper-slide" key={index}>
<span>{item}</span>
</li>
)
})
: null
}
</ul>
</div>
</div>
)
}
}
export default SystemBulletScreen
@import "../user-bullet-screen/bullet-screen";
#system-bullet-screen {
@extend .bullet-screen;
overflow: hidden;
margin-top: 11px;
margin-bottom: 16px;
padding-left: 2px;
display: flex;
align-items: center;
transition: height .1s ease-out;
.sys-bullet-screen-swiper-container{
height: 100%;
}
ul {
flex: auto;
max-width: 293px;
}
li {
overflow: hidden;
height: 30px;
span {
display: inline-block;
white-space: nowrap;
overflow: visible;
line-height: 30px;
}
}
}
.bullet-screen{
width: 329px;
height: 30px;
margin: 0 auto 28px;
background: rgba(0, 0, 0, .6);
border-radius: 15px;
line-height: 30px;
text-align: left;
li {
height: 100%;
padding: 2px;
line-height: 26px;
display: flex;
align-items: center;
}
.avatar {
width: 26px;
height: 26px;
border-radius: 50%;
margin-right: 7px;
vertical-align: middle;
}
& span:nth-of-type(1) {
margin-right: 5px;
}
span {
font-size: 12px;
color: #fff;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
#user-bullet-screen {
@extend .bullet-screen
}
import React, { Component } from 'react'
import { http } from "@/utils"
import Swiper from 'swiper'
import 'swiper/dist/css/swiper.min.css'
import './bullet-screen.scss'
class UserBulletScreen extends Component {
swiper
state = {
bulletScreenData: []
}
componentDidMount() {
this.getBulletScreenData(true)
}
componentWillUnmount() {
this.swiper && this.swiper.destroy()
}
initializeBulletScreen = () => {
const _this = this
const slidesPerRequest = 20
const indexArray = [...Array(slidesPerRequest - 1).keys()]
let removed = false
this.swiper = new Swiper('.swiper-container', {
direction: 'vertical',
allowTouchMove: false,
autoplay: true,
on: {
transitionEnd() {
if (this.slides.length > slidesPerRequest) {
this.removeSlide(0)
this.autoplay.start()
}
if (this.activeIndex === this.slides.length - 1 && !removed) {
this.autoplay.stop()
_this.getBulletScreenData().then(res => {
removed = true
this.removeSlide(indexArray)
this.appendSlide(_this.getSlides(res))
setTimeout(() => {
this.autoplay.start()
removed = false
})
})
}
}
}
})
}
getSlides = list => list.map(item => {
return `
<li class="swiper-slide">
<img class="avatar" src="${item.avatar_file}" alt="">
<span>${item.user_name} ${item.msg}</span>
</li>
`
})
getBulletScreenData = (initializeSwiper = false) => {
return http.get(`${API.home}/sys/barrage_data`)
.then(res => {
const {data, code} = res.data
if (code == 200) {
if (initializeSwiper) {
this.setState({
bulletScreenData: data
}, () => {
this.initializeBulletScreen()
})
} else {
return data
}
}
})
}
render() {
const {bulletScreenData} = this.state
return (
<div id="user-bullet-screen" className='swiper-container'>
<ul className='swiper-wrapper'>
{
bulletScreenData.length && bulletScreenData.map((item, index) => {
return (
<li className='swiper-slide' key={index}>
<img src={item['avatar_file']}
alt="" className="avatar"/>
<span>{item.user_name} {item.msg}</span>
</li>
)
})
}
</ul>
</div>
)
}
}
export default UserBulletScreen
import React, { Component } from 'react'
import BoxContainer from '../box-container/container'
import { Toast, WhiteSpace } from "antd-mobile"
import { Popup } from "@common/index"
import { connect } from "react-redux"
import Prizes from "@components/activity/newyear-2019/common/prizes"
import BulletScreen from "@components/activity/newyear-2019/common/user-bullet-screen"
import './landing.scss'
import { browser, getParam, http, wxShare, SendMessageToApp } from "@/utils"
import QRCode from "qrcode"
import YearCourse from '../preheat/YearCourse'
import { FadeLoader } from "react-spinners"
class Landing extends Component {
closeIcon = 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png'
createTeamSuccessPopup = null
joinSuccessPopup = null
shareTipPopup = null
swiper = null
shareTitle = ''
shareDesc = ''
state = {
teamData: {
member: []
},
origin: sessionStorage.getItem('isCaptain') ? 1 : getParam('origin'),
treasure_code: getParam('treasure_code'),
activityEnd: false,
notices: [],
rule: '',
isCaptain: getParam('origin') == 1,
isLoading: this.props.user.isFetching
}
componentDidMount() {
this.getStage();
this.fetchPageData()
window.showFollowAlert = this.remind.bind(this, 'create')
document.title = '七月在线年终大回馈,幸运宝箱随你开,100%有奖!'
const landing = document.querySelector('#landing')
const boxContainer = document.querySelector('.box-container')
if (boxContainer.offsetHeight < window.innerHeight) {
landing.style.minHeight = `${window.innerHeight}px`
boxContainer.style.minHeight = `${window.innerHeight}px`
}
}
componentDidUpdate(prevProps) {
if (prevProps.user.hasError !== this.props.user.hasError && !this.props.user.hasError) {
this.fetchPageData()
}
if(prevProps.user.isFetching !== this.props.user.isFetching && !this.props.user.isFetching){
this.setState({
isLoading: this.props.user.isFetching
})
}
}
componentWillUnmount() {
this.shareTipPopup && this.shareTipPopup.remove()
}
// 获取活动以及宝箱的阶段
getStage = () => {
http.get(`${API.home}/activity/stage`).then(res => {
const {code, data, msg} = res.data
if (code === 200) {
if(Number(data.activity_stage) === 0) {
this.props.history.push('/');
return;
}
} else {
Toast.info(msg, 2)
}
})
}
createMeta = (title,dec,imgname) => {
let meta = document.createElement('meta');
meta.setAttribute('name', 'description')
meta.setAttribute('itemprop', 'description')
meta.setAttribute('content', dec)
let meta2 = document.createElement('meta')
meta2.setAttribute('itemprop', 'name')
meta2.setAttribute('content', title)
let meta3 = document.createElement('meta')
meta3.setAttribute('itemprop', 'image')
meta3.setAttribute('content', imgname)
let head = document.getElementsByTagName('head')[0]
head.appendChild(meta)
head.appendChild(meta2)
head.appendChild(meta3)
}
fetchPageData = ({origin = this.state.origin, treasure_code = this.state.treasure_code} = {}) => {
const {location} = this.props
http.post(`${API.home}/sys/treasure/team`, {
treasure_code,
origin
})
.then(res => {
const {data, code, msg} = res.data
if (code == 200) {
this.setState({
teamData: data,
isCaptain: sessionStorage.getItem('isCaptain') ? sessionStorage.getItem('isCaptain') : getParam('origin') == 1,
activityEnd: data.status == 5
})
this.setupWxShareConfig(data.member)
if (browser.isWeixin) {
wxShare({
title: this.shareTitle,
desc: this.shareDesc,
link: `${window.location.origin}${location.pathname}?treasure_code=${getParam('treasure_code')}&origin=2`,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/wx-share-icon.png'
})
// history.replace(`${match.url}?treasure_code=${getParam('treasure_code')}&origin=2`)
} else {
this.createMeta(this.shareTitle, this.shareDesc, 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/wx-share-icon.png')
}
let searchParams = new URLSearchParams(window.location.search)
if (searchParams.get('origin') === '1' && !browser.isWeixin) {
searchParams.set('origin', '2')
sessionStorage.setItem('isCaptain', '1')
window.history.replaceState(null, '', `landing?${searchParams.toString()}`)
}
this.showSharePromptWithParam()
} else {
Toast.info(msg, 2, null, false)
}
})
}
setupWxShareConfig = member => {
const len = member.length
let count = 5 - len <= 0 ? 4 : 5 - len
this.shareTitle = `还差${count}人即可开宝箱,100%有奖!`
this.shareDesc = '加入我的队伍,机械键盘,纸质书籍等超多奖品等你拿!--七月在线'
}
showSharePromptWithParam = () => {
if (sessionStorage.getItem('showShareTip') && !sessionStorage.getItem('closedRemind')) {
this.showShareTip()
}
}
joinTeam = () => {
if (this.requiredLogin()) {
return
}
const {treasure_code} = this.state
http.post(`${API.home}/sys/treasure/joinTeam`, {
treasure_code
})
.then(res => {
const {data, code, msg} = res.data
if (code === 200) {
/*
* status
* 1-成功加入
* 2-成功加入组队成功
* 3-已加入当前队伍
* 4-已加入其他队伍
* */
switch (data.status) {
case 1:
case 2:
this.joinSuccess(data)
break
default:
Toast.info(msg, 2, null, false)
}
} else {
Toast.info(msg, 2, null, false)
}
})
}
handleToMyTreasure = id => {
const {history} = this.props
this.joinSuccessPopup && this.joinSuccessPopup.remove()
if (getParam('version')) {
window.location.assign(`https://m.julyedu.com/year/yearTreasure?id=${id}&version=${getParam('version')}`)
} else {
window.location.assign(`https://m.julyedu.com/year/yearTreasure?id=${id}`)
}
}
joinSuccess = ({id, status, my_team: {team_num, lack_member, is_team, treasure_code}}) => {
this.joinSuccessPopup = Popup({
title: <div className={'join-success'}>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/check-icon.png" alt=""/>
<div>成功加入队伍</div>
</div>,
className: 'landing-join-success-wrapper',
content: <div>
<div className={'tip'}>
{
status === 2
? '组队成功,恭喜你获得一个宝箱!'
: is_team
? <>您的{<span>{team_num}</span>}号队伍还差{<span>{lack_member}</span>}人即可获得宝箱</>
: '自己当队长,宝箱内有专属奖品哦~'
}
</div>
{
status === 2
? <img style={{width: '150px', marginTop: '23px'}}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/treasure-split.gif"
alt=""
onClick={this.handleToMyTreasure.bind(this, id)}
/>
: is_team
? <button type='button'
onClick={this.inviteMembers.bind(this, treasure_code)}>继续组队</button>
: <button type="button" onClick={this.createMyTeam}>创建我的队伍</button>
}
</div>,
closeIcon: this.closeIcon,
close: () => {
this.fetchPageData()
this.getFollowStatus()
.then(isFollow => {
!isFollow && this.remind('join', this.state.treasure_code, 2)
})
}
})
}
inviteMembers = treasure_code => {
const {history, match, user, location} = this.props
if (getParam('version')) {
let data = {
title: this.shareTitle,
desc: this.shareDesc,
link: `${window.location.origin}${location.pathname}?treasure_code=${treasure_code}&origin=2`,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/wx-share-icon.png'
}
SendMessageToApp("toShare", data)
}
sessionStorage.setItem('showShareTip', '1')
history.replace(`${match.url}?treasure_code=${treasure_code}&origin=${1}`)
this.createTeamSuccessPopup && this.createTeamSuccessPopup.remove() && (this.createTeamSuccessPopup = null)
this.joinSuccessPopup && this.joinSuccessPopup.remove() && (this.joinSuccessPopup = null)
this.fetchPageData({treasure_code, origin: 1})
this.setState({
isCaptain: true
})
}
getFollowStatus = () => http.get(`${API.home}/sys/user/isFollowWeChat`)
.then(res => {
const {code, data} = res.data
return code === 200 && data['is_follow']
})
createTeamSuccess = ({member, team_num, lack_member, treasure_code}) => {
this.joinSuccessPopup && this.joinSuccessPopup.remove() && (this.joinSuccessPopup = null)
this.getFollowStatus()
.then(isFollow => {
this.createTeamSuccessPopup = Popup({
title: '创建成功',
className: 'landing-create-success',
content: <div>
<div className="tip">{<span>{team_num}</span>}号队伍 还差{<span>{lack_member}</span>}名队员即可获得宝箱哦~</div>
<img className={'treasure-box'}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/treasure-box-icon.png" alt=""/>
<ul className='members'>
{
new Array(5).fill('a').map((item, index) => {
const _member = member[index]
return <li key={index}>
{_member && _member['is_captain'] && <sup>队长</sup>}
<img
className={'avatar'}
src={
_member
? _member['head_img']
: "https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/not-joined-placeholder.png"
}
alt=""/>
</li>
})
}
</ul>
<button type={'button'} onClick={this.inviteMembers.bind(this, treasure_code)}>邀请好友加入队伍</button>
</div>,
closeIcon: this.closeIcon,
afterClose: () => {
if (!isFollow) {
this.remind('create', treasure_code)
}
}
})
})
}
// 安卓手机保存二维码
saveImage = url => {
let version = getParam('version')
version = typeof version === 'string' ? version.replace('.', '').replace('.', '').slice(0, 3) : ''
if (version && parseInt(version) < 451) {
Toast.info('当前不支持此功能,升级到最新版本app可以点击保存二维码!', 3, null, false)
} else {
SendMessageToApp('generateQRCode', url)
}
}
remind = (type = 'create', treasure_code, origin = 1) => {
const {user} = this.props
http.get(`${API["base-api"]}/wx/user_temporary_qrcode/${user.data.uid}`)
.then(res => {
const {data} = res.data
return data.url
}).then(text => {
QRCode.toDataURL(text)
.then(url => {
Popup({
title: '提醒服务',
className: 'landing-remind',
closeIcon: this.closeIcon,
content: <div>
<div className="des">{type === 'create' ? '有好友加入队伍后第一时间通知我~' : '获得宝箱时第一时间通知我~'}</div>
<img src={url} alt=""/>
{browser.isAndroidApp ? <div>
<button className={'android-qr-code-btn'} onClick={this.saveImage.bind(this, text)}>保存二维码</button>
</div> : null}
<div className="des">长按识别/扫码 关注【七月在线】服务号即可预约</div>
</div>,
close: () => {
// history.replace(`${match.path}?treasure_code=${treasure_code}&origin=1`)
sessionStorage.setItem('closedRemind', '1')
this.fetchPageData({
treasure_code,
origin
})
}
})
})
})
}
showShareTip = () => {
const {user, location} = this.props
if (browser.isAndroidApp || browser.isIOSApp) {
SendMessageToApp('toShare', {
title: this.shareTitle,
desc: this.shareDesc,
link: `${window.location.origin}${location.pathname}?treasure_code=${getParam('treasure_code')}&origin=2`,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/wx-share-icon.png'
})
} else {
this.shareTipPopup = Popup({
title: <div>还差<span>{this.state.teamData.lack_member}</span>名队友即可获得宝箱 快分享给好友吧~</div>,
className: `landing-share-tip ${browser.isWeixin ? 'wechat' : ''}`,
closable: false,
close: () => {
sessionStorage.removeItem('showShareTip')
if (!user.hasError) {
this.getFollowStatus()
.then(isFollow => {
!isFollow && this.remind('create', getParam('treasure_code'), 1)
})
}
}
})
}
}
showOpenInBrowserTip = () => {
Popup({
title: <div>点击右上角,选择“在浏览器打开”</div>,
className: 'landing-open-in-browser-tip',
closable: false,
})
}
createMyTeam = () => {
if (this.requiredLogin()) {
return
}
http.get(`${API.home}/sys/treasure/createMyTeam`)
.then(res => {
const {data, code, msg} = res.data
if (code == 200) {
this.createTeamSuccess(data)
} else {
Toast.info(msg, 2, null, false)
}
})
}
requiredLogin = () => {
const {history, user, location} = this.props
if (user.hasError) {
if (browser.isWeixin) {
window.location.assign(`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=${encodeURIComponent(`${window.location.origin}${location.pathname}?treasure_code=${getParam('treasure_code')}&origin=${getParam('origin')}&aa=bb`)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`)
} else {
history.push('/passport')
}
return true
}
}
toSquare = () => {
const {history} = this.props
if (!getParam('version')) {
window.location.assign('https://m.julyedu.com/year/yearindex')
} else {
window.location.assign('https://m.julyedu.com/year/yearindex?version=' + getParam('version'))
}
}
render() {
const {
teamData: {
head_img,
member,
status,
lack_member,
team_num,
prize_info,
my_team,
standby_plan
},
activityEnd,
isCaptain,
isLoading
} = this.state
/*
* status
* 1-自己的队伍
* 2-未加入队伍
* 3-已加入当前队伍
* 4-已加入别的队伍
* */
return (
<div id={'landing'}>
{
!(standby_plan && browser.isWeixin) &&
<div id="to-square">
<a href='javascript:' onClick={this.toSquare}>前往活动会场,享更多福利! >></a>
</div>
}
<BoxContainer>
<i className={`snow-deco ${standby_plan && browser.isWeixin ? 'standby' : ''}`}/>
{
standby_plan && browser.isWeixin &&
<>
<WhiteSpace className={'standby-space'}/>
<div className={'standby-tip'}>点击右上角,选择“在浏览器打开”</div>
</>
}
<img className='main-avatar'
src={head_img} alt=""/>
{
status === 1
? <div className="des">邀请好友加入队伍,开宝箱领取丰厚奖品~</div>
: <div className="des">加入我的<span>{team_num}</span>号队伍,一起开宝箱领取丰厚奖品~</div>
}
<Prizes showSystemNotices={false}/>
<BulletScreen/>
<div className="group">
<ul className={'member'}>
{
member && member.length &&
new Array(5).fill('a').map((item, index) => {
const _member = member[index]
return (
_member
? <li key={index}>
<div className='avatar-wrapper'>
{
_member.is_captain ? <sup>队长</sup> : null
}
<img
src={_member.head_img}
alt=""
className="avatar"/>
</div>
</li>
:
<li key={index}>
<div className="avatar-wrapper">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/default-member-avatar.png"
alt=""
className="avatar"/>
</div>
</li>
)
})
}
</ul>
<ul className={'bars'}>
{
member && member.length &&
new Array(5).fill('a').map((item, index) => {
return (
<li key={index} className={`${index < member.length ? 'active' : ''}`}/>
)
})
}
</ul>
{
status === 1 && !activityEnd &&
<>
<div className="group-des">
还差 {lack_member} 名队员即可获得当前宝箱哦~
</div>
{
!(standby_plan && browser.isWeixin) &&
<button type='button' className={'invite-btn'} onClick={this.showShareTip}>
邀请好友加入队伍
</button>
}
</>
}
{
status === 3 && !activityEnd &&
<>
<div className="group-des">
<p>已加入当前队伍</p>
{
my_team['is_team']
? <p>您的{my_team['team_num']}号队伍还差{my_team['lack_member']}人即可获得宝箱~</p>
: <p>自己当队长,宝箱内有专属奖品哦~</p>
}
</div>
{
!(standby_plan && browser.isWeixin) && (my_team['is_team'] ?
<button type='button' className={'invite-btn'}
onClick={this.inviteMembers.bind(this, my_team['treasure_code'])}>
继续组队
</button>
: <button type='button' className={'invite-btn'} onClick={this.createMyTeam}>
创建我的队伍
</button>)
}
</>
}
{
status === 4 && !activityEnd &&
<>
<div className="group-des">
<p>已加入其他队伍</p>
{
my_team['is_team']
? <p>您的{my_team['team_num']}号队伍还差{my_team['lack_member']}人即可获得宝箱~</p>
: <p>自己当队长,宝箱内有专属奖品哦~</p>
}
</div>
{
!(standby_plan && browser.isWeixin) && (my_team['is_team'] ?
<button type='button' className={'invite-btn'}
onClick={this.inviteMembers.bind(this, my_team['treasure_code'])}>
继续组队
</button>
: <button type='button' className={'invite-btn'} onClick={this.createMyTeam}>
创建我的队伍
</button>)
}
</>
}
{
!(standby_plan && browser.isWeixin) && status === 2 && !activityEnd &&
< button type='button' className={'invite-btn'} onClick={this.joinTeam}>
同意加入队伍
</button>
}
{
prize_info && prize_info.length !== 0 && !activityEnd && !isCaptain && <div className="certainly-prompt">
{prize_info[0].stage_no}个宝箱必中 {prize_info[0].name}
</div>
}
{
activityEnd &&
<div className='activity-end'>
<div>活动已结束</div>
<div>关注【七月在线】服务号了解更多活动信息</div>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/tinypng-common/right_weixin.png" alt=""/>
<div>长按识别 / 微信扫码</div>
</div>
}
</div>
</BoxContainer>
{
!isCaptain &&
<>
<WhiteSpace size={'xl'}/>
<YearCourse getSum={() => {
}}/>
</>
}
{
isLoading && <div className="loading" style={{width: window.innerWidth + 'px', height: window.innerHeight + 'px'}}>
<FadeLoader
color={'#fff'}
loading={isLoading}
/>
</div>
}
</div>
)
}
}
export default connect(
state => ({user: state.user}),
null
)(Landing)
.sup {
position: absolute;
right: -10px;
top: 0;
transform: translateY(-50%);
width: 30px;
height: 16px;
background: rgba(255, 227, 0, 1);
border: 1px solid rgba(255, 255, 255, 1);
border-radius: 8px 8px 8px 0;
color: #0E7442;
font-size: 10px;
text-align: center;
line-height: 16px;
}
#landing {
background: #BC2A18;
text-align: center;
min-height: 100%;
#to-square {
position: fixed;
width: 100%;
height: 30px;
background: #FF2121;
color: #fff;
font-size: 14px;
line-height: 30px;
text-align: center;
z-index: 21;
}
.box-container {
width: 100%;
}
.snow-deco {
position: absolute;
top: 30px;
left: 0;
display: block;
width: 100%;
height: 68px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/snow-deco.png") no-repeat;
background-size: contain;
&.standby {
top: 0;
}
}
.main-avatar {
width: 49px;
height: 49px;
border-radius: 50%;
margin-bottom: 5px;
margin-top: 55px;
object-fit: cover;
}
.des {
font-size: 14px;
color: #FFDC1E;
span {
display: inline-block;
width: 15px;
height: 15px;
line-height: 16px;
color: #327443;
border-radius: 50%;
background: #FFDC1E;
}
}
.standby-space {
height: 25px;
}
.standby-tip {
position: relative;
width: 270px;
height: 32px;
background: #FFDE00;
border-radius: 5px;
margin: 0 auto -40px;
line-height: 32px;
text-align: center;
color: #202426;
font-size: 15px;
&::after {
content: '';
display: block;
position: absolute;
top: -120%;
right: -6%;
width: 50px;
height: 38px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/standby-share-tip-icon.png");
background-size: contain;
}
}
.group {
ul.member {
display: flex;
padding: 0 49px;
}
& li:nth-last-child(1) {
margin-right: 0;
}
li {
margin-right: 24.5px;
}
.avatar-wrapper {
position: relative;
&::after {
content: '';
display: block;
position: absolute;
bottom: 0;
left: 50%;
transform: translateX(-50%);
width: 22px;
height: 3px;
background: #243529;
opacity: 0.8;
border-radius: 50%;
}
sup {
@extend .sup;
}
img {
width: 36px;
height: 36px;
border-radius: 50%;
border: 1px solid #fff;
}
}
.bars {
display: flex;
padding-left: 37.5px;
margin-top: 15px;
& li:nth-child(1) {
border-radius: 2px 0 0 2px;
}
& li:nth-last-child(1) {
border-radius: 0 2px 2px 0;
margin-right: 0;
}
li {
width: 59px;
height: 5px;
margin-right: 1.5px;
background: #035B34;
&.active {
background: #FFDD1D;
}
}
}
&-des {
margin-top: 27px;
font-size: 14px;
color: #FFE300;
}
.invite-btn {
width: 320px;
height: 44px;
line-height: 44px;
margin: 14.5px auto 57px;
color: #0B7B45;
font-size: 15px;
background: #FFE300;
border: 0;
outline: 0;
-webkit-appearance: none;
border-radius: 3px;
font-family: "HiraginoSansGB-W6", "Helvetica Neue", Helvetica, "PingFang SC", "Hiragino Sans GB", "Microsoft YaHei", "微软雅黑", Arial, sans-serif;
}
.certainly-prompt {
margin-top: 27px;
padding-bottom: 16px;
font-size: 14px;
color: #FFE300;
}
}
.activity-end {
display: flex;
flex-flow: column;
align-items: center;
margin-top: 26px;
font-size: 14px;
color: #FFE300;
div:first-child {
margin-bottom: 5px;
}
div:nth-child(2) {
margin-bottom: 19px;
}
img {
width: 120px;
height: 120px;
margin-bottom: 12px;
}
div:last-child {
color: #fff;
font-size: 12px;
}
}
.am-whitespace.am-whitespace-xl {
height: 35px;
}
.loading{
transform: scale(1);
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,.8);
z-index: 1000;
display: flex;
align-items: center;
justify-content: center;
}
}
.popup-container {
.tip {
font-size: 15px;
line-height: 37px;
color: #666;
text-align: center;
span {
color: #FF2121;
}
}
}
.popup-button {
width: 270px;
height: 44px;
padding: 0;
margin-top: 20px;
background: #FFE319;
border: 1px solid #090909;
border-radius: 5px;
line-height: 44px;
font-size: 16px;
color: #090909;
}
.landing-treasure-rules {
width: 320px;
&.popup-container {
.title {
font-size: 18px;
color: #111111;
}
}
.content {
padding: 0 19px 15px;
margin-top: 22px;
color: #666666;
font-size: 14px;
li {
margin-bottom: 5px;
}
}
}
.landing-join-success-wrapper {
&.popup-container {
width: 320px;
text-align: center;
.title {
img {
width: 54px;
height: 54px;
margin-bottom: 10px;
}
font-size: 18px;
color: #111111;
}
}
/*.tip {
font-size: 15px;
line-height: 37px;
color: #666;
text-align: center;
}*/
button {
@extend .popup-button;
}
}
.landing-create-success {
text-align: center;
&.popup-container {
width: 320px;
padding: 20px;
.title {
font-size: 18px;
color: #111111;
}
}
img.treasure-box {
margin: 20px 0;
width: 120px;
height: 72px;
}
.members {
display: flex;
& li:nth-last-child(1) {
margin-right: 0;
}
li {
position: relative;
margin-right: 15px;
}
.avatar {
width: 44px;
height: 44px;
border-radius: 50%;
}
sup {
@extend .sup;
}
}
button {
@extend .popup-button;
}
}
.landing-remind {
&.popup-container {
width: 320px;
text-align: center;
padding: 20px 30px;
.title {
font-size: 18px;
color: #111;
margin-bottom: 8px;
}
}
img {
margin: 15px 0 16px;
width: 137px;
height: 137px;
}
.des {
font-size: 14px;
color: #666;
}
button {
width: 270px;
height: 44px;
background: rgba(255, 227, 25, 1);
border: 1px solid rgba(9, 9, 9, 1);
border-radius: 5px;
font-size: 16px;
font-weight: normal;
color: rgba(9, 9, 9, 1);
margin-bottom: 15px;
}
}
.landing-open-in-browser-tip, .landing-share-tip {
font-size: 17px;
color: #111;
&.popup-container {
position: absolute;
width: 270px;
text-align: center;
top: 114px;
padding: 20px 33px;
}
span {
color: #FF2121;
}
}
.landing-open-in-browser-tip.wechat, .landing-share-tip.wechat {
&.popup-container {
&::after {
content: '';
display: block;
position: absolute;
top: -50px;
right: -18px;
width: 50px;
height: 38px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/share-indicator.png") no-repeat;
background-size: contain;
}
}
}
.landing-open-in-browser-tip {
&.popup-container {
width: 312px;
}
}
.year19-index {
display: none;
}
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { HeaderBar } from '@common'
import AddressPopup from '@common/addressPopup/index'
import BindPhone from '@common/bindPhone/index'
import ConfirmPhone from '@common/confirmPhone/index'
import CreateSuccess from './../common/createSuccess/index'
import TreasureTeam from './team'
import PrizeStatus from './prize'
import SplitSuccess from './../common/splitSuccess/index'
import { http, getParam, SendMessageToApp, browser } from '@/utils'
import Mask from './mask'
import './index.scss'
@connect(({country, user}) => ({
country,
userInfo: user.data
}))
class MyTreasure extends Component {
popupInstance = null
constructor(props) {
super(props)
this.state = {
isEnd: false,
isEmpty: false,
seconds: 3,
teams: [],
ids: [], // 未拆宝箱统计
bindInfo: {}, // 绑定手机号冲突信息
isPhone: false,
isAddress: false,
isConfirm: false,
confirmInfo: {},
isSplit: false,
isCreate: false,
createInfo: {},
prizeName: '', // 当前商品的名字
treasureTime: '', // 宝箱活动结束时间
}
}
componentDidMount() {
this.fetchMyTreasure()
this.fetchActivityStatus()
document.title = '七月在线年终大回馈,幸运宝箱随你开,100%有奖!人气好课免费学,精品课程1分抢!';
}
componentWillReceiveProps(nextProp) {
const {history} = this.props
const {userInfo} = nextProp
if (!userInfo.uid) {
history.push('/passport')
}else {
this.fetchMyTreasure();
}
}
// 页面加载时,初始化当前需要绑定手机号的奖品名字
initPrizeName = (params) => {
const key = this.fetchCurrentTeamId(params)
const data = params.filter(item => item.id == key)
if (data.length > 0) {
this.setState({
prizeName: data[0]['prize_name']
})
}
}
// 页面加载时,是否需要拆宝箱
judgeIsHaveId = (data) => {
const id = getParam('id')
if (id) {
const newData = data.filter(item => item.id == id)
if (newData.length > 0) {
const params = {
team_num: newData[0]['team_num'],
owner_uid: newData[0]['captain_uid']
}
this.toSplitTreasure(params)
}
}
}
// 获取当前需要绑定手机的队伍id,当拆到需要绑定手机号/地址的宝箱时,如果不进行绑定则无法拆下一个
fetchCurrentTeamId = (data = []) => {
const arr = data.filter(item => item.is_open && (item.bind_phone || item.bind_address))
if (arr.length > 0) {
return arr[0]['id']
} else {
return ''
}
}
// 页面加载时,是否是从选择区号页面过来的
// TODO,当同时展示拆宝箱成功弹窗和绑定手机号弹窗时,选择区号返回时未展示拆宝箱成功弹窗(和产品确认,后续优化)
isShowBindPhone = (data) => {
const {country} = this.props
if (country.from) {
const id = this.fetchCurrentTeamId(data)
this.handleToBindPhone(id)
}
}
// 绑定手机号--展示
handleToBindPhone = (id) => {
this.setState({
isPhone: true,
})
}
// 绑定手机号--确认
handleToConfirmPhone = (params, bindInfo) => {
this.handleToHideWindow('isPhone')
this.setState({
confirmInfo: {
params,
bindInfo,
},
isConfirm: true,
})
}
// 绑定手机号--成功
successBindPhone = () => {
this.setState({
isPhone: false,
isConfirm: false,
})
const {teams, splitInfo} = this.state
const teamId = this.fetchCurrentTeamId(teams)
const data = teams.map(item => {
if (item.id == teamId) {
if (item.bind_address) {
this.handleToBindAddress()
}
return Object.assign({}, item, {
bind_phone: false,
})
}
return item
})
this.setState({
teams: data,
splitInfo: Object.assign({}, splitInfo, {
bind_phone: false
})
})
}
// 拆宝箱--拆
toSplitTreasure = (params) => {
http.post(`${API.home}/sys/split_treasure`, params).then(res => {
const {code, data} = res.data
if (code === 200) {
// 拆宝箱弹窗--成功
this.showSuccessSplit(data)
// 更新队伍状态
this.successSplitTreasure(data)
if (data.bind_phone) {
setTimeout(() => {
this.handleToBindPhone(data.id)
}, 500)
} else if (data.bind_address) {
setTimeout(() => {
this.handleToBindAddress(data.id, data.prize_name)
}, 500)
}
} else if (code === 12000) {
// 绑定手机号
this.handleToBindPhone()
} else if (code === 12001) {
// 绑定地址
this.handleToBindAddress()
}
})
}
// 拆宝箱--成功,更新数据
successSplitTreasure = (params) => {
const {userInfo} = this.props
const {teams} = this.state
const data = teams.map(item => {
if (item.id == params.id) {
return Object.assign({}, item, {
bind_phone: params.bind_phone,
bind_address: params.bind_address,
is_open: true,
prize_type: params.prize_type,
prize_data: params.prize_data,
member: item.member.map(val => {
if (val.uid == userInfo.uid) {
return Object.assign({}, val, {
is_open: true,
prize_name: params.prize_name
})
}
return val
})
})
} else {
return item
}
})
this.initNoSplitInfo(data)
this.setState({
teams: data,
splitInfo: params,
prizeName: params.prize_name
})
}
// 拆宝箱--成功,展示弹窗
showSuccessSplit = (data) => {
this.setState({
isSplit: true,
splitInfo: data
})
}
// 绑定地址--展示
handleToBindAddress = (id, prizeName = '') => {
if (id) {
if(prizeName) {
this.setState({
prizeName
})
}else {
const {teams} = this.state
const data = teams.filter(item => item.id == id)
if (data.length > 0) {
this.setState({
prizeName: data[0]['prize_name']
})
}
}
}
this.setState({
isAddress: true
})
}
// 绑定地址--成功
successBindAddress = () => {
this.setState({
isAddress: false,
})
const {teams, splitInfo} = this.state
const teamId = this.fetchCurrentTeamId(teams)
const data = teams.map(item => {
if (item.id == teamId) {
return Object.assign({}, item, {
bind_address: false,
})
}
return item
})
this.setState({
teams: data,
splitInfo: Object.assign({}, splitInfo, {
bind_address: false
})
})
}
// 获取我的宝箱信息
fetchMyTreasure = () => {
http.get(`${API.home}/sys/treasure/my`).then(res => {
const {code, data} = res.data
if (code === 200) {
this.setState({
rule: data.rule
})
if (Array.isArray(data.team) && data.team.length > 0) {
this.initNoSplitInfo(data.team)
this.judgeIsHaveId(data.team)
this.isShowBindPhone(data.team)
this.initPrizeName(data.team)
this.setState({
isEmpty: false,
teams: data.team,
})
} else {
this.setState({
isEmpty: true,
})
}
}
})
}
// 统计未拆的宝箱信息
initNoSplitInfo = (data = []) => {
if (data.length > 0) {
this.setState({
ids: data.filter(item => !item.is_open && item.status === 2).map(val => {
return {
team_num: val.team_num,
owner_uid: val.captain_uid
}
})
})
}
}
// 获取宝箱活动状态
fetchActivityStatus = () => {
http.get(`${API.home}/activity/stage`).then(res => {
const {code, data} = res.data
if (code === 200) {
if(Number(data.activity_stage) === 0) {
this.props.history.push('/');
return;
}
// treasure_stage,宝箱阶段,0-不在活动时间,1-活动时间内
if (data.treasure_stage === 0) {
this.startCountDown()
}
this.setState({
isEnd: data.treasure_stage === 0,
treasureTime: data.treasure_stop_date
})
}
})
}
// 活动结束--倒计时
startCountDown = () => {
const {history} = this.props
let {seconds} = this.state
if (this.timer) {
clearInterval(this.timer)
}
this.setState({
seconds: seconds--
})
this.timer = setInterval(() => {
this.setState({
seconds: seconds--
})
if (seconds === 0) {
this.setState({
seconds: 0
})
clearInterval(this.timer)
if (getParam('version')) {
history.push(`/year/yearIndex?version=${getParam('version')}`)
} else {
history.push('/year/yearIndex')
}
}
}, 1000)
}
// 邀请好友
handleToInvite = (treasure_code) => {
const {history} = this.props
if (getParam('version')) {
window.location.assign(`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=1&version=${getParam('version')}`)
} else {
window.location.assign(`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=1`)
}
}
// 组队开宝箱
toOrganizeTeam = () => {
const {history, userInfo: {uid = ''}} = this.props
if (uid === '') {
history.push('/passport')
} else {
http.get(`${API.home}/sys/treasure/createMyTeam`).then(res => {
const {code, data} = res.data
if (code === 200) {
const teams = []
teams[0] = data
this.setState({
isEmpty: false,
teams,
isCreate: true,
createInfo: data
})
}
})
}
}
// 奖品,代金券碎片--合成
toComposeCoupon = () => {
const {history} = this.props
if (getParam('version')) {
SendMessageToApp("toCoupon")
} else {
history.push('/coupons/my-patch')
}
}
// 奖品,指定课程代金券--使用
toUseCoupon = (id) => {
const {history} = this.props
if (getParam('version')) {
SendMessageToApp("toCourse", id)
} else {
history.push(`/detail?id=${id}`)
}
}
// 第三:奖品,通用课程代金券--使用
toCourseList = () => {
const {history} = this.props
if (getParam('version')) {
SendMessageToApp('toQualityCourse')
} else {
history.push('/classify')
}
}
// 第三:奖品,现金红包--提现
toFecthMoney = () => {
const {history} = this.props
if (getParam('version')) {
SendMessageToApp('toAccount')
} else {
history.push('/scholarship')
}
}
// 弹窗--隐藏
handleToHideWindow = (key) => {
const param = {}
param[key] = false
this.setState(param)
}
render() {
const {history, userInfo, country} = this.props
const {
isEnd,
isEmpty,
seconds,
teams,
ids,
isPhone,
isAddress,
isConfirm,
isSplit,
splitInfo = {},
confirmInfo: {
params = {},
bindInfo = {}
},
isCreate,
createInfo,
prizeName,
rule,
treasureTime,
} = this.state
return (
<div data-skip="treasure">
{(!browser.isAndroidApp && !browser.isIOSApp) && <HeaderBar title="我的宝箱" arrow={true}/>}
{
isEnd &&
<div className="team-empty">
<p className="activity-end__desc">
活动已结束<br/>
{seconds}s后将自动返回首页
</p>
</div>
}
{
(!isEnd && isEmpty) &&
<div className="team-empty">
<i className="team-empty__icon"></i>
<p className="team-empty__desc">您当前还没有宝箱哦~</p>
<p className="team-empty__desc">快去组队邀请好友一起开宝箱吧!</p>
<button className="team-empty__button" onClick={this.toOrganizeTeam}>组队开宝箱</button>
</div>
}
{
(!isEnd && !isEmpty && userInfo.uid) &&
<div className="treasure-content">
{
teams.map((item, index) => (
<TreasureTeam
data={item}
key={index}
userInfo={userInfo}
history={history}
splitInstance={this.splitInstance}
toSplitTreasure={() => this.toSplitTreasure({
team_num: item.team_num,
owner_uid: item.captain_uid
})}
>
<PrizeStatus
data={{
bind_phone: item.bind_phone,
bind_address: item.bind_address,
prize_type: item.prize_type,
}}
handleToBindPhone={this.handleToBindPhone}
handleToBindAddress={() => this.handleToBindAddress(item.id)}
toComposeCoupon={this.toComposeCoupon}
toUseCoupon={() => this.toUseCoupon(item.prize_data)}
toCourseList={this.toCourseList}
toFecthMoney={this.toFecthMoney}
/>
</TreasureTeam>
))
}
{/* 拆宝箱--弹窗,成功 */}
<Mask visible={isSplit} handleToHide={() => this.handleToHideWindow('isSplit')}>
<SplitSuccess
ids={ids}
data={splitInfo}
handleToInvite={() => this.handleToInvite(splitInfo.treasure_code)}
handleToBindPhone={this.handleToBindPhone}
handleToBindAddress={this.handleToBindAddress}
successSplitTreasure={this.successSplitTreasure}
>
<PrizeStatus
data={splitInfo}
handleToBindPhone={this.handleToBindPhone}
handleToBindAddress={this.handleToBindAddress}
toComposeCoupon={this.toComposeCoupon}
toUseCoupon={() => this.toUseCoupon(splitInfo.prize_data)}
toCourseList={this.toCourseList}
toFecthMoney={this.toFecthMoney}
/>
</SplitSuccess>
</Mask>
{/*绑定手机号--弹窗 */}
<Mask visible={isPhone} className="popup-bind-phone" handleToHide={() => this.handleToHideWindow('isPhone')}>
<BindPhone
history={history}
country={country}
hideBindPhone={() => this.handleToHideWindow('isPhone')}
handleToConfirmPhone={this.handleToConfirmPhone}
successBindPhone={this.successBindPhone}
desc={
<>
<p className="phone-treasure__desc">恭喜您获得 {prizeName}</p>
<p className="phone-treasure__notice">为了您的账户安全,请于{treasureTime}前绑定手机号,过期将失效</p>
</>
}
/>
</Mask>
{/* 绑定手机号--弹窗,确认 */}
<Mask visible={isConfirm} handleToHide={() => this.handleToHideWindow('isConfirm')}>
<ConfirmPhone
data={params}
bindInfo={bindInfo}
handleToCancle={() => this.handleToHideWindow('isConfirm')}
successBindPhone={this.successBindPhone}
/>
</Mask>
{/* 绑定地址--弹窗 */}
<Mask visible={isAddress} className="popup-bind-address" handleToHide={() => this.handleToHideWindow('isAddress')}>
<AddressPopup
skip="year"
tip={
<>
<p className="address-treasure__desc">恭喜您获得 {prizeName}</p>
<p className="address-treasure__notice">请及时填写/确认收货信息,活动结束后统一邮寄</p>
</>
}
successBindAddress={this.successBindAddress}
/>
</Mask>
{/* 组队成功 */}
<Mask visible={isCreate} handleToHide={() => this.handleToHideWindow('isCreate')}>
<CreateSuccess
data={createInfo}
handleToInvite={() => {
this.handleToInvite(createInfo.treasure_code)
this.handleToHideWindow('isCreate')
}}
/>
</Mask>
</div>
}
{
rule &&
<>
<div className="activity-rule__header">
<i className="activity-rule__decorate"></i>
<h2 className="activity-rule__title">活动规则</h2>
<i className="activity-rule__decorate"></i>
</div>
<div className="activity-rule__body" dangerouslySetInnerHTML={{__html: rule}}></div>
</>
}
</div>
)
}
}
export default MyTreasure
[data-skip="treasure"] {
min-height: 100vh;
background-color: #0E7442;
&+ .year19-index {
display: none;
}
.treasure-content {
padding: 16px 0 10px;
}
.team-container {
margin: 0 10px 12px;
}
.activity-end__desc {
font-size: 30px;
color: #fff;
text-align: center;
line-height: 42px;
}
.team-empty {
padding-top: 118px;
}
.team-empty__icon {
display: block;
width: 56px;
height: 49px;
margin: 0 auto 18px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-empty.png');
}
.team-empty__desc {
margin: 0 70px;
font-size: 15px;
color: #fff;
text-align: center;
line-height: 21px;
}
.team-empty__button {
display: block;
width: 297px;
height: 44px;
margin: 20px auto 0;
border: 1px solid #090909;
border-radius: 5px;
box-sizing: border-box;
font-size: 16px;
color: #090909;
background-color: #FFE319;
}
.activity-rule__header {
display: flex;
align-items: center;
justify-content: center;
margin: 49px 0 0;
}
.activity-rule__title {
margin: 0 16px;
font-size: 18px;
color: #FFE300;
line-height: 1;
}
.activity-rule__decorate {
display: inline-block;
width: 11px;
height: 12px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-decorate-0.png');
}
.activity-rule__body {
margin: 13px 0 0;
padding: 0 21px 40px;
p {
font-size: 12px;
color: #FFE300;
line-height: 18px;
}
}
}
.mask-content {
&.popup-bind-phone {
height: 350px;
}
&.popup-bind-address {
height: 316px;
}
}
// 所有弹窗
.popup-container {
&.year {
.close-icon {
position: absolute;
bottom: 80px;
left: 0;
right: 0;
margin: 0 auto;
}
}
}
// 地址弹窗--宝箱
.address-treasure__desc {
margin: 12px 0 0;
font-size: 14px;
color: #666;
line-height: 1;
}
.address-treasure__notice {
margin: 10px 0 16px;
font-size: 12px;
color: #FF2121;
line-height: 1;
}
// 绑定手机弹窗--宝箱
.phone-treasure__desc {
width: 269px;
margin: 10px 25px 0;
font-size: 14px;
color: #666;
line-height: 1;
}
.phone-treasure__notice {
width: 269px;
margin: 9px 25px 15px;
font-size: 12px;
color: #FF2121;
line-height: 18px;
}
\ No newline at end of file
import React, { Component } from 'react';
import ReactDOM from 'react-dom';
import classnames from 'classnames';
import './mask.scss';
const Root = document.querySelector('body');
class Mask extends Component {
constructor(props) {
super(props);
if(!this.el) {
this.el = document.createElement('div');
}
}
componentDidMount() {
Root.appendChild(this.el);
}
componentWillUnmount() {
Root.removeChild(this.el);
}
render() {
const { visible, handleToHide, className } = this.props;
if(visible) {
return ReactDOM.createPortal(
(
<div className="mask">
<div className={classnames("mask-content", className)}>
{this.props.children}
</div>
<div className="mask-footer">
<i className="mask-button__close" onClick={handleToHide}></i>
</div>
</div>
),
this.el
);
}else {
return null;
}
}
}
export default Mask;
\ No newline at end of file
.mask {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
color:#fff;
background-color: rgba(0, 0, 0, .5);
}
.mask-content {
min-width: 200px;
min-height: 100px;
padding: 10px 0;
border-radius: 5px;
box-sizing: border-box;
background-color: #fff;
}
.mask-footer {
margin-top: 33px;
}
.mask-button__close {
display: inline-block;
width: 33px;
height: 33px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/close-btn.png');
}
\ No newline at end of file
import React from 'react';
import './prize.scss';
export default (props) => {
const {
data: {
bind_phone,
bind_address,
prize_type,
},
handleToBindPhone,
handleToBindAddress,
toComposeCoupon,
toUseCoupon,
toCourseList,
toFecthMoney,
} = props;
return (
<>
{/* 第一:是否需要绑定手机号 */}
{
bind_phone &&
<a className="team-result" onClick={handleToBindPhone}>
<span>绑定手机号</span>
</a>
}
{/* 第二:是否需要填写地址 */}
{
(!bind_phone && bind_address) &&
<a className="team-result" onClick={handleToBindAddress}>
<span>查看/修改收货信息</span>
</a>
}
{/* 第三:奖品,实物 */}
{
(!bind_phone && !bind_address && prize_type === 1) &&
<a className="team-result" onClick={handleToBindAddress}>
<span>查看/修改收货信息</span>
</a>
}
{/* 第三:奖品,代金券碎片 */}
{
(!bind_phone && !bind_address && prize_type === 6) &&
<a className="team-result" onClick={toComposeCoupon}>
可合成代金券在购课时使用,
<span>去合成</span>
</a>
}
{/* 第三:奖品,指定课程代金券 */}
{
(!bind_phone && !bind_address && prize_type === 3) &&
<a className="team-result" onClick={toUseCoupon}>
已发放至您的账户,
<span>去使用</span>
</a>
}
{/* 第三:奖品,通用课程代金券 */}
{
(!bind_phone && !bind_address && prize_type === 4) &&
<a className="team-result" onClick={toCourseList}>
已发放至您的账户,
<span>去使用</span>
</a>
}
{/* 第三:奖品,现金红包 */}
{
(!bind_phone && !bind_address && prize_type === 7) &&
<a className="team-result" onClick={toFecthMoney}>
已存入您的账户,
<span>去提现</span>
</a>
}
{/* 第三:奖品,线上课程 */}
{
(!bind_phone && !bind_address && prize_type === 2) &&
<a className="team-result">已发放至您的账户</a>
}
{/* 第三:奖品,任意线上课程兑换券 */}
{
(!bind_phone && !bind_address && prize_type === 5) &&
<a className="team-result">关注公众号“七月在线实验室” 回复“领课”
</a>
}
</>
)
}
\ No newline at end of file
.team-result {
display: inline-block;
margin: 8px 0 0;
font-size: 12px;
color: #666;
text-align: center;
line-height: 1;
span {
text-decoration: underline;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import './team.scss';
import { getParam } from "@/utils"
class TreasureTeam extends Component {
constructor(props) {
super(props);
this.state = {
team: {},
currentMember: {}
};
}
componentDidMount() {
this.initMemberInfo();
}
componentWillReceiveProps(nextProps) {
const { data: oldData } = this.props;
const { data: newData } = nextProps;
if(newData.is_open != oldData.is_open) {
this.initMemberInfo(newData);
}
}
initMemberInfo = (params = {}) => {
const { data, userInfo } = this.props;
const arr = JSON.stringify(params) !== '{}'? params: data;
let member = arr.member;
let len = member.length - 5;
for(; len < 0; len++) {
member.push({});
}
this.setState({
team: Object.assign({}, arr, {
member
}),
currentMember: userInfo.uid? member.filter(item => item.uid == userInfo.uid)[0] : {}
});
}
computedClass = (id) => {
const { data: { is_open } } = this.props;
const { currentMember } = this.state;
return classnames(
'team-member__item',
{
'active': id === currentMember.uid && is_open,
}
);
}
computedBg = (val) => {
return val? {
backgroundImage: `url(${val})`
} : {};
}
// 查看队友的奖品,条件:宝箱已拆
toCheckPrize = (id) => {
const { team: { is_open, member = []} } = this.state;
if(is_open) {
const data = member.filter(item => item.uid === id);
this.setState({
currentMember: data[0]
});
}
}
render() {
const {
team: {
is_captain,
status,
team_num,
lack_member,
is_open,
treasure_code,
member = [],
},
currentMember
} = this.state;
const {
toSplitTreasure,
userInfo,
children
} = this.props;
return (
<div className="team-container" data-skip="team">
{
!is_captain &&
<i className="team-friend"></i>
}
{/* 组队状态 */}
{
status === 1
? <i className="team-status">组队中..</i>
: <i className="team-decorate"></i>
}
{/* 队伍类型 */}
{
is_captain
? <h2 className="team-title">{team_num}号队伍</h2>
: <h2 className="team-title">好友队伍</h2>
}
{/* 队员情况 */}
{
status === 1
? <p className="team-desc">还差{lack_member}名队员即可获得宝箱哦~</p>
: <p className="team-desc">组队成功</p>
}
<div className="team-member">
{
member.map((item, index) => (
<div
className={this.computedClass(item.uid)}
onClick={() => this.toCheckPrize(item.uid)}
key={index}
style={this.computedBg(item.head_img)}
>
{
item.is_captain &&
<span className="team-member__captain">队长</span>
}
</div>
))
}
</div>
<div className="team-footer" data-layout={is_open? 'column': 'row'}>
{/* 队伍未满 */}
{
status === 1 &&
<>
{
getParam('version')
? is_captain
? <a className="team-button" href={`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=1&version=${getParam('version')}`}>继续邀请队友</a>
: <a className="team-button" href={`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=2&version=${getParam('version')}`}>帮好友完成组队</a>
: is_captain
? <a className="team-button" href={`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=1`}>继续邀请队友</a>
: <a className="team-button" href={`https://h5.julyedu.com/activity/newyear-2019/landing?treasure_code=${treasure_code}&origin=2`}>帮好友完成组队</a>
}
</>
}
{/* 可拆状态 */}
{
(status === 2 && !is_open) &&
<>
<span className="team-icon" data-direction="left"></span>
<span className="team-button--split" onClick={toSplitTreasure}></span>
<span className="team-icon" data-direction="right"></span>
</>
}
{/* 已拆状态 */}
{
(status === 2 && is_open) &&
<>
{
currentMember.prize_name
? <p className="team-prize">{currentMember.prize_name}</p>
: <p className="team-prize">尚未开宝箱</p>
}
{
currentMember.uid == userInfo.uid
? children
: null
}
</>
}
</div>
</div>
)
}
}
export default TreasureTeam;
.team-container {
&[data-skip="team"] {
height: 195px;
border-radius: 3px;
box-sizing: border-box;
background-color: #fff;
}
}
[data-skip="team"] {
position: relative;
padding: 10px 0 0;
.team-friend {
position: absolute;
top: 0;
left: 0;
width: 22px;
height: 22px;
padding-left: 2px;
box-sizing: border-box;
font-size: 12px;
font-style: normal;
color: #fff;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/team-friend-bg.png');
}
.team-status {
position: absolute;
top: 0;
right: 0;
width: 54px;
border-radius: 0 3px 0 5px;
font-size: 12px;
font-style: normal;
color: #fff;
text-align: center;
line-height: 24px;
background-color: #00C091;
}
.team-decorate {
position: absolute;
top: -10px;
right: -10px;
width: 25px;
height: 25px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/team-decorate.png');
}
.team-title {
margin: 5px 0 0;
font-size: 16px;
color: #090909;
text-align: center;
line-height: 1;
}
.team-desc {
margin: 10px 0 0;
font-size: 12px;
color: #FF2121;
text-align: center;
line-height: 1;
}
.team-member {
display: flex;
align-items: center;
justify-content: center;
margin: 18px 0 0;
}
.team-member__item {
position: relative;
width: 44px;
height: 44px;
margin: 0 10px;
border-radius: 50%;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/team-bg.png');
&.active {
border: 1px solid #00C091;
&::after {
display: block;
}
}
&::after {
content: '';
display: none;
position: absolute;
left: 0;
bottom: -12px;
right: 0;
width: 24px;
height: 3px;
margin: 0 auto;
border-radius: 50%;
background-color: #E6E6E6;
}
}
.team-member__captain {
position: absolute;
top: -6px;
right: -23px;
width: 33px;
height: 18px;
border-radius: 9px 9px 9px 1px;
border: 1px solid #fff;
box-sizing: border-box;
font-size: 12px;
color: #0B7B45;
text-align: center;
line-height: 18px;
background-color: #FFE319;
}
.team-footer {
display: flex;
align-items: center;
justify-content: center;
margin: 17px 0 0;
&[data-layout="column"] {
flex-direction: column;
}
}
.team-button {
display: block;
width: 297px;
height: 44px;
margin: 0 auto;
border: 1px solid #090909;
border-radius: 5px;
box-sizing: border-box;
font-size: 16px;
color: #090909;
text-align: center;
line-height: 44px;
background-color: #FFE319;
}
.team-button--split {
display: inline-block;
width: 60px;
height: 46px;
margin: 0 20px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/treasure-split.gif');
}
.team-icon {
display: inline-block;
width: 31px;
height: 21px;
background-size: cover;
&[data-direction="left"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-direction-left.png');
}
&[data-direction="right"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-direction-right.png');
}
}
.team-prize {
margin: 5px 0 0;
font-size: 15px;
color: #303030;
line-height: 1;
}
.team-result {
margin: 8px 0 0;
font-size: 12px;
color: #666;
line-height: 1;
span {
text-decoration: underline;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss';
import { Toast } from 'antd-mobile';
import {Link, withRouter} from "react-router-dom"
import { getParam, http, SendMessageToApp, browser } from "@/utils"
import CommonContainer from './../../common/commonContainer/index'
import CommonPopup from './../../common/commonPopup/index';
import { connect } from 'react-redux';
import { Popup } from "@common/index"
import QRCode from 'qrcode'
@connect(state => ({
user: state.user
}))
class LiveRoom extends Component {
constructor(props) {
super(props);
this.state = {
list: [],
showMark: false,
subUrl: '',
QRCodeUrl: '',
}
}
componentDidMount() {
this.getLiveInfo();
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (this.props.isAppUpdate !== nextProps.isAppUpdate) {
this.getLiveInfo();
return false
}
return true
}
getLiveInfo = () => {
http.get(`${API.home}/activity/get_live_info`).then(res => {
const { code, data, msg } = res.data;
if (code === 200) {
this.setState({
list: data
})
} else {
Toast.info(msg);
}
});
}
// 预约直播
subscribe = (id) => {
// 检查是否已登录
const {hasError, data = {}} = this.props.user;
if(hasError) {
this.toLogin();
}else{
http.get(`${API['base-api']}/sys/createLiveQrcode/${id}`).then(res => {
let { errno, data, msg } = res.data;
if (errno === 200) {
QRCode.toDataURL(data.url, (err, url) => {
this.setState({
showMark: true,
subUrl: url,
QRCodeUrl: data.url,
})
})
} else {
Toast.info(msg);
}
});
}
}
// 已预约 给提示
tip = () => {
Toast.info('你已预约该直播');
}
// 去直播间
toLivingRoom = (id) => {
const {hasError, data = {}} = this.props.user;
if(hasError) {
this.toLogin();
}else{
window.location.href = `${window.location.protocol}//www.julyedu.com/live/m_room/${id}`
}
}
// 查看回放
checkVideo = (url) => {
const {hasError, data = {}} = this.props.user;
if(hasError) {
this.toLogin();
}else{
const vCourseId = url.split('/')[0];
window.location.href = `/play/video?id=${vCourseId}`
}
}
// 关闭弹框
closePopup = () => {
this.setState({
showMark: false,
})
// 关闭弹框的时候再次查询接口 查询预约状态
this.getLiveInfo();
}
// APP内需要保存图片 是否还是这样做 需要确认
saveImage = () => {
let version = getParam('version')
version = typeof version === 'string' ? version.replace('.', '').replace('.', '').slice(0, 3) : ''
const {QRCodeUrl} = this.state
if (version && parseInt(version) < 451) {
Toast.info('当前不支持此功能,升级到最新版本app可以点击保存二维码!', 2, null, false)
} else {
SendMessageToApp('generateQRCode', QRCodeUrl)
}
}
// 去登录
toLogin = () => {
if (!getParam('version')) {
this.props.history.push('/passport/login')
} else {
SendMessageToApp("toLogin")
}
}
render() {
const { list,showMark,subUrl } = this.state;
return (
<div className='live__container'>
{
showMark && (
<CommonPopup top={50} closePopup={this.closePopup} mark={true}>
<div className='sub__code_container'>
<p className='sub__title'>扫码关注“七月在线”服务号即可预约</p>
<img className='sub__qr_code' id={'live-qr-code'} src={subUrl} alt=""/>
{
browser.isAndroidApp ? (
<button className={'save-image'} onClick={this.saveImage}>保存二维码</button>
) : null
}
</div>
</CommonPopup>
)
}
<CommonContainer title='大咖直播' id="year-live">
<ul className='live__list'>
{
list.length && (
list.map((item, index) => {
return <li key={index} className='live_room_item'>
<img className='user__avatar' src={item.avatar} alt="" />
<div className='live__info'>
<div className="theme">
<span>主题:</span>
<p>{item.title}</p>
</div>
<div className="info__item">
<span>时间:</span>
<p>{item.date}</p>
</div>
<div className="info__item">
<span>讲师:</span>
<p>{item.teacher}</p>
</div>
{
item.on_live == 0 && item.is_end == 0 && item.is_subscribe == 0 && (
<span onClick={ ()=>this.subscribe(item.live_id)} className="order__btn">立即预约</span>
)
}
{
item.is_end == 1 && item.transcribe_url=='' && (
<span className="order__btn live__end">已结束</span>
)
}
{
item.on_live == 0 && item.is_end == 0 && item.is_subscribe == 1 && (
<span onClick={this.tip} className="order__btn subscribed">已预约</span>
)
}
{
item.on_live == 1 && item.is_end == 0 && (
<span onClick={()=>this.toLivingRoom(item.room_url)} className="order__btn living">正在直播</span>
)
}
{
item.is_end == 1 && item.transcribe_url != '' && (
<span onClick={() => this.checkVideo(item.transcribe_url)} className="order__btn check__video">查看回放</span>
)
}
</div>
</li>
})
)
}
</ul>
</CommonContainer>
</div>
)
}
}
export default withRouter(LiveRoom)
.live__container {
.live_room_item {
width: 330px;
height: 100px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
padding-bottom: 15px;
margin-top: 15px;
&:first-child {
border-bottom: 1px solid rgba(13, 77, 43, 1);
}
.user__avatar {
width: 73px;
height: 85px;
flex: 0 0 auto;
margin-right: 12px;
background: #ddd;
border-radius: 4px;
}
.live__info {
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
color: #fff;
font-size: 14px;
width: 246px;
height: 85px;
position: relative;
.info__item {
display: flex;
justify-content: flex-start;
align-content: center;
&:nth-child(2) {
margin: 9px 0;
}
span {
width: 46px;
flex: 0 0 auto;
color: #eaf787;
line-height: 16px;
}
p {
line-height: 16px;
}
}
.theme {
span {
display: block;
width: 46px;
float: left;
color: #eaf787;
line-height: 16px;
}
p {
width: 198px;
overflow: hidden;
text-overflow: ellipsis;
display: -webkit-box;
-webkit-line-clamp: 2;
float: left;
line-height: 16px;
color: #fff;
/* autoprefixer: off */
-webkit-box-orient: vertical;
}
}
.order__btn {
position: absolute;
right: 0;
bottom: 0;
width: 89px;
height: 28px;
border-radius: 4px;
display: flex;
justify-content: center;
align-items: center;
color: #070f08;
background: linear-gradient(
90deg,
rgba(255, 227, 0, 1) 0%,
rgba(255, 202, 0, 1) 100%
);
}
.subscribed {
background: rgba(254, 228, 29, 1);
}
.live__end{
background: #999;
color: #fff;
}
.living {
background: rgba(0, 153, 255, 1);
color: #fff;
}
.check__video {
background: rgba(114, 220, 141, 1);
color: #fff;
}
}
}
.sub__code_container {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.sub__title {
color: #525c65;
font-size: 16px;
line-height: 16px;
font-weight: 500;
text-align: center;
margin: 20px 0;
}
}
.save-image {
margin-top: 16px;
width: 270px;
height: 44px;
background: rgba(255, 227, 25, 1);
border: 1px solid rgba(9, 9, 9, 1);
border-radius: 5px;
font-size: 16px;
font-weight: normal;
color: rgba(9, 9, 9, 1);
}
}
import React, { Component } from 'react'
import './index.scss'
import { http, SendMessageToApp, getParam, browser } from '@/utils'
import CommonContainer from './../../common/commonContainer/index'
import CourseItem from '../../../../blessingPreheat/courseItem/index'
import { withRouter } from "react-router-dom"
import CommonPopup from './../../common/commonPopup/index'
import { Toast } from 'antd-mobile'
import QRCode from 'qrcode'
import { connect } from "react-redux"
import dateFns from 'date-fns';
@connect(state => ({
user: state.user
}))
class YearCourse extends Component {
constructor(props) {
super(props)
this.state = {
tofreeStudy: false,
basic: {
course: [],
courseList: [],
isMore: false,
addshowMore: false,
},
advanced: {
course: [],
courseList: [],
isMore: false,
addshowMore: false,
},
higher: {
course: [],
courseList: [],
isMore: false,
addshowMore: false,
},
expand: {
course: [],
courseList: [],
isMore: false,
addshowMore: false,
},
bigcourse: {
course: [],
courseList: [],
isMore: false,
},
freecourse: {
course: [],
courseList: [],
isMore: false,
},
groupcourse: {
course: [],
courseList: [],
isMore: false,
},
isshowFollow: false, // 是否提示关注公众号
wish: {
id: '',
key: ""
},
followBarcode: '',
qrUrl: '',
sum: '',
removable: '',
currentId: '',
}
}
componentDidMount() {
this.getTeamInfo()
this.getLength()
this.fetchBigCourse()
this.fetchFreeCourse()
this.fetchGroupCourse()
// AI之路-基础
this.fetchAICourse('one', false)
// AI之路-进阶
this.fetchAICourse('two', false)
// AI之路-高阶
this.fetchAICourse('three', false)
// AI之路-拓展
this.fetchAICourse('four', false)
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (this.props.isAppUpdate !== nextProps.isAppUpdate) {
this.getTeamInfo()
this.getLength()
this.fetchBigCourse()
this.fetchFreeCourse()
this.fetchGroupCourse()
// AI之路-基础
this.fetchAICourse('one')
// AI之路-进阶
this.fetchAICourse('two')
// AI之路-高阶
this.fetchAICourse('three')
// AI之路-拓展
this.fetchAICourse('four')
return false
}
return true
}
getLength = () => {
let _this = this
http.get(`${API.home}/activity/wish_sum`).then(res => {
const { code, data } = res.data
if (code == 200) {
_this.setState({
sum: data.sum
})
}
})
}
fetchBigCourse = () => {
const { bigcourse } = this.state
http.get(`${API.home}/activity/preheat_data`).then(res => {
const { code, data } = res.data
if (code === 200) {
this.setState({
bigcourse: Object.assign({}, bigcourse, {
isMore: false,
course: data,
courseList: data,
})
})
}
})
}
fetchFreeCourse = () => {
const { freecourse } = this.state
http.get(`${API['base-api']}/assistance/detail`).then(res => {
const { errno, data } = res.data
if (errno === 200) {
this.setState({
freecourse: Object.assign({}, freecourse, {
isMore: data.course_info.length > 4 ? true : false,
course: data.course_info.length > 4 ? data.course_info.filter((item, index) => index < 4) : data.course_info,
courseList: data.course_info,
})
})
}
})
}
fetchGroupCourse = () => {
const { groupcourse } = this.state
http.get(`${API.home}/activity/excellent_course`).then(res => {
const { code, data } = res.data
if (code === 200) {
this.setState({
groupcourse: Object.assign({}, groupcourse, {
isMore: data.length > 4 ? true : false,
course: data.length > 4 ? data.filter((item, index) => index < 4) : data,
courseList: data,
})
})
}
})
}
fetchAICourse = (key, addshowMore) => {
http.get(`${API.home}/activity/four_stage/${key}`).then(res => {
const { code, data } = res.data
if (code === 200) {
this.getList(key, data, addshowMore)
}
})
}
getList = (key, data, addshowMore) => {
const { basic, advanced, higher, expand } = this.state
if (key === 'one') {
this.setState({
basic: Object.assign({}, basic, {
isMore: data.length > 4 && !addshowMore ? true : false,
course: data.length > 4 && !addshowMore ? data.filter((item, index) => index < 4) : data,
courseList: data,
addshowMore: addshowMore,
})
})
}
if (key === 'two') {
this.setState({
advanced: Object.assign({}, advanced, {
isMore: data.length > 4 && !addshowMore ? true : false,
course: data.length > 4 && !addshowMore ? data.filter((item, index) => index < 4) : data,
courseList: data,
addshowMore: addshowMore,
})
})
}
if (key === 'three') {
this.setState({
higher: Object.assign({}, higher, {
isMore: data.length > 4 && !addshowMore ? true : false,
course: data.length > 4 && !addshowMore ? data.filter((item, index) => index < 4) : data,
courseList: data,
addshowMore: addshowMore,
})
})
}
if (key === 'four') {
this.setState({
expand: Object.assign({}, expand, {
isMore: data.length > 4 && !addshowMore ? true : false,
course: data.length > 4 && !addshowMore ? data.filter((item, index) => index < 4) : data,
courseList: data,
addshowMore: addshowMore,
})
})
}
}
toQQque = () => {
if (!getParam('version')) {
location.href = 'https://q.url.cn/AB8aue?_type=wpa&qidian=true'
} else {
SendMessageToApp("toQQ", 'https://q.url.cn/AB8aue?_type=wpa&qidian=true')
}
}
// 去课程详情页
toCourse = (courseId) => {
const { history } = this.props
if (!getParam('version')) {
history.push(`/detail?id=${courseId}`)
} else {
SendMessageToApp("toCourse", courseId)
}
}
handleToMore = (key) => {
let data = {}
if (this.state[key]['isMore']) {
data[key] = {
isMore: !this.state[key]['isMore'],
course: this.state[key]['courseList'],
courseList: this.state[key]['courseList'],
addshowMore: !this.state[key]['addshowMore']
}
this.setState({
...data
})
} else {
data[key] = {
isMore: !this.state[key]['isMore'],
course: this.state[key]['courseList'].filter((item, index) => index < 4),
courseList: this.state[key]['courseList'],
addshowMore: !this.state[key]['addshowMore']
}
this.setState({
...data
})
}
}
// 去登录
toLogin = () => {
if (!getParam('version')) {
this.props.history.push('/passport/login')
} else {
SendMessageToApp("toLogin")
}
}
// 免费学习
freeStudy = () => {
this.setState({
tofreeStudy: true,
})
}
// 关闭弹框
closePopup = () => {
this.setState({
tofreeStudy: false,
})
}
closePopupWish = () => {
const _this = this
_this.setState({
isshowFollow: false
})
setTimeout(function () {
_this.toJoinList(_this.state.wish.id, _this.state.wish.key)
}, 200)
}
getQRcodeUrl = () => {
let _this = this
http.get(`${API['base-api']}/wx/user_temporary_qrcode/${_this.props.user.data.uid}`)
.then(res => {
const { errno, data, msg } = res.data
if (errno == 0) {
this.setState({
qrUrl: data.url
})
QRCode.toDataURL(data.url, (err, url) => {
this.setState({
followBarcode: url,
})
})
} else {
Toast.info(msg, 2)
}
})
}
// 点击加入心愿单登录验证,在判断是否关注公众号,已关注的话直接加入,未关注弹出二维码弹窗,点击关闭按钮加入心愿单
addWishList = (id, key) => {
const _this = this
const isLogin = !this.props.user.hasError
_this.setState({
wish: {
id: id,
key: key
}
})
if (isLogin) {
_this.isFollow(id, key)
} else {
_this.toLogin()
}
}
isFollow = (id, key) => {
const _this = this
http.get(`${API.home}/sys/user/isFollowWeChat`).then(res => {
const { code, data, msg } = res.data
if (code === 200) {
_this.setState({
isshowFollow: !data.is_follow
})
if (!_this.state.isshowFollow) {
_this.toJoinList(id, key)
} else {
_this.getQRcodeUrl()
}
} else {
Toast.info(msg, 2)
}
})
}
toJoinList = (id, key) => {
const _this = this
http.post(`${API.home}/activity/join_list`, { course_id: id })
.then(res => {
const { code, msg } = res.data
if (code == 200) {
Toast.success('已成功加入心愿单', 3)
_this.getLength()
if (key === '1') {
_this.fetchAICourse('one', _this.state.basic.addshowMore)
}
if (key === '2') {
_this.fetchAICourse('two', _this.state.advanced.addshowMore)
}
if (key === '3') {
_this.fetchAICourse('three', _this.state.higher.addshowMore)
}
if (key === '4') {
_this.fetchAICourse('four', _this.state.expand.addshowMore)
}
if (key === 'group') {
_this.fetchGroupCourse()
}
} else {
Toast.info(msg, 2)
}
})
}
// 安卓手机保存二维码
saveImage = () => {
let version = getParam('version')
version = typeof version === 'string' ? version.replace('.', '').replace('.', '').slice(0, 3) : ''
const QRCodeUrl = this.state.qrUrl
if (version && parseInt(version) < 451) {
Toast.info('当前不支持此功能,升级到最新版本app可以点击保存二维码!', 3, null, false)
} else {
SendMessageToApp('generateQRCode', QRCodeUrl)
}
}
saveImage2 = () => {
let version = getParam('version')
version = typeof version === 'string' ? version.replace('.', '').replace('.', '').slice(0, 3) : ''
const QRCodeUrl = 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/2018christyear/h5/qrcode.jpg'
if (version && parseInt(version) < 451) {
Toast.info('当前不支持此功能,升级到最新版本app可以点击保存二维码!', 3, null, false)
} else {
SendMessageToApp('saveImage', QRCodeUrl)
}
}
// 获取队伍信息
getTeamInfo = () => {
http.get(`${API.home}/sys/treasure/teamInfo`).then(res => {
const { code, data, msg } = res.data
if (code === 200) {
const { info, removable_data } = data
this.setState({
removable: info.removable,
currentId: info.removable > 0 ? removable_data[0].id : null
})
} else {
Toast.info(msg)
}
})
}
// 跳转到我的宝箱列表页
toBoxList = () => {
const isLogin = !this.props.user.hasError
const { currentId } = this.state
let search = ''
if (currentId) {
search = `?id=${currentId}`
}
if (isLogin) {
if (!getParam('version')) {
this.props.history.push(`/year/yearTreasure${search}`)
} else {
this.props.history.push(`/year/yearTreasure${search}?version=${getParam('version')}`)
}
} else {
this.toLogin()
}
}
toYearWish = () => {
const isLogin = !this.props.user.hasError
if (isLogin) {
if (!getParam('version')) {
this.props.history.push('/year/yearWish')
} else {
this.props.history.push(`/year/yearWish?version=${getParam('version')}`)
}
} else {
this.toLogin()
}
}
toInviteFriends = (oid, params = {}) => {
const { history } = this.props
if (getParam('version')) {
let data = {
title: `【仅剩${params.number}个名额】我${params.price}元拼了《${params.course_title}》`,
desc: params.course_title,
link: `${API.m}/togroup?id=${oid}&is_originator=1`,
imgUrl: params.image_name,
}
SendMessageToApp("toShare", data)
} else {
history.push(`/togroup?id=${oid}`);
}
}
isCountDown = (condition, val) => {
if (condition) {
return val;
}
return '';
}
formatTitleAndKey = (key) => {
let data = null;
switch (key) {
case 1:
data = {
title: '基础',
key: 'basic'
};
break;
case 2:
data = {
title: '进阶',
key: 'advanced'
};
break;
case 3:
data = {
title: '高阶',
key: 'higher'
};
break;
case 4:
data = {
title: '扩展',
key: 'expand'
};
break;
default:
data = null;
break;
}
return data;
}
formatCourseData = (key) => {
const { basic, advanced, higher, expand } = this.state;
let data = null;
switch (key) {
case 1:
data = basic;
break;
case 2:
data = advanced;
break;
case 3:
data = higher;
break;
case 4:
data = expand;
break;
default:
data = null;
break;
}
return data;
}
toCart = (id) => {
const { history } = this.props;
http.post(`${API.home}/m/cart/add`, {
course_id: id
}).then((res) => {
const { code, msg } = res.data;
// code 15001 已加入购物车
if (code === 200 || code === 15001) {
if(getParam('version')) {
SendMessageToApp('toShoppingCart')
}else {
history.push('/shopcart');
}
} else if (code === 4030 || code === 4040) {
this.toLogin();
} else {
Toast.info(msg, 2);
}
})
};
toContinueBargain = (id, price, code, image) => {
const { history } = this.props;
if(getParam('version')) {
let data = {
title: '我发现一门好课,快来帮我砍价吧!',
desc: `我已经砍了${price}元,看看你能砍多少`,
link: `${API.m}/bargain-middle-page?id=${id}&bargaincode=${code}&is_originator=1`,
imgUrl: image,
}
SendMessageToApp("toShare", data)
}else {
history.push(`/bargain-middle-page?id=${id}&bargaincode=${code}&is_originator=1`);
}
}
// 砍完价去支付
bargainToOrder = (id) => {
const { history, user } = this.props;
if(user.hasError) {
this.toLogin();
}else{
if(getParam('version')) {
SendMessageToApp('toPay', id)
}else {
http.get(`${API['base-api']}/m/cart/addtopreorder/[${id}]`).then((res) => {
const { errno, msg } = res.data;
if (errno === 0) {
history.push(`/order?id=[${id}]`, {bargain: 1});
} else {
Toast.info(msg, 2);
}
})
}
}
}
render() {
const {
bigcourse,
freecourse,
groupcourse,
basic,
advanced,
higher,
expand,
removable,
sum,
} = this.state
const { stage,treasureStage } = this.props
return (
<div className={'year-index-course'}>
{/*浮框*/}
{
Number(treasureStage) === 1 &&
<div className='nav-right'>
<span onClick={this.toBoxList} className='nav-right__link'>
未开宝箱
{
removable > 0 &&
<i className="nav-right__number">{removable}</i>
}
</span>
<a onClick={() => this.toYearWish()} className='nav-right__link'>
心愿单
{
sum > 0 &&
<i className="nav-right__number">{sum}</i>
}
</a>
</div>
}
{
Number(treasureStage) === 0 &&
<div className='nav-right-wish nav-right'>
<a onClick={() => this.toYearWish()} className='nav-right__link'>
心愿单
{
sum > 0 &&
<i className="nav-right__number">{sum}</i>
}
</a>
</div>
}
{/* 重磅好课 */}
<CommonContainer title='重磅好课' id='year-course'>
{
(bigcourse.course && bigcourse.course.length > 0) &&
<>
<div className='bigcourse course-box'>
{
bigcourse.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
}
{
item.is_buy == 0 &&
<a
onClick={() => this.toQQque()}
className="btn big-course"
>免费试听</a>
}
</div>
</CourseItem>
))
}
</div>
{/* {
(bigcourse.courseList && bigcourse.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('bigcourse')}
>{bigcourse.isMore ? '查看更多' : '收起'}</button>
} */}
</>
}
</CommonContainer>
{/* 人气好课免费学 */}
{
Number(stage) !== 3 &&
<CommonContainer title='人气好课免费学' id='year-free'>
<a className='boss__add' href="/active/givecourse?activename=shuangdan">更有42本技术书籍免费送</a>
{
(freecourse.course && freecourse.course.length > 0) &&
<>
<div className='freecourse course-box'>
{
freecourse.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
}
{
item.is_buy == 0 &&
<a
onClick={() => this.freeStudy()}
className="btn free-study"
>点击免费学</a>
}
<p className="free-course-num">
已送出<span>{item.act_num}</span>个课
</p>
</div>
</CourseItem>
))
}
</div>
{
(freecourse.courseList && freecourse.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('freecourse')}
>{freecourse.isMore ? '查看更多' : '收起'}</button>
}
</>
}
</CommonContainer>
}
{/* stage,活动阶段 0-不在活动时间 1-预热 2-正式 3-返场 */}
{
Number(stage) !== 1 &&
<>
{/* 精品好课1分开抢 */}
<CommonContainer title='精品好课1分开抢' id='year-group'>
{
(groupcourse.course && groupcourse.course.length > 0) &&
<>
<div className='groupcourse course-box' data-stage="2">
{
groupcourse.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
time={this.isCountDown(item.is_assemble === 1, item.add_time)}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{/* is_assemble 0 未拼团 1 正在拼团 2 已购买 */}
{
item.is_assemble == 2 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-group"
data-status="study"
>开始学习</a>
</div>
</>
}
{
item.is_assemble != 2 &&
<>
<div className="type">
<span className="tag" data-color="green">拼团价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">0.01</span>
<span className="old-price">
<s>¥{item.price1}</s>
</span>
</div>
{
item.is_assemble == 0 &&
<div className="progree-and-sale">
<div className="progress">
<i
className="progress_bar"
style={{
width: `${item.progress}%`
}}
></i>
</div>
<p className="sale-sum">
{Number(item.sum <= 285) ? `已抢${item.sum}个` : '即将售罄'}
</p>
</div>
}
<div className="status">
{
item.is_assemble == 0 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-group"
>马上抢>></a>
}
{
item.is_assemble == 1 &&
<a
onClick={() => this.toInviteFriends(item.order_id, {
number: item.number,
course_title: item.course_title,
image_name: item.image_name,
price: 0.01
})}
className="status-btn to-group"
data-status="done"
>已参团,邀请好友参团</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(groupcourse.courseList && groupcourse.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('groupcourse')}
>{groupcourse.isMore ? '查看更多' : '收起'}</button>
}
</>
}
</CommonContainer>
{/* 好课价到,等你抄底 */}
<CommonContainer title='好课价到,等你抄底' id='year-discount'>
{
[1, 2, 3, 4].map(item => {
const keys = this.formatTitleAndKey(item);
const data = this.formatCourseData(item);
return (
<React.Fragment key={item}>
<h4 className="ai-course__subtitle">{keys.title}</h4>
{
(data.course && data.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
data.course.map(val => {
return (
<CourseItem
image={val.image_name}
key={val.course_id}
id={val.course_id}
time={this.isCountDown(val.type === 2, val.end_time)}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{/* type 1 立即参团 2 已参团 3 我要砍价 4 已参加砍价 可以继续砍价 5 马上抢 6 开始学习 7 已参加一分钱拼团 8 砍价待支付 */}
{
(val.type === 4 || val.type === 8) &&
<div className="bargain-price">已砍{val.already_bargain}</div>
}
{
val.type === 0 &&
<>
<div className="type">
<span className="tag" data-color="green">活动价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">{val.original_price}</span>
<span className="old-price">
<s>¥{val.original_price}</s>
</span>
</div>
</>
}
{
(val.type === 1 || val.type === 2) &&
<>
<div className="type">
<span className="tag" data-color="green">拼团价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">{val.pdd_price}</span>
<span className="old-price">
<s>¥{val.original_price}</s>
</span>
</div>
</>
}
{
(val.type === 3 || val.type === 4 || val.type === 8) &&
<>
<div className="type">
<span className="tag" data-color="green">好友帮帮砍</span>
</div>
<div className="price price-group">
<span className="price-label">到手最低:¥</span>
<span className="new-price">{val.low_prize}</span>
<span className="old-price">
<s>¥{val.original_price}</s>
</span>
</div>
</>
}
{
val.type === 6 &&
<p className={'course-title text-overflow-1'}>
{val.course_title}
</p>
}
<div className="status" data-layout={val.type ===4? 'row': '' }>
{
val.type === 0 &&
<a
onClick={() => this.toCart(val.course_id)}
className="status-btn to-group"
>立即购买</a>
}
{
val.type === 1 &&
<a
onClick={() => this.toCourse(val.course_id)}
className="status-btn to-group"
>立即参与拼团</a>
}
{
val.type === 2 &&
<a
onClick={() => this.toInviteFriends(val.order_id, {
number: val.number,
course_title: val.course_title,
image_name: val.image_name,
price: val.pdd_price
})}
className="status-btn to-group"
data-status="done"
>已参团,邀请好友参团</a>
}
{
val.type === 3 &&
<a
onClick={() => this.toCourse(val.course_id)}
className="status-btn to-group"
>我要砍价</a>
}
{
val.type === 4 &&
<>
<a
onClick={() => this.toContinueBargain(val.course_id, val.already_bargain, val.bargain_code, val.image_name)}
className="status-btn to-group"
>继续砍价</a>
<a
onClick={() => this.bargainToOrder(val.course_id)}
className="status-btn to-group"
>支付{val.actual_payment}</a>
</>
}
{
val.type === 8 &&
<a
onClick={() => this.bargainToOrder(val.course_id)}
className="status-btn to-group"
>支付{val.actual_payment}</a>
}
{
val.type === 6 &&
<a
onClick={() => this.toCourse(val.course_id)}
className="btn to-group"
data-status="study"
>开始学习</a>
}
</div>
</div>
</CourseItem>
)
})
}
</div>
{
(data.courseList && data.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore(keys.key)}
>{data.isMore ? '查看更多' : '收起'}</button>
}
</>
}
</React.Fragment>
)
})
}
</CommonContainer>
</>
}
{
Number(stage) === 1 &&
<>
{/* 精品好课1分开抢 */}
<CommonContainer title='精品好课1分开抢' id='year-group'>
{
(groupcourse.course && groupcourse.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
groupcourse.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="group-num">限量300</div>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
<span className="tag">拼团价</span>
<span className="time">1223日开团</span>
</div>
<div className="price">
¥
<span className="new-price">0.01</span>
<span className="old-price">
现价:<s>¥{item.price1}</s>
</span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id, 'group')}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(groupcourse.courseList && groupcourse.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('groupcourse')}
>{groupcourse.isMore ? '查看更多' : '收起'}</button>
}
</>
}
</CommonContainer>
{/* 好课价到,等你抄底 */}
<CommonContainer title='好课价到,等你抄底' id='year-discount'>
<h4 className="ai-course__subtitle">基础</h4>
{
(basic.course && basic.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
basic.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
{
item.type == 0 &&
<>
<span className="tag">活动价</span>
<span className="time">12.23开始</span>
</>
}
{
item.type == 1 &&
<>
<span className="tag">拼团价</span>
<span className="time">12.23开团</span>
</>
}
{
item.type == 2 &&
<>
<span className="tag">好友帮帮砍</span>
<span className="time">12.23开砍</span>
</>
}
</div>
<div className="price">
{item.type == 2 ? '到手最低:¥' : '¥'}
<span className="new-price">{item.price2}</span>
<span className="old-price">
{item.type == 2 ? '' : '现价:'}
<s>¥{item.price1}</s>
</span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id, '1')}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(basic.courseList && basic.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('basic')}
>{basic.isMore ? '查看更多' : '收起'}</button>
}
</>
}
<h4 className="ai-course__subtitle">进阶</h4>
{
(advanced.course && advanced.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
advanced.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
{
item.type == 0 &&
<>
<span className="tag">活动价</span>
<span className="time">12.23开始</span>
</>
}
{
item.type == 1 &&
<>
<span className="tag">拼团价</span>
<span className="time">12.23开团</span>
</>
}
{
item.type == 2 &&
<>
<span className="tag">好友帮帮砍</span>
<span className="time">12.23开砍</span>
</>
}
</div>
<div className="price">
{item.type == 2 ? '到手最低:¥' : '¥'}
<span className="new-price">{item.price2}</span>
<span className="old-price">
{item.type == 2 ? '' : '现价:'}
<s>¥{item.price1}</s>
</span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id, '2')}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(advanced.courseList && advanced.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('advanced')}
>
{advanced.isMore ? '查看更多' : '收起'}
</button>
}
</>
}
<h4 className="ai-course__subtitle">高阶</h4>
{
(higher.course && higher.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
higher.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
{
item.type == 0 &&
<>
<span className="tag">活动价</span>
<span className="time">12.23开始</span>
</>
}
{
item.type == 1 &&
<>
<span className="tag">拼团价</span>
<span className="time">12.23开团</span>
</>
}
{
item.type == 2 &&
<>
<span className="tag">好友帮帮砍</span>
<span className="time">12.23开砍</span>
</>
}
</div>
<div className="price">
{item.type == 2 ? '到手最低:¥' : '¥'}
<span className="new-price">{item.price2}</span>
<span className="old-price">
{item.type == 2 ? '' : '现价:'}
<s>¥{item.price1}</s>
</span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id, '3')}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(higher.courseList && higher.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('higher')}
>{higher.isMore ? '查看更多' : '收起'}</button>
}
</>
}
<h4 className="ai-course__subtitle">扩展</h4>
{
(expand.course && expand.course.length > 0) &&
<>
<div className='groupcourse course-box'>
{
expand.course.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
{
item.type == 0 &&
<>
<span className="tag">活动价</span>
<span className="time">12.23开始</span>
</>
}
{
item.type == 1 &&
<>
<span className="tag">拼团价</span>
<span className="time">12.23开团</span>
</>
}
{
item.type == 2 &&
<>
<span className="tag">好友帮帮砍</span>
<span className="time">12.23开砍</span>
</>
}
</div>
<div className="price">
{item.type == 2 ? '到手最低:¥' : '¥'}
<span className="new-price">{item.price2}</span>
<span className="old-price">
{item.type == 2 ? '' : '现价:'}
<s>¥{item.price1}</s>
</span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id, '4')}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
{
(expand.courseList && expand.courseList.length > 4) &&
<button
className="more-button"
onClick={() => this.handleToMore('expand')}
>{expand.isMore ? '查看更多' : '收起'}</button>
}
</>
}
</CommonContainer>
</>
}
{
this.state.tofreeStudy &&
<CommonPopup top={100} closePopup={this.closePopup} mark={false}>
<div className='sub__code_container'>
<p className='sub__title'>提醒服务</p>
<p className='sub__tip'>进入服务号回复<i>77</i>免费领取课程</p>
<img className='sub__qr_code' id={'live-qr-code'}
src='//julyedu-cdn.oss-cn-beijing.aliyuncs.com/2018christyear/h5/qrcode.jpg' alt="" />
{
browser.isAndroidApp ? (
<button className={'save-image'} onClick={this.saveImage2}>保存二维码</button>
) : <p className='sub__tip'>长按识别/扫码 关注【七月在线】服务号</p>
}
</div>
</CommonPopup>
}
{
this.state.isshowFollow &&
<CommonPopup top={100} closePopup={this.closePopupWish} mark={false}>
<div className='sub__code_container'>
<p className='sub__title'>提醒服务</p>
<p className='sub__tip'>课程开售立即提醒,不错过任何优惠哦!</p>
<img className='sub__qr_code' id={'live-qr-code'}
src={this.state.followBarcode} alt="" />
{
browser.isAndroidApp ? (
<button className={'save-image'} onClick={this.saveImage}>保存二维码</button>
) : <p className='sub__tip'>长按识别/扫码 关注【七月在线】服务号</p>
}
</div>
</CommonPopup>
}
</div>
)
}
}
export default withRouter(YearCourse)
.year-index-course {
.boss__add {
font-size: 12px;
color: #fff;
text-align: center;
height: 16px;
line-height: 16px;
text-decoration: underline;
display: block;
margin: 12px auto 0;
}
.course-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.course-container {
width: 168px;
margin: 15px 0 0 0;
text-align: center;
position: relative;
}
.group-num {
width: 66px;
height: 16px;
position: absolute;
left: 10px;
top: 10px;
line-height: 16px;
background: #CA161C;
opacity: 0.8;
border-radius: 1px;
font-size: 12px;
color: #fff;
text-align: center;
}
.bargain-price {
position: absolute;
left: 4px;
top: 10px;
margin: 0;
height: 18px;
padding: 0 8px;
border-radius: 0 9px 9px 0;
font-size: 12px;
color: #fff;
line-height: 18px;
background-color: #F01D0E;
}
.coupon-course__footer {
.course-title {
padding-left: 10px;
font-size: 15px;
color: #333;
font-weight: 500;
margin-top: 7px;
}
.btn {
display: inline-block;
width: 138px;
height: 24px;
text-align: center;
line-height: 24px;
border-radius: 2px;
font-size: 12px;
outline: none;
border: none;
letter-spacing: 1px;
}
.big-course {
background-color: #FEE41D;
border: 1px solid #090F08;
color: #090F08;
margin-top: 10px;
}
.to-study {
background-color: #09f;
color: #fff;
position: absolute;
left: 10px;
bottom: 10px;
}
.free-study {
background: linear-gradient(-90deg, #EB1612 0%, #F92927 100%);
color: #fff;
margin-top: 10px;
}
.free-course-num {
font-size: 12px;
color: #070F08;
margin-top: 7px;
letter-spacing: 1px;
span {
font-size: 14px;
color: #FF0002;
}
}
}
.type {
text-align: left;
padding-left: 7px;
margin-top: 3px;
.tag {
display: inline-block;
padding: 0 6px;
height: 14px;
line-height: 15px;
text-align: center;
font-size: 12px;
color: #FFF;
position: relative;
z-index: 0;
}
.time {
display: inline-block;
height: 15px;
line-height: 15px;
padding: 0 6px;
margin-left: 5px;
position: relative;
font-size: 12px;
color: #555;
text-align: center;
z-index: 0;
}
.time:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #E6E6E6;
transform: skewX(-20deg);
z-index: -1;
}
.tag:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #FF0002;
transform: skewX(-20deg);
z-index: -1;
}
.tag[data-color="green"]:before {
background-color: #357345;
}
}
.price {
margin-top: 3px;
padding-left: 4px;
font-size: 12px;
color: #FF0002;
text-align: left;
&.price-group {
font-size: 0;
height: 30px;
}
.price-label {
font-size: 12px;
}
.new-price {
font-size: 16px;
}
.old-price {
margin-left: 2px;
font-size: 12px;
color: #666;
}
}
.status {
position: absolute;
left: 0;
bottom: 10px;
right: 0;
padding: 0 5px;
text-align: left;
&[data-layout="row"] {
display: flex;
.to-group {
font-size: 12px;
&:nth-child(1) {
margin-right: 2px;
}
&:nth-child(2) {
margin-left: 2px;
}
}
}
.status-btn {
display: inline-block;
height: 22px;
line-height: 22px;
border-radius: 2px;
text-align: center;
font-size: 12px;
color: #fff;
}
.to-buy {
width: 55px;
background-color: #FF8080;
}
.to-group {
display: block;
width: 100%;
height: 22px;
border-radius: 11px;
box-sizing: border-box;
font-size: 14px;
color: #fff;
text-align: center;
line-height: 22px;
background: linear-gradient(-90deg,rgba(235,22,18,1) 0%,rgba(255,0,2,1) 100%);
&[data-status="study"] {
background: #0099FF;
}
&[data-status="done"] {
border: 1px solid #090F08;
font-size: 12px;
color: #090F08;
background: #FEE41D;
}
}
.add-wish, .add-wish-success {
width: 88px;
margin-left: 5px;
outline: none;
color: #FF0002;
background-color: #fff;
border: 1px solid #FF0002;
img {
width: 12px;
height: 11px;
margin-right: 2px;
position: relative;
top: 1px;
}
}
.add-wish-success {
color: #fff;
background: linear-gradient(90deg, rgba(235, 22, 18, 1) 0%, rgba(249, 41, 39, 1) 100%);
}
}
}
.bigcourse .course-container {
height: 156px;
}
.freecourse .course-container {
height: 177px;
}
.groupcourse .course-container {
height: 195px;
}
.groupcourse[data-stage="2"] .course-container {
height: 215px;
}
.progree-and-sale {
display: flex;
align-items: center;
justify-content: center;
padding-left: 5px;
}
.progress {
width: 90px;
height: 8px;
border-radius: 4px;
background-color: #E6E6E6;
}
.progress_bar {
display: block;
width: 10%;
height: 100%;
border-radius: 4px 0 0 4px;
background-color: #FF0002;
}
.sale-sum {
flex: 1;
margin: 0;
font-size: 12px;
color: #333;
text-align: center;
line-height: 1;
}
.ai-course__subtitle {
width: 73px;
height: 24px;
margin: 15px auto 0;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
color: #070F08;
text-align: center;
line-height: 22px;
letter-spacing: 2px;
background-color: #FFE300;
border: 1px solid #070F08;
}
.more-button {
display: block;
width: 75px;
height: 26px;
margin: 15px auto 5px;
padding: 0;
border-radius: 12px;
font-size: 12px;
font-weight: 400;
color: #fff;
line-height: 26px;
cursor: pointer;
outline: none;
background-color: #0F6237;
border: none;
letter-spacing: 1px;
}
.sub__code_container {
padding: 20px;
}
.save-image {
display: block;
width: 133px;
height: 30px;
margin: 20px auto 0 auto;
background: rgba(83, 39, 250, 1);
border-radius: 15px;
font-size: 14px;
color: #fff;
-webkit-appearance: none;
outline: 0;
border: none;
}
.nav-right {
width: 100px;
height: 125px;
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/sd_fc_bj.png");
background-repeat: no-repeat;
background-size: cover;
position: fixed;
right: 0;
bottom: 20%;
margin-top: -57px;
z-index: 22;
.nav-right__link {
display: block;
position: relative;
font-size: 12px;
font-weight: 500;
color: #fff;
text-align: center;
top: 47px;
line-height: 25px;
}
.nav-right__number {
position: absolute;
top: -5px;
right: 5px;
padding: 0 5px;
border: 1px solid #F7D067;
border-radius: 7px 7px 7px 0px;
font-size: 12px;
font-style: normal;
color: #FEE41D;
background-color: #FF4F24;
height: 16px;
line-height: 14px;
}
}
.nav-right-wish {
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/fanc-bx.png");
.nav-right__link{
top: 60px;
left: 10px;
}
}
}
\ No newline at end of file
import React, {Component} from 'react'
import './index.scss'
import LiveRoom from './LiveRoom/index'
import YearCourse from './YearCourse/index'
import TreasureBox from './../treasure-box/index'
import TreasureNav from './nav'
import CommonPopup from './../common/commonPopup/index'
import cookie from "js-cookie"
import {setCurrentUser, startFetchUser} from "@/store/userAction"
import {SendMessageToApp, getParam, http} from '@/utils'
import {addDays} from "date-fns"
import {connect} from "react-redux"
import {Toast} from 'antd-mobile'
import {compose} from "redux"
@connect(state => ({
user: state.user
}),
{setCurrentUser, startFetchUser}
)
export default class index extends Component {
state = {
removable: 0, // 未拆宝箱的数量
currentOpenId: 0, // 当前要拆的宝箱的队伍的ID
treasure_stage: 0, // 宝箱的活动阶段
activity_stage: 0, // 整个活动的阶段
userInfoList: [],
userInfo: {},
isAppUpdate: false,
showMark: false,
banner: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_banner_bj%402x.png'
}
componentDidMount() {
const _this = this
// 获取App登录信息
window['loginInfo'] = result => {
_this.loginInfo(result)
}
_this.getStage()
document.title = '七月在线年终大回馈,幸运宝箱随你开,100%有奖!人气好课免费学,精品课程1分抢!';
}
// 获取app登录数据
loginInfo = (result) => {
this.setState({
userInfoList: result
}, () => {
if (this.state.userInfoList.length) {
this.props.startFetchUser()
this.appLogin()
}
})
}
// 保存cookie
appLogin = () => {
let expires = addDays(new Date(), 90)
this.state.userInfoList.map((item, index) => {
cookie.set("token", item.token, {expires, path: '/', domain: '.julyedu.com'})
cookie.set("plat", item.plat, {expires, path: '/', domain: '.julyedu.com'})
cookie.set("uid", item.uid, {expires, path: '/', domain: '.julyedu.com'})
cookie.set("uname", item.uname, {expires, path: '/', domain: '.julyedu.com'})
cookie.set("avatar_file", item.avatar_file, {expires, path: '/', domain: '.julyedu.com'})
})
if (cookie.get("token") && cookie.get("uid")) {
this.setState({
isAppUpdate: true
})
}
this.props.setCurrentUser(this.transformUser(this.state.userInfoList))
}
transformUser = res => {
let payload
res.map((item, index) => {
payload = {
hasError: false,
data: {
username: item.uname,
avatar: item.avatar_file,
token: item.token,
uid: item.uid
},
isFetching: false
}
})
return payload
}
// 关闭弹框
closePopup = () => {
this.setState({
showMark: false,
})
}
// 获取未拆宝箱数量
getRemovable = (removable, currentOpenId) => {
}
// 获取活动以及宝箱的阶段
getStage = () => {
http.get(`${API.home}/activity/stage`).then(res => {
const {code, data, msg} = res.data
if (code === 200) {
if(Number(data.activity_stage) === 0) {
this.props.history.push('/');
return;
}
// treasure_stage,宝箱阶段,0-不在活动时间,1-活动时间内
this.setState({
activity_stage: data.activity_stage,
treasure_stage: data.treasure_stage
})
if(data.activity_stage == 3){
this.setState({
banner: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_banner_fc.png',
})
} else {
this.setState({
banner: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_banner_bj%402x.png',
})
}
} else {
Toast.info(msg, 2)
}
})
}
render() {
const {
banner,
activity_stage,
treasure_stage,
} = this.state
return (
<div className={'year-index'}>
<div className="banner-treasure">
<div id="banner" className="banner-treasure__header"
style={{backgroundImage: `url(${banner})`}}></div>
<div className="banner-treasure__nav">
<TreasureNav id="banner" treasure_stage={treasure_stage} activeStage={activity_stage}/>
</div>
<div className="banner-treasure__decorate"></div>
</div>
{/* 大咖直播 */}
<LiveRoom isAppUpdate={this.state.isAppUpdate}/>
{/* 组队开宝箱 */}
{
treasure_stage === 1 &&
<TreasureBox isAppUpdate={this.state.isAppUpdate} getRemovable={this.getRemovable}/>
}
{/* 课程 */}
<YearCourse stage={activity_stage} treasureStage={treasure_stage} isAppUpdate={this.state.isAppUpdate} />
{/*好友加入队伍提醒;获得宝箱提醒;开售提醒弹窗,需要自取,注意修改文案*/}
{
this.state.showMark &&
<CommonPopup top={50} closePopup={this.closePopup} mark={true}>
<div className='sub__code_container'>
<p className='sub__title'>提醒服务</p>
<p className='sub__tip'>有好友加入队伍后第一时间通知我~</p>
<img className='sub__qr_code' id={'live-qr-code'}
src='//julyedu-cdn.oss-cn-beijing.aliyuncs.com/2018christyear/h5/qrcode.jpg' alt=""/>
<p className='sub__tip'>长按识别/扫码 关注【七月在线】服务号即可预约</p>
</div>
</CommonPopup>
}
{/*规则弹窗*/}
{
this.state.showMark &&
<CommonPopup top={50} closePopup={this.closePopup} mark={true}>
<div className='sub__code_container'>
<p className='sub__title'>组队开宝箱活动规则</p>
<p className='sub__rule'>
1. 活动期间(1218-1231日)可随时参与开宝箱;<br/>
2. 当前队伍满员后可继续创建新队伍;<br/>
3. 每人有一次机会加入好友的队伍;<br/>
4. 队伍满员后所有成员均可随机获得宝箱内奖品,队长奖励更丰厚哦~<br/>
5. 代金券、课程等虚拟奖品将直接发放至账户,实物奖品活动结束后统一邮寄;<br/>
6. 现金可提现:我的 赚奖学金 提现。
</p>
</div>
</CommonPopup>
}
<div className={'btm-rule'}>* 本活动解释权归北京七月在线科技有限公司所有 *</div>
</div>
)
}
}
.year-index {
padding-bottom: 30px;
background-color: #BC2A18;
.banner-treasure {
}
.banner-treasure__header {
height: 320px;
background-size: cover;
background-position: center;
}
.banner-treasure__nav {
height: 30px;
}
.banner-treasure__decorate {
height: 35px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/m_nv_bj%402x.png');
}
.sub__code_container {
padding: 20px 30px;
text-align: center;
.sub__title {
font-size: 18px;
color: #111;
font-weight: normal;
}
.sub__qr_code {
width: 137px;
height: 137px;
}
.sub__tip {
font-size: 14px;
color: #666;
margin: 13px 0;
letter-spacing: 1px;
i {
font-style: normal;
color: #FF0000;
font-size: 16px;
}
}
.sub__rule {
font-size: 14px;
color: #666;
text-align: left;
margin-top: 20px;
margin-bottom: 5px;
}
}
.btm-rule {
color: #fff;
font-size: 12px;
width: 100%;
text-align: center;
}
}
.year-index + .year19-index {
display: none;
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import { http } from '@/utils';
import './nav.scss';
class TreasureNav extends Component {
constructor(props) {
super(props);
this.state = {
isFixed: false,
curIndex: 0,
formatNavs: [],
navs: [
{
id: 'year-live',
name: '大咖直播'
},
{
id: 'year-treasure',
name: '组队开宝箱'
},
{
id: 'year-course',
name: '重磅好课'
},
{
id: 'year-free',
name: '免费学'
},
{
id: 'year-group',
name: '1分拼团'
},
{
id: 'year-discount',
name: '抄底专区'
},
]
};
}
componentDidMount() {
window.addEventListener('scroll', this.calcNavActive)
}
componentWillUnmount () {
window.removeEventListener('scroll', this.calcNavActive);
}
componentWillReceiveProps(nextProps) {
this.initNav(nextProps.treasure_stage,nextProps.activeStage);
}
initNav = (treasure_stage,activeStage) => {
let {navs} = this.state;
// treasure_stage,宝箱阶段,0-不在活动时间,1-活动时间内
let data = this.state.navs
if(treasure_stage === 0) {
data = navs.filter(item => item.id !== 'year-treasure')
}
if(activeStage === 3) {
data = data.filter(item => item.id !== 'year-free')
}
this.setState({
formatNavs: data
})
}
calcNavActive = () => {
const { formatNavs } = this.state;
const { id } = this.props;
const bannerEl = document.querySelector(`#${id}`);
setTimeout(() => {
let y = window.scrollY,
len = formatNavs.length - 1;
this.setState({
isFixed: y >= bannerEl.offsetHeight
});
for (; len > -1; len--) {
let el = document.querySelector(`#${formatNavs[len].id}`);
if (el && (y + 200) >= el.offsetTop) {
this.setState({
curIndex: len
})
break;
}
}
}, 100);
}
selectToNav = (i) => {
const { formatNavs } = this.state;
const id = `#${formatNavs[i]['id']}`;
let el = document.querySelector(id);
if(el) {
this.setState({
curIndex: i
});
window.scrollTo({
top: el.offsetTop,
left: 0
});
}
}
render() {
const { isFixed, curIndex, formatNavs } = this.state;
return (
<div className={classnames("treasure-nav", {'fixed': isFixed})} data-skip="nav">
{
formatNavs.map((item, index) => (
<a
href={`#${item.id}`}
className={classnames("treasure-nav__item", {'active': index === curIndex})}
key={item.id}
onClick={() => this.selectToNav(index)}
>{item.name}</a>
))
}
</div>
)
}
}
export default TreasureNav;
\ No newline at end of file
.treasure-nav {
&[data-skip="nav"] {
display: flex;
align-items: center;
justify-content: center;
height: 30px;
background-color: #357345;
}
&.fixed {
position: fixed;
top: 0;
width: 100%;
z-index: 999;
}
}
[data-skip="nav"] {
.treasure-nav__item {
flex: 1;
box-sizing: border-box;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 26px;
&.active {
border: 1px solid #090F08;
border-radius: 3px;
color: #090F08;
background-color: #FEE41D;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import { withRouter } from 'react-router-dom';
import CommonContainer from './../common/commonContainer/index';
import TreasureRank from './rank';
import TeamInfo from './team'
import Prizes from "@components/activity/newyear-2019/common/prizes"
import UserBulletScreen from "@components/activity/newyear-2019/common/user-bullet-screen"
class TreasureBox extends Component {
constructor(props) {
super(props);
}
render() {
return (
<CommonContainer id="year-treasure" title={'组队开宝箱'}>
<div style={{
textAlign: 'center',
fontSize: '12px',
color: '#FFDC1E',
marginTop: '10px'
}}>邀请好友组队一起开宝箱,满5人后将随机获得以下奖品~</div>
<Prizes showSystemNotices={true}/>
<UserBulletScreen/>
<TeamInfo isAppUpdate={this.props.isAppUpdate} getRemovable={this.props.getRemovable} />
<TreasureRank history={this.props.history} />
</CommonContainer>
)
}
}
export default withRouter(TreasureBox);
import React, { Component } from 'react';
import { http, getParam, SendMessageToApp } from '@/utils';
import './rank.scss'
class TreasureRank extends Component {
constructor(props) {
super(props);
this.state = {
rank: [],
rankList: [],
isMore: false,
}
}
componentDidMount() {
this.fetchRankInfo();
}
fetchRankInfo = () => {
http.get(`${API.home}/sys/treasure/ranking`).then(res => {
const { code, data } = res.data;
if(code === 200) {
if(JSON.stringify(data) !== '{}') {
if(data.length > 5) {
this.setState({
rank: data.filter((item, index) => index < 5),
rankList: data,
isMore: true,
});
}else {
this.setState({
rank: data,
rankList: data,
isMore: false,
});
}
}
}
});
}
switchMoreRank = () => {
const { rankList, isMore } = this.state;
if(isMore) {
this.setState({
rank: rankList,
isMore: false,
})
}else {
this.setState({
rank: rankList.filter((item, index) => index < 5),
isMore: true,
})
}
}
handleToVip = (id) => {
const { history } = this.props;
if(id) {
if(getParam('version')) {
SendMessageToApp('toCourse', id);
}else {
history.push(`/detail?id=${id}`);
}
}
}
render() {
const { rank, isMore } = this.state;
return (
<>
{
rank.length !== 0 &&
<div data-skip="rank">
<div className="rank-title">
<i className="rank-title__decorate"></i>
<h2 className="rank-title__txt">宝箱达人榜</h2>
<i className="rank-title__decorate"></i>
</div>
<p className="rank-desc">宝箱数量前50名可额外获得一份奖品,数量相同的用时短者排名在前</p>
<dl className="rank-header">
<dd className="rank-column">排名</dd>
<dd className="rank-column">用户</dd>
<dd className="rank-column">宝箱数量</dd>
<dd className="rank-column">奖品</dd>
</dl>
<div className="rank-body">
{
rank.map((item, index) => (
<dl className="rank-item" key={index}>
<dd className="rank-column">
{
index <= 2
? <span className="rank-column__number" data-num={index}></span>
: <span>{index+1}</span>
}
</dd>
<dd className="rank-column">
<span className="rank-column__name">{item.user_name}</span>
</dd>
<dd className="rank-column">
<span>{item.num}</span>
</dd>
<dd className="rank-column">
{
item.url
? <a className="rank-column__txt" onClick={() => this.handleToVip(item.url)}>{item.prize_name}</a>
: <span className="rank-column__txt">{item.prize_name}</span>
}
</dd>
</dl>
))
}
<div className="rank-more" onClick={this.switchMoreRank}>
<span className="rank-more__txt">{isMore? '展开' : '收起'}</span>
<i className="rank-more__icon" data-more={isMore}></i>
</div>
</div>
</div>
}
</>
)
}
}
export default TreasureRank;
\ No newline at end of file
[data-skip="rank"] {
.rank-title {
display: flex;
align-items: center;
justify-content: center;
}
.rank-title__decorate {
display: inline-block;
width: 11px;
height: 12px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-decorate-0.png');
}
.rank-title__txt {
position: relative;
margin: 0 8px;
font-size: 18px;
font-weight: normal;
color: #FFE300;
text-align: center;
line-height: 1;
&::after {
content: '';
position: absolute;
top: -8px;
right: -8px;
width: 14px;
height: 11px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-decorate-1.png');
}
}
.rank-desc {
margin: 7px 0 0;
padding: 0 48px;
font-size: 12px;
color: #FFE300;
text-align: center;
line-height: 16px;
}
.rank-header {
margin: 12px 10px 0;
border-radius: 5px 5px 0 0;
font-size: 0;
overflow: hidden;
.rank-column {
color: #1D5432;
font-size: 12px;
line-height: 30px;
background-color: #FFE300;
}
}
.rank-body {
margin: 0 10px;
border-left: 1px solid #81F3AF;
border-bottom: 1px solid #81F3AF;
border-right: 1px solid #81F3AF;
border-radius: 0 0 5px 5px;
background-color: #1D5432;
}
.rank-item {
border-bottom: 1px solid #0E7442;
.rank-column {
display: inline-flex;
align-items: center;
justify-content: center;
height: 40px;
font-size: 12px;
color: #fff;
}
}
.rank-column {
display: inline-block;
text-align: center;
vertical-align: middle;
&:nth-child(1) {
width: 10%;
}
&:nth-child(2) {
width: 25%;
}
&:nth-child(3) {
width: 20%;
}
&:nth-child(4) {
width: 45%;
}
}
.rank-column__number {
display: inline-block;
width: 11px;
height: 12px;
background-size: cover;
&[data-num="0"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-diyiming.png');
}
&[data-num="1"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-dierming.png');
}
&[data-num="2"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-disanming.png');
}
}
.rank-column__name {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.rank-column__txt {
display: inline-block;
width: 100%;
box-sizing: border-box;
padding: 0 5px;
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
a.rank-column__txt {
text-decoration: underline;
}
.rank-more {
display: flex;
align-items: center;
justify-content: center;
height: 40px;
}
.rank-more__txt {
font-size: 14px;
color: #fff;
}
.rank-more__icon {
width: 11px;
height: 12px;
margin-left: 5px;
background-size: cover;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-arrow-double.png');
&[data-more="false"] {
transform: rotate(180deg);
}
}
}
import React, { Component } from 'react';
import './team.scss'
import { getParam, http, SendMessageToApp } from "@/utils"
import { Toast } from 'antd-mobile';
import {withRouter} from 'react-router-dom';
import {compose} from "redux"
import { connect } from "react-redux";
import jsCookie from 'js-cookie'
class TeamInfo extends Component {
constructor(props) {
super(props);
this.state = {
is_my_team: false, // 是否有自己的队伍
prize_info: [],
info: {
removable: 0,
total: 0
},
member: [],
removable_data: [],
my_team: {},
}
}
componentDidMount() {
this.getTeamInfo();
}
// 获取队伍信息
getTeamInfo = () => {
http.get(`${API.home}/sys/treasure/teamInfo`).then(res => {
const { code, data, msg } = res.data;
if (code === 200) {
const { prize_info, is_my_team, info, member, removable_data, my_team } = data;
this.setState({
prize_info,
is_my_team,
info,
member: this.fillTeam(member, is_my_team),
removable_data,
my_team
})
let currentId = null;
if(info.removable > 0) {
currentId = removable_data[0].id;
}
this.props.getRemovable(info.removable, currentId);
} else {
Toast.info(msg);
}
})
}
// 跳转到我的宝箱页
toYearTreasure = (close) => {
if(this.props.user.hasError) {
this.toLogin();
} else {
let search = '';
if(close) {
const {removable_data, info: {removable}} = this.state;
if(removable > 0) {
let current = removable_data[0];
search = `?id=${current.id}`;
}
}
if (!getParam('version')) {
this.props.history.push(`/year/yearTreasure${search}`);
} else {
this.props.history.push(`/year/yearTreasure${search}?version=${getParam('version')}`);
}
}
}
// 去登录
toLogin = () => {
if (!getParam('version')) {
this.props.history.push('/passport/login')
} else {
SendMessageToApp("toLogin")
}
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if (this.props.isAppUpdate !== nextProps.isAppUpdate) {
this.getTeamInfo();
return false
}
return true
}
// 邀请好友组队
createTeam = () => {
if(this.props.user.hasError) {
this.toLogin();
} else {
sessionStorage.setItem('showShareTip', '1')
const {is_my_team, my_team: {treasure_code}} = this.state;
if(is_my_team) { // 有自己的队伍
// 直接跳转
if (!getParam('version')) {
// this.props.history.push('/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code);
window.location.assign('https://h5.julyedu.com/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code);
} else {
window.location.assign('https://h5.julyedu.com/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code + '&version='+ getParam('version'));
}
}else{ // 没自己的队伍
// 请求创建队伍的接口
http.get(`${API.home}/sys/treasure/createMyTeam`).then(res => {
const { code, data, msg } = res.data;
if (code === 200) {
const { treasure_code } = data;
if (!getParam('version')) {
// this.props.history.push('/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code);
window.location.assign('https://h5.julyedu.com/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code);
} else {
window.location.assign('https://h5.julyedu.com/activity/newyear-2019/landing?origin=1&treasure_code=' + treasure_code + '&version='+ getParam('version'));
}
} else {
Toast.info(msg);
}
});
}
}
}
// 队伍成员信息必须满五个 不满的需要填充
fillTeam = (list, is_my_team) => {
let len = list.length;
// 没有创建队伍 并且没有加入他人队伍
if(this.props.user.hasError) {
for(let i=0;i<5-len;i++) {
list.push({
head_img: '',
user_name: '',
nobody: true,
})
}
} else {
if(len === 0 && !is_my_team) {
list.push({
head_img: jsCookie.get('avatar_file'),
user_name: jsCookie.get('user_name'),
})
for(let i=0;i<4;i++) {
list.push({
head_img: '',
user_name: '',
nobody: true,
})
}
}else{
for(let i=0;i<5-len;i++) {
list.push({
head_img: '',
user_name: '',
nobody: true,
})
}
}
}
return list;
}
render() {
const { prize_info, is_my_team, info: {removable, total}, member } = this.state;
let name = '', stage_no = 0;
if(prize_info.length > 0) {
name = prize_info[0].name;
stage_no = prize_info[0].stage_no;
}
// 显示文案控制
let Text = '';
if(total === 0) {
Text = `我的宝箱`;
} else if (removable === 0) {
Text = `共${total}个宝箱`;
} else {
Text = `共${total}个宝箱/${removable}个未开`;
}
return (
<div className='team_info__container'>
<div className='team__member'>
<ul className='member__list'>
{
member && member.length > 0 && (
member.map((item, index) => {
return <li key={index} className='member__item'>
<div className='avatar__container'>
{
item.nobody ? (
<img className='head__image' src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/default-member-avatar.png" alt=""/>
) : (
<img className='head__image' src={item.head_img} alt=""/>
)
}
{
index === 0 ? (
<img className='caption__flag' src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/caption.png" alt=""/>
) : (null)
}
<div className='shadow'></div>
</div>
<div className={`member__join ${item.nobody ? '' : 'join'}`}></div>
</li>
})
)
}
</ul>
<div className='box__number'>
<img onClick={() => this.toYearTreasure(true)} src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/treasure-box-icon.png" alt="" />
<p onClick={() => this.toYearTreasure(false)} className='box__text'>
{Text}
</p>
<img className='position__arrow' src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/arrow_jinzhan.png" alt=""/>
{
removable > 0 && (
<div className='position__number'>{removable}</div>
)
}
</div>
</div>
<div onClick={this.createTeam} className='invite__btn'>
{
is_my_team ? ('继续组队') : ('组队开宝箱')
}
</div>
{
stage_no > 0 && name && <p className='stage_prize'>{`第${stage_no}个宝箱必中${name}`}</p>
}
</div>
)
}
}
export default compose(
connect(
state => ({user: state.user}),
null
),
withRouter
)(TeamInfo)
.team_info__container {
margin-bottom: 30px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
.team__member {
height: 72px;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 16px;
.member__list {
height: 50px;
width: 224px;
display: flex;
justify-content: flex-start;
align-items: center;
margin-right: 12px;
.member__item {
width: 44px;
height: 50px;
display: flex;
flex-direction: column;
justify-content: space-between;
align-items: center;
margin-left: 1px;
&:first-child {
margin-left: 0;
.member__join {
border-radius: 2px 0 0 2px;
}
}
&:last-child {
.member__join {
border-radius: 0 2px 2px 0;
}
}
.avatar__container {
width: 27px;
height: 27px;
position: relative;
border: 1px solid #fff;
border-radius: 50%;
.head__image {
border-radius: 50%;
width: 100%;
height: 100%;
}
.shadow {
width: 24px;
height: 3px;
background: #1a3528;
border-radius: 50%;
position: absolute;
bottom: -6px;
}
.caption__flag {
position: absolute;
width: 18px;
height: 10px;
left: 50%;
top: 0;
}
}
.member__join {
width: 40px;
height: 5px;
background: rgba(0, 88, 51, 1);
box-shadow: 1px 1px 2px 0px rgba(3, 52, 91, 0.35);
}
.join {
background: rgba(255, 221, 29, 1);
box-shadow: 1px 2px 2px 0px rgba(253, 253, 253, 0.46) inset,
1px 2px 2px 0px rgba(253, 253, 253, 0.46) inset;
}
}
}
.box__number {
width: 108px;
height: 100%;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
position: relative;
img {
width: 92px;
height: 50px;
}
.box__text {
width: 1000px;
font-size: 100px;
transform: scale(0.1);
text-decoration: underline;
color: rgba(255, 227, 0, 1);
position: absolute;
bottom: -72px;
text-align: center;
}
.position__arrow {
width: 18px;
height: 18px;
position: absolute;
left: -7px;
top: 18px;
}
.position__number {
min-width: 22px;
height: 18px;
font-size: 12px;
background: rgba(255, 60, 22, 1);
border: 1px solid rgba(255, 227, 0, 1);
border-radius: 9px 9px 9px 0px;
color: rgba(255, 227, 0, 1);
position: absolute;
display: flex;
justify-content: center;
align-items: center;
padding: 0 5px;
right: -4px;
top: -4px;
}
}
}
.invite__btn {
width: 320px;
height: 44px;
background: rgba(255, 227, 0, 1);
border-radius: 3px;
display: flex;
justify-content: center;
align-items: center;
font-size: 15px;
color: rgba(11, 123, 69, 1);
margin-bottom: 12px;
}
.stage_prize {
font-size: 12px;
line-height: 12px;
color: rgba(255, 227, 0, 1);
text-align: center;
}
}
import React, {Component} from 'react'
import './index.scss'
import {http, SendMessageToApp, getParam} from '@/utils'
import CommonContainer from './../common/commonContainer/index'
import CourseItem from '../../../blessingPreheat/courseItem/index'
import {withRouter} from "react-router-dom"
import { connect } from 'react-redux';
@connect(({user}) => ({
user
}))
class YarnWish extends Component {
state = {
list: [],
activityStage: 1,
}
componentDidMount() {
this.fetchCourse()
this.getStage()
}
componentWillUpdate() {
const {activityStage} = this.state
if (activityStage == 1) {
document.title = `七月在线年终大回馈,人气好课免费学,精品课程1分抢!`
} else {
document.title = `七月在线年终大回馈,人气好课免费学,精品课程1分抢!`
}
}
fetchCourse = () => {
http.get(`${API.home}/activity/wish_course`).then(res => {
const {code, data} = res.data
if (code === 200) {
this.setState({
list: JSON.stringify(data) === '{}' ? [] : data
})
} else if (code === 4030) {
this.props.history.push('/passport/login')
}
})
}
getStage = () => {
http.get(`${API.home}/activity/stage`).then(res => {
const {code, data} = res.data
if (code === 200) {
if(Number(data.activity_stage) === 0) {
this.props.history.push('/');
return;
}
this.setState({
activityStage: data.activity_stage // 0-不在活动时间 1-预热 2-正式 3-返场
})
}
})
}
// 去课程详情页
toCourse = (courseId) => {
const {history} = this.props
if (!getParam('version')) {
history.push(`/detail?id=${courseId}`)
} else {
SendMessageToApp("toCourse", courseId)
}
}
toInviteFriends = (oid, params = {}) => {
const { history } = this.props
if (getParam('version')) {
let data = {
title: `【仅剩${params.number}个名额】我${params.price}元拼了《${params.course_title}》`,
desc: params.course_title,
link: `${API.m}/togroup?id=${oid}`,
imgUrl: params.image_name,
}
SendMessageToApp("toShare", data)
} else {
history.push(`/togroup?id=${oid}`);
}
}
toContinueBargain = (id, price, code, image) => {
const { history } = this.props;
if(getParam('version')) {
let data = {
title: '我发现一门好课,快来帮我砍价吧!',
desc: `我已经砍了${price}元,看看你能砍多少`,
link: `${API.m}/bargain-middle-page?id=${id}&bargaincode=${code}&is_originator=1`,
imgUrl: image,
}
SendMessageToApp("toShare", data)
}else {
history.push(`/bargain-middle-page?id=${id}&bargaincode=${code}&is_originator=1`);
}
}
toCart = (id) => {
const { history } = this.props;
http.post(`${API.home}/m/cart/add`, {
course_id: id
}).then((res) => {
const { code, msg } = res.data;
// code 15001 已加入购物车
if (code === 200 || code === 15001) {
if(getParam('version')) {
SendMessageToApp('toShoppingCart')
}else {
history.push('/shopcart');
}
} else if (code === 4030 || code === 4040) {
this.toLogin();
} else {
Toast.info(msg, 2);
}
})
}
// 砍完价去支付
bargainToOrder = (id) => {
console.log(this.props);
const { history, user } = this.props;
if(user.hasError) {
this.toLogin();
}else{
if(getParam('version')) {
SendMessageToApp('toPay', id)
}else {
http.get(`${API['base-api']}/m/cart/addtopreorder/[${id}]`).then((res) => {
const { errno, msg } = res.data;
if (errno === 0) {
history.push(`/order?id=[${id}]`, {bargain: 1});
} else {
Toast.info(msg, 2);
}
})
}
}
}
render() {
const { list, activityStage } = this.state
console.log(activityStage);
return (
<div className='year-wish'>
<div className="banner">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/xy_banner_bj.png" alt=""/>
</div>
{
list.length > 0
? <>
{
activityStage !== 1 &&
<>
<CommonContainer>
<div className='groupcourse course-box'>
{
list.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
time={item.type === 2 || item.type === 7? item.end_time : ''}
toCourse={this.toCourse}
>
{/*
* 拼团,正常:未开团1 已开2;一分:未开团5 已开7
* type 1 立即参团 2 已参团 3 我要砍价 4 已参加砍价 可以继续砍价 5 马上抢 6 开始学习 7 已参加一分钱拼团 8 砍价待支付
*/}
<div className="coupon-course__footer">
{
(item.type === 4 || item.type === 8) &&
<div className="bargain-price">已砍{item.already_bargain}</div>
}
{
item.type === 0 &&
<>
<div className="type">
<span className="tag" data-color="green">活动价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">{item.original_price}</span>
<span className="old-price">
<s>¥{item.original_price}</s>
</span>
</div>
</>
}
{
(item.type === 1 || item.type === 2) &&
<>
<div className="type">
<span className="tag" data-color="green">拼团价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">{item.pdd_price}</span>
<span className="old-price">
<s>¥{item.original_price}</s>
</span>
</div>
</>
}
{
(item.type === 5 || item.type === 7) &&
<>
<div className="type">
<span className="tag" data-color="green">拼团价</span>
</div>
<div className="price price-group">
<span className="price-label">¥</span>
<span className="new-price">0.01</span>
<span className="old-price">
<s>¥{item.original_price}</s>
</span>
</div>
</>
}
{
(item.type === 3 || item.type === 4 || item.type === 8) &&
<>
<div className="type">
<span className="tag" data-color="green">好友帮帮砍</span>
</div>
<div className="price price-group">
<span className="price-label">到手最低:¥</span>
<span className="new-price">{item.low_prize}</span>
<span className="old-price">
<s>¥{item.original_price}</s>
</span>
</div>
</>
}
{
item.type === 6 &&
<p className={'course-title text-overflow-1'}>
{item.course_title}
</p>
}
<div className="status" data-layout={item.type === 4? 'row' : ''}>
{
item.type === 0 &&
<a
onClick={() => this.toCart(item.course_id)}
className="status-btn to-group"
>立即购买</a>
}
{
item.type === 1 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-group"
>立即参与拼团</a>
}
{
(item.type === 2 || item.type === 7) &&
<a
onClick={() => this.toInviteFriends(item.order_id, {
number: item.number,
course_title: item.course_title,
image_name: item.image_name,
price: item.type === 2? item.pdd_price : 0.01
})}
className="status-btn to-group"
data-status="done"
>已参团,邀请好友参团</a>
}
{
item.type === 3 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-group"
>我要砍价</a>
}
{
item.type === 4 &&
<>
<a
onClick={() => this.toContinueBargain(item.course_id, item.already_bargain, item.bargain_code, item.image_name)}
className="status-btn to-group"
>继续砍价</a>
<a
onClick={() => this.bargainToOrder(item.course_id)}
className="status-btn to-group"
>支付{item.actual_payment}</a>
</>
}
{
item.type === 8 &&
<a
onClick={() => this.bargainToOrder(item.course_id)}
className="status-btn to-group"
>支付{item.actual_payment}</a>
}
{
item.type === 5 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-group"
>马上抢>></a>
}
{
item.type === 6 &&
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-group"
data-status="study"
>开始学习</a>
}
</div>
</div>
</CourseItem>
))
}
</div>
</CommonContainer>
</>
}
{
activityStage === 1 &&
<>
<CommonContainer>
<div className='groupcourse course-box'>
{
list.map(item => (
<CourseItem
image={item.image_name}
key={item.course_id}
id={item.course_id}
toCourse={this.toCourse}
>
{
item.type == 4 && item.is_buy != 1 &&
<div className="group-num">限量300</div>
}
<div className="coupon-course__footer">
{
item.is_buy == 1 &&
<>
<p className={'course-title text-overflow-1'}>{item.course_title}</p>
<a
onClick={() => this.toCourse(item.course_id)}
className="btn to-study"
>开始学习</a>
</>
}
{
item.is_buy == 0 &&
<>
<div className="type">
{
item.type == 0 &&
<>
<span className="tag">活动价</span>
<span className="time">12.23开始</span>
</>
}
{
(item.type == 1 || item.type == 4) &&
<>
<span className="tag">拼团价</span>
<span className="time">12.23开团</span>
</>
}
{
item.type == 2 &&
<>
<span className="tag">好友帮帮砍</span>
<span className="time">12.23开砍</span>
</>
}
</div>
<div className="price">
{item.type == 2 ? '到手最低:¥' : '¥'}
<span
className="new-price">{item.type == 4 ? '0.01' : item.price2}</span>
<span className="old-price">{item.type == 2 ? '' : '现价:'}<s>¥{item.price1}</s></span>
</div>
<div className="status">
<a
onClick={() => this.toCourse(item.course_id)}
className="status-btn to-buy"
>直接购买</a>
{
item.is_join == 1 &&
<a className="status-btn add-wish">
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/add-success.png"
alt=""
/>
已加心愿单
</a>
}
{
item.is_join == 0 &&
<a
onClick={() => this.addWishList(item.course_id)}
className="status-btn add-wish-success"
>
<img
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/like_icon.png"
alt=""
/>
加入心愿单
</a>
}
</div>
</>
}
</div>
</CourseItem>
))
}
</div>
</CommonContainer>
</>
}
</>
: (
<div className="notData">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/PC/icon-empty.png" alt=""/>
{
activityStage == 1
? <p>你的心愿单目前空空如也,<br/>快去挑选更多优惠课程吧~</p>
: <p>你的心愿单没有课程哦,<br/>感兴趣的课程可在双旦主会场直接购买!</p>
}
</div>
)
}
</div>
)
}
}
export default withRouter(YarnWish)
html, body, #root {
height: 100%;
}
.year-wish {
min-height: 100%;
background-color: #BA2C21;
padding-bottom: 35px;
.banner {
width: 100%;
margin-bottom: 30px;
}
.course-box {
display: flex;
justify-content: space-between;
flex-wrap: wrap;
.course-container {
width: 168px;
margin: 15px 0 0 0;
text-align: center;
position: relative;
}
.group-num {
width: 66px;
height: 16px;
position: absolute;
left: 10px;
top: 10px;
line-height: 16px;
background: #CA161C;
opacity: 0.8;
border-radius: 1px;
font-size: 12px;
color: #fff;
text-align: center;
}
.bargain-price {
position: absolute;
left: 4px;
top: 10px;
margin: 0;
height: 18px;
padding: 0 8px;
border-radius: 0 9px 9px 0;
font-size: 12px;
color: #fff;
line-height: 18px;
background-color: #F01D0E;
}
.coupon-course__footer {
.course-title {
padding-left: 10px;
font-size: 15px;
color: #333;
font-weight: 500;
margin-top: 7px;
}
.btn {
display: inline-block;
width: 138px;
height: 24px;
text-align: center;
line-height: 24px;
border-radius: 2px;
font-size: 12px;
outline: none;
border: none;
letter-spacing: 1px;
}
.big-course {
background-color: #FEE41D;
border: 1px solid #090F08;
color: #090F08;
margin-top: 10px;
}
.to-study {
background-color: #09f;
color: #fff;
position: absolute;
left: 10px;
bottom: 10px;
}
.free-study {
background: linear-gradient(-90deg, #EB1612 0%, #F92927 100%);
color: #fff;
margin-top: 10px;
}
.free-course-num {
font-size: 12px;
color: #070F08;
margin-top: 7px;
letter-spacing: 1px;
span {
font-size: 14px;
color: #FF0002;
}
}
}
.type {
text-align: left;
padding-left: 7px;
margin-top: 3px;
.tag {
display: inline-block;
padding: 0 6px;
height: 14px;
line-height: 15px;
text-align: center;
font-size: 12px;
color: #FFF;
position: relative;
z-index: 0;
}
.time {
display: inline-block;
height: 15px;
line-height: 15px;
padding: 0 6px;
margin-left: 5px;
position: relative;
font-size: 12px;
color: #555;
text-align: center;
z-index: 0;
}
.time:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #E6E6E6;
transform: skewX(-20deg);
z-index: -1;
}
.tag:before {
content: '';
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-color: #FF0002;
transform: skewX(-20deg);
z-index: -1;
}
.tag[data-color="green"]:before {
background-color: #357345;
}
}
.price {
margin-top: 3px;
padding-left: 4px;
font-size: 12;
color: #FF0002;
text-align: left;
&.price-group {
font-size: 0;
height: 30px;
}
.price-label {
font-size: 12px;
}
.new-price {
font-size: 16px;
}
.old-price {
margin-left: 2px;
font-size: 12px;
color: #666;
}
}
.status {
position: absolute;
left: 0;
bottom: 10px;
right: 0;
padding: 0 5px;
text-align: left;
&[data-layout="row"] {
display: flex;
.to-group {
font-size: 12px;
&:nth-child(1) {
margin-right: 2px;
}
&:nth-child(2) {
margin-left: 2px;
}
}
}
.status-btn {
display: inline-block;
height: 22px;
line-height: 22px;
border-radius: 2px;
text-align: center;
font-size: 12px;
color: #fff;
}
.to-buy {
width: 148px;
background-color: #FF8080;
}
.to-group {
display: block;
width: 100%;
height: 22px;
border-radius: 11px;
box-sizing: border-box;
font-size: 14px;
color: #fff;
text-align: center;
line-height: 22px;
background: linear-gradient(-90deg,rgba(235,22,18,1) 0%,rgba(255,0,2,1) 100%);
&[data-status="study"] {
background: #0099FF;
}
&[data-status="done"] {
border: 1px solid #090F08;
font-size: 12px;
color: #090F08;
background: #FEE41D;
}
}
}
}
.groupcourse .course-container {
height: 195px;
}
.notData {
margin: 100px auto 0;
text-align: center;
img {
width: 56px;
height: 49px;
}
p{
font-size: 16px;
color: #fff;
margin-top: 20px;
}
}
}
.year-wish + .year19-index {
display: none;
}
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -68,7 +68,7 @@ class BargainMiddlePage extends Component {
// 获取砍价信息
getBargainInfo = () => {
// is_originator 来源,0-PC端扫码 1-M端分享 2-APP端分享
http.get(`${API.home}/m/bargain/info?bargaincode=${getParam('bargaincode')}&is_originator=${getParam('is_originator')}`).then((res) => {
if (res.data.code === 200) {
this.setState(
......@@ -153,11 +153,15 @@ class BargainMiddlePage extends Component {
// 直接支付
toCart = () => {
http.get(`${API['base-api']}/m/cart/addtopreorder/[${getParam('id')}]`).then((res) => {
if (res.data.errno === 0) {
const { history } = this.props;
http.get(`${API['base-api']}/m/cart/addtopreorder/[${getParam('id')}]`).then((res) =>{
const { errno, msg } = res.data;
if (errno === 0) {
this.props.history.push(`/order?id=[${getParam('id')}]`, {bargain: 1});
}else if(errno === 4030 || errno === 4040) {
history.push('/passport');
} else {
Toast.info(res.data.msg, 2);
Toast.info(msg, 2);
}
})
// let data = {
......@@ -204,19 +208,23 @@ class BargainMiddlePage extends Component {
// 领取砍价神器
toArtifact = () => {
const { history } = this.props;
const { course: { course_id = '' } } = this.state;
let data = {
courseId: getParam('id')? getParam('id') : course_id
}
http.post(`${API.home}/m/bargain/receiveLimit`, data).then((res) => {
if (res.data.code === 200) {
const { code, msg } = res.data;
if (code === 200) {
this.setState({
isShowOverlay: true,
status: 5,
});
this.getBargainInfo();
}else if(code === 4030 || code === 4040) {
history.push('/passport');
} else {
Toast.info(res.data.msg, 2)
Toast.info(msg, 2)
}
})
}
......@@ -322,6 +330,8 @@ class BargainMiddlePage extends Component {
// 邀请好友砍价
shareFriendBargain = () => {
const { history } = this.props;
history.push(`/bargain-middle-page?id=${getParam('id')}&bargaincode=${getParam('bargaincode')}&is_originator=1`);
this.setState({
isShowOverlay: true,
status: 7,
......@@ -634,7 +644,7 @@ function CourseDes(props) {
<span className={'discount-price'}>{course.course_price}</span>
{/* is_originator 是否发起人 0-否 1-是 */}
{
(is_originator == 1 && bargain_status == 0 || bargain_status == 1) &&
(is_originator == 1 && bargain_status !=3) &&
<button className={'purchase-btn'} onClick={toCart}>
¥{course.pay_price}去支付
</button>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -2,11 +2,54 @@ import React, { Component } from 'react';
import './index.scss';
class CourseItem extends Component {
constructor(props) {
super(props);
this.state = {
countdown: ''
}
}
componentDidMount() {
const { time } = this.props;
this.startCountDown(time);
}
componentWillReceiveProps(nextProps) {
const { time: newTime } = nextProps
const { time: oldTime } = this.props;
if(oldTime != newTime) {
this.startCountDown(newTime);
}
}
startCountDown = (time) => {
if(time) {
let date = time * 1000,
hours = 0,
minutes = 0,
seconds = 0;
setInterval(() => {
date -= 1000
hours = `${parseInt(date / (60 * 60 * 1000))}`.padStart(2, 0);
minutes = `${parseInt((date - hours * 3600000) / 60000)}`.padStart(2, 0);
seconds = `${parseInt((date - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0);
this.setState({
countdown: `${hours}${minutes}${seconds}秒后结束`
});
}, 1000);
}
}
render() {
const { image,toCourse,id} = this.props;
const { image, toCourse, id} = this.props;
const { countdown } = this.state;
return (
<div className="course-container">
<div className="course__cover">
{
countdown &&
<p className="course__time">{countdown}</p>
}
<img src={image} alt="cover" onClick={() => toCourse(id)}/>
</div>
{this.props.children}
......
......@@ -7,6 +7,7 @@
}
.course__cover {
position: relative;
height: 108px;
padding: 4px 4px 0;
overflow: hidden;
......@@ -18,3 +19,17 @@
height: 100%;
}
}
.course__time {
position: absolute;
left: 4px;
top: 10px;
margin: 0;
height: 18px;
padding: 0 8px;
border-radius: 0 9px 9px 0;
font-size: 12px;
color: #fff;
line-height: 18px;
background-color: #F01D0E;
}
\ No newline at end of file
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -68,7 +68,8 @@ class Coupon extends PureComponent {
id,
format_expire_time,
start_amount,
limit_amount
limit_amount,
limit_course
} = this.props
let top, bottom
......@@ -84,7 +85,7 @@ class Coupon extends PureComponent {
)
bottom = (
<>
<span className={'limit'}>可用于大于代金券金额的课程</span>
<span className={'limit'}>{limit_course == 0 ? '可用于大于代金券金额的课程': `仅适用于《${course_title}》`}</span>
{
showUseButton && ctype == this.VOUCHER &&
<button
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -79,7 +79,7 @@ class UseCoupon extends PureComponent {
}
}
if (state.from === '/order') {
const coupon = data.data
/*const coupon = data.data
if (coupon['ctype'] == 2
&& coupon['limit_course'] != this.state.courseId) {
......@@ -93,7 +93,7 @@ class UseCoupon extends PureComponent {
valid_coupons: [...this.state.valid_coupons, coupon],
redeemCode: ''
})
}
}*/
Toast.info('兑换成功')
this.getAllCoupons()
}
......@@ -143,7 +143,7 @@ class UseCoupon extends PureComponent {
const [expansionCoupons, selectCoupons] = coupons
const {data: select} = selectCoupons
const {data: expansion} = expansionCoupons
let PzCoupon = this.state.valid_coupons.concat(expansion.data)
let PzCoupon = Array.isArray(expansion.data) ? expansion.data : []
if (expansion.code == 200) {
Array.isArray(expansion.data)
&& (expansion.data = expansion.data.map(item => (item.ctype = 4, item)))
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -372,12 +372,7 @@
}
.artifact-box, .use-artifact-box {
padding: 20px 0;
background-color: $bg_fff;
border-radius: 3px;
text-align: center;
margin: 200px auto 20px auto;
position: relative;
.top-img {
position: absolute;
......
import React, {Component} from 'react';
import {InputItem, List} from "antd-mobile";
import './bargain-info.scss'
import {validateTel} from "@/utils";
import {Toast} from 'antd-mobile'
import { http, getParam } from "@/utils";
import {Link} from "react-router-dom";
import classnames from 'classnames';
class BargainInfo extends Component {
state = {
mobile: '',
code: '',
num: '86',
isBargain: true,
isFocus: false,
bindInfo: {},
isTip: false,
seconds: 60,
isTimer: false, // 是否开始倒计时
}
handleChange = e => {
let {name, value} = e.target
this.setState({
[name]: value
})
}
// 获取短信验证码
sendCode = () => {
const { country } = this.props;
let { mobile, isTimer, seconds } = this.state;
if(!isTimer) {
if(!/^\d+$/.test(mobile)){
Toast.info('请输入正确的手机号');
return;
}
// 获取验证码
http.post(
`${API['passport-api']}/m/personal/bindPhoneSendCode`,
{
area_code: `00${country}`,
phone_num: mobile
}
).then(res => {
const { errno, msg } = res.data;
if(errno === 200) {
Toast.info('验证码发送成功', 2, null, false);
// 倒计时
this.timer = window.setInterval(() => {
console.log(seconds);
if (seconds <= 0) {
window.clearInterval(this.timer);
this.setState({
isTimer: false,
seconds: 60
});
}else {
this.setState({
isTimer: true,
seconds: --seconds
});
}
}, 1000);
}else {
Toast.info(msg);
}
});
}
// http.post(`${API['base-api']}/sys/bind_send_sms`, {
// phone_num: this.state.mobile
// }).then(res => {
// if (res.data.code == 200) {
// Toast.info('验证码发送成功', 2, null, false)
// } else if (res.data.errno === 410) {
// Toast.info('该手机号已注册,请使用该手机号登录,发起砍价。', 3, null, false)
// this.setState({
// isBargain: false
// })
// } else {
// Toast.info(res.data.msg)
// }
// })
}
// 绑定手机号
handleClick = (isValid = 1) => {
const { country, iWantBargain } = this.props;
const { code, mobile } = this.state;
if (!mobile) {
Toast.info('请填手机号码');
return;
}
if (!code) {
Toast.info('请填写验证码');
return;
}
// is_valid 是否验证 1:验证(默认),0不验证
http.post(
`${API['passport-api']}/m/personal/bindPhone`,
{
area_code: `00${country}`,
phone_num: mobile,
code: code,
type: 1,
is_valid: isValid
}
).then(res => {
const { errno, data, msg } = res.data;
if(errno === 200) {
if(isValid) {
if(data.tip_info) {
this.setState({
isTip: true,
bindInfo: data.tip_info
})
}else {
iWantBargain();
}
}else {
iWantBargain();
}
}else {
Toast.info(msg);
}
});
// http.post(`${API.home}/m/user/bindMobile`, {
// ...this.state
// }).then(res => {
// if (res.data.code == 200) {
// Toast.info('绑定手机号成功', 2, null, false)
// this.props.iWantBargain()
// } else {
// Toast.info(res.data.msg)
// }
// })
}
render() {
const { country, toClose } = this.props;
const { mobile, code, isBargain, isFocus, bindInfo, isTip, isTimer, seconds } = this.state;
const bool = /^\d+$/.test(mobile);
return (
<>
{/* 该手机号已绑定其他帐号 */}
{
isTip &&
<div className="popup-bind popup-bind--bargain">
<div className="popup-bind__content">
<h4 className="popup-bind__title">绑定确认</h4>
<p className="popup-bind__desc">该手机号已绑定到以下账号,继续绑定将解除以下绑定状态</p>
<ul className="popup-bind__list">
{
bindInfo['email'] &&
<li className="popup-bind__account">
{/* 邮箱 */}
<i className="iconfont iconduanxin"></i>
<p className="popup-bind__account--name">{bindInfo['email']}</p>
</li>
}
{
bindInfo['wechat_nickname'] &&
<li className="popup-bind__account">
{/* wechat */}
<i className="icon-wachat"></i>
<p className="popup-bind__account--name">{bindInfo['wechat_nickname']}</p>
</li>
}
{
bindInfo['qq_nickname'] &&
<li className="popup-bind__account">
{/* qq */}
<i className="icon-qq"></i>
<p className="popup-bind__account--name">{bindInfo['qq_nickname']}</p>
</li>
}
{
bindInfo['sina_nickname'] &&
<li className="popup-bind__account">
{/* 微博 */}
<i className="icon-sina"></i>
<p className="popup-bind__account--name">{bindInfo['sina_nickname']}</p>
</li>
}
</ul>
<div className="popup-bind__button">
<button
className="popup-bind__button--cancle"
onClick={toClose}>取消</button>
<button
className="popup-bind__button--confirm"
onClick={() => this.handleClick(0)}>继续绑定</button>
</div>
</div>
</div>
}
{
!isTip &&
<div className="bargain-phone-popup">
<h2 className="bargain-phone-popup__title">绑定手机,先砍一刀</h2>
<div
className={classnames(
"bargain-phone-popup__item",
{
'active': isFocus
}
)}
>
<Link
className="bargain-phone-popup__button--num"
to={`/country?id=${getParam('id')}&from=bargain`}
>
+{country}
<i className="iconfont iconiconfront-69"></i>
</Link>
<input
className="bargain-phone-popup__ipt"
type="tel"
onChange={this.handleChange}
onFocus={() => {
this.setState({
isFocus: true
});
}}
onBlur={() => {
this.setState({
isFocus: false
});
}}
name='mobile'
placeholder='手机号'
maxLength={11}
/>
</div>
<div className="bargain-phone-popup__item">
<input
type="tel"
id='code'
onChange={this.handleChange}
name='code'
placeholder='验证码'
maxLength={6}
/>
<button
type="button"
className={classnames(
'bargain-phone-popup__button--send',
{
'active': bool
}
)}
onClick={this.sendCode}
>
{isTimer? `重新发送${seconds}s` : '发送验证码'}
</button>
</div>
{
isBargain
? (
<button
type="button"
onClick={() => this.handleClick()}
className={classnames(
'bargain-phone-popup__button--bargain',
{
'active': bool && code
}
)}
>先砍一刀</button>
)
: (
<Link
className='bargain-phone-popup__button--bargain active'
to={`/passport/login`}
>去登录</Link>
)
}
</div>
}
</>
);
}
}
export default BargainInfo;
\ No newline at end of file
File mode changed from 100644 to 100755
import React, { Component, useState } from 'react'
import './bargain.scss'
import { Flex, Toast } from "antd-mobile"
import Overlay from '../overlay'
import BargainInfo from './bargainInfo'
import {differenceInSeconds, differenceInMinutes, differenceInHours, differenceInDays} from "date-fns"
import { api, getParam, http } from "@/utils"
import { getParam, http } from "@/utils"
import Ranking from "@/components/bargainMiddlePage/ranking"
import { compose } from "redux"
import { withRouter } from 'react-router-dom'
import {connect} from "react-redux";
import { Object } from 'core-js'
import { connect } from "react-redux";
import Mask from '@/common/Mask/index';
import BargainBindPhone from './../bindPhone/index';
import BargainConfirmBind from './../bindPhone/confirm';
class Bargain extends Component {
constructor(props) {
super(props)
this.state = {
isShowOverlay: false,
kanjiaIcon: require('./image/kanjia_icon.png'),
info: '',
outList: [],
list: [],
limitPeople: '',
status: '',
bargainCode: '',
time: '',
barInfo: {},
country: '86',
price: 0, // 每次砍价砍掉的价格
sum: 0 // 累计砍掉的价格
sum: 0, // 累计砍掉的价格,
bindInfo: {}, // 冲突信息
formInfo: {}
}
}
......@@ -43,7 +41,6 @@ class Bargain extends Component {
if(country.from && country.from === 'bargain') {
this.setState({
country: country.num,
isShowOverlay: true,
status: 3,
});
......@@ -66,7 +63,6 @@ class Bargain extends Component {
})
}
//获取砍价信息
getBargainInfo = (isFetch = true) => {
let data = {
......@@ -77,9 +73,6 @@ class Bargain extends Component {
if (code === 200) {
this.setState({
barInfo: data,
// info: res.data.data,
// limitPeople: res.data.data.limit_people,
// bargainCode: res.data.data.bargain_code
});
if(isFetch) {
// 砍价状态 0-砍价中,1砍价结束,待支付,2砍价过期(没有砍价记录没有砍价信息),3已购买
......@@ -116,7 +109,6 @@ class Bargain extends Component {
http.post(`${API.home}/m/bargain/receiveLimit`, data).then((res) => {
if (res.data.code === 200) {
this.setState({
isShowOverlay: true,
status: 1
});
this.getBargainInfo(false);
......@@ -144,11 +136,13 @@ class Bargain extends Component {
}
})
}
// 继续砍价
continueBargain = () => {
const { history } = this.props;
const { barInfo = {} } = this.state;
const code = barInfo.bargain_code;
this.props.history.push(`/bargain-middle-page?id=${getParam('id')}&bargaincode=${code}&is_originator=1`)
history.push(`/bargain-middle-page?id=${getParam('id')}&bargaincode=${code}&is_originator=1`)
}
// 我要砍价
......@@ -177,13 +171,11 @@ class Bargain extends Component {
// user_status 用户状态 1-关注公众号,2-绑定手机号 3-再砍一刀 (是发起人没有这个字段)
if(data.user_status === 2) {
this.setState({
isShowOverlay: true,
status: 3,
});
}else {
if(type === 2) {
this.setState({
isShowOverlay: true,
status: 2,
price: data.amount,
sum: data.bargain_price
......@@ -197,40 +189,41 @@ class Bargain extends Component {
history.push(`/bargain-middle-page?id=${getParam('id')}&bargaincode=${data.bargain_code}&is_originator=1`)
}
}
// if (type === 2) {
// this.setState({
// isShowOverlay: true,
// status: 2,
// })
// } else {
// // user_status 用户状态 1-关注公众号,2-绑定手机号 3-再砍一刀 (是发起人没有这个字段)
// if (data.user_status === 2) {
// this.setState({
// isShowOverlay: true,
// status: 3,
// })
// } else {
// history.push(`/bargain-middle-page?id=${getParam('id')}&bargaincode=${data.bargain_code}&is_originator=1`)
// }
// }
} else {
Toast.info(res.data.msg, 2)
}
})
}
// 关闭弹窗
close = () => {
handleToHide = () => {
this.setState({
isShowOverlay: false,
status: '',
})
status: ''
});
}
// 绑定手机号--确认
confirmBindPhone = (params, bindInfo) => {
this.setState({
status: 4,
formInfo: params,
bindInfo
});
}
render() {
const { list, outList, barInfo, country, price, sum } = this.state;
const {user} = this.props
const {
list,
outList,
barInfo,
country,
price,
sum,
status,
formInfo,
bindInfo
} = this.state;
const { user } = this.props
const uid = user && user.data && user.data.uid
return (
<div className={'bargain-func'}>
......@@ -238,7 +231,10 @@ class Bargain extends Component {
{/*bargain_status 砍价状态 0-砍价中,1砍价结束,待支付,2砍价过期(没有砍价记录没有砍价信息),3已购买*/}
{
(barInfo.bargain_status === 2 || (getParam('id') === '139' && barInfo.bargain_status === 3) || !uid) &&
<BargainIntro limitPeople={barInfo.limit_people} iWantBargain={this.iWantBargain}/>
<BargainIntro
limitPeople={barInfo.limit_people}
iWantBargain={this.iWantBargain}
/>
}
{
(barInfo.bargain_status === 0 || barInfo.bargain_status === 1) && uid &&
......@@ -252,43 +248,39 @@ class Bargain extends Component {
/>
}
{/* 绑定手机号 */}
<Mask visible={status === 3} handleToHide={this.handleToHide}>
<BargainBindPhone
country={country}
handleToBargain={this.iWantBargain}
confirmBindPhone={this.confirmBindPhone}
/>
</Mask>
{/* 绑定手机号--确认 */}
<Mask visible={status === 4} handleToHide={this.handleToHide}>
<BargainConfirmBind
data={formInfo}
bindInfo={bindInfo}
handleToBargain={this.iWantBargain}
/>
</Mask>
{
this.state.isShowOverlay &&
<Overlay>
{/*绑定手机号*/}
{
this.state.status === 3 &&
<BargainInfo country={country} iWantBargain={this.iWantBargain} toClose={this.close} />
}
{/* 领取砍价神器 */}
<Mask visible={status === 1} handleToHide={this.handleToHide}>
<Artifact useArtifact={this.useArtifact} />
</Mask>
{/*领取砍价神器*/}
{
this.state.status === 1 &&
<Artifact useArtifact={this.useArtifact}/>
}
{/*使用砍价神器*/}
{
this.state.status === 2 &&
{/* 使用砍价神器 */}
<Mask visible={status === 2} handleToHide={this.handleToHide}>
<UseArtifact
price={price}
sum={sum}
toCart={this.toCart}
/>
}
{
this.state.status !== 0 &&
<i onClick={this.close} className={'iconfont iconiconfront-2 bargain-close'}></i>
}
</Overlay>
}
</Mask>
{/*更多好友砍价*/}
{/* 更多好友砍价 */}
<Ranking
list={list}
icon={this.state.kanjiaIcon}
......@@ -296,17 +288,21 @@ class Bargain extends Component {
isShowMore={this.state.isShowMore}
boxHide={this.boxHide}
/>
</div>
)
}
}
// 是砍价课程时,展示砍价按钮
function BargainIntro(props) {
return (
<div className="intro-outer">
<div className="intro-inner">
<Flex direction={'column'} justify={'center'} className={'intro-wrapper'}>
<Flex
direction={'column'}
justify={'center'}
className={'intro-wrapper'}
>
<p>
邀请
<span className={'indicator'}>{props.limitPeople}</span>
......@@ -428,10 +424,7 @@ function BargainStatus(props) {
)
}
{/*领取砍价神器*/
}
// 领取砍价神器
function Artifact(props) {
return (
<div className='artifact-box'>
......@@ -446,26 +439,28 @@ function Artifact(props) {
)
}
// 使用砍价神器
function UseArtifact(props) {
const { sum, price } = props;
return (
<div className='use-artifact-box'>
<img className='top-img' src={require('./image/kanjia_cg_icon.png')} alt=""/>
<img
className='top-img'
src={require('./image/kanjia_cg_icon.png')}
alt=""
/>
<p className='top-tip'>厉害了,又砍掉了{price}元!</p>
<p className='middle-tip'>
你已经砍了
<span className={'indicator'}>{sum}</span>
没见过你这么能砍的人...
</p>
<p className='btm-tip'>
不能再砍了哦~
</p>
<p className='btm-tip'>不能再砍了哦~</p>
<button className='tubuy' onClick={props.toCart}>去支付</button>
</div>
)
}
export default compose(
connect(
state => ({
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
import React, { Component } from 'react';
import { Toast } from 'antd-mobile';
import { http } from '@/utils';
import './confirm.scss';
class BargainConfirmBind extends Component {
farmatKey = (key) => {
let data = null;
switch (key) {
case 1:
data = {
key: 'email',
type: 'email'
};
break;
case 2:
data = {
key: 'wechat_nickname',
type: 'wechat'
};
break;
case 3:
data = {
key: 'qq_nickname',
type: 'qq'
};
break;
case 4:
data = {
key: 'sina_nickname',
type: 'sina'
};
break;
default:
data = null;
break;
}
return data;
}
confirmBindPhone = () => {
const { data, handleToBargain } = this.props;
// is_valid 是否验证 1:验证(默认),0不验证
http.post(
`${API['passport-api']}/m/personal/bindPhone`,
{
...data,
type: 1,
is_valid: 0
}
).then(res => {
const { errno, msg } = res.data;
if(errno === 200) {
handleToBargain();
}else {
Toast.info(msg);
}
});
}
render() {
const { bindInfo, handleToHide } = this.props;
return (
<div className="bargain-bind-confirm">
<h4 className="bargain-bind-confirm__title">绑定确认</h4>
<p className="bargain-bind-confirm__desc">该手机号已绑定到以下账号,继续绑定将解除以下绑定状态</p>
<ul className="bargain-bind-confirm__list">
{
bindInfo && [1,2,3,4].map(item => {
const data = this.farmatKey(item);
if(bindInfo[data.key]) {
return (
<li className="bargain-bind-confirm__account" key={item}>
<i className="bargain-bind-confirm__icon" data-plat={data.type}></i>
<p className="bargain-bind-confirm__name">{bindInfo[data.key]}</p>
</li>
);
}
return null;
})
}
</ul>
<div className="bargain-bind-confirm__footer">
<button
className="bargain-bind-confirm__button"
data-type="cancle"
onClick={handleToHide}
>取消</button>
<button
className="bargain-bind-confirm__button"
data-type="confirm"
onClick={this.confirmBindPhone}
>继续绑定</button>
</div>
</div>
)
}
}
export default BargainConfirmBind;
\ No newline at end of file
.bargain-bind-confirm {
width: 290px;
padding-top: 10px;
padding-bottom: 8px;
}
.bargain-bind-confirm__title {
margin: 0 0 12px;
font-size: 15px;
color: #333;
text-align: center;
line-height: 1;
}
.bargain-bind-confirm__desc {
margin: 0;
padding: 0 20px;
font-size: 12px;
color: #666;
}
.bargain-bind-confirm__list {
padding: 0 0 10px;
}
.bargain-bind-confirm__account {
display: flex;
align-items: center;
height: 30px;
margin: 0 52px;
padding: 0 4px;
text-align: left;
&:nth-child(n+2) {
border-top: 1px solid #E5E5E5;
}
}
.bargain-bind-confirm__icon {
display: inline-block;
width: 22px;
height: 22px;
background-size: 100% auto;
background-repeat: no-repeat;
background-position: center;
&[data-plat="email"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-mail.png');
}
&[data-plat="sina"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-sina.png');
}
&[data-plat="qq"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-qq.png');
}
&[data-plat="wechat"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/newyear20/H5/icon-wechat.png');
}
}
.bargain-bind-confirm__name {
margin: 0;
padding-left: 7px;
font-size: 12px;
color: #999;
}
.bargain-bind-confirm__footer {
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 28px;
}
.bargain-bind-confirm__button {
width: 105px;
height: 30px;
box-sizing: border-box;
border-radius: 15px;
font-size: 14px;
cursor: pointer;
outline: none;
&[data-type="cancle"] {
border: 1px solid #0099FF;
color: #0099FF;
background-color: transparent;
}
&[data-type="confirm"] {
border-style: none;
color: #fff;
background-color: #0099FF;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import { Link } from 'react-router-dom';
import { Formik, Form, Field } from 'formik';
import { Toast } from 'antd-mobile';
import { http, getParam } from '@/utils';
import './index.scss';
class BargainBindPhone extends Component {
constructor(props) {
super(props);
this.state = {
mobile: '',
code: '',
num: '86',
seconds: 60,
isTimer: false, // 是否开始倒计时
};
}
// 获取短信验证码
handleToSendCode = ({ mobile }) => {
const { country: { num = 86 } } = this.props;
let { isTimer, seconds } = this.state;
if(!isTimer) {
if(!/^\d+$/.test(mobile)){
Toast.info('请输入正确的手机号');
return;
}
// 获取验证码
http.post(
`${API['passport-api']}/m/personal/bindPhoneSendCode`,
{
area_code: `00${num}`,
phone_num: mobile
}
).then(res => {
const { errno, msg } = res.data;
if(errno === 200) {
Toast.info('验证码发送成功', 2, null, false);
// 倒计时
this.timer = window.setInterval(() => {
if (seconds <= 0) {
window.clearInterval(this.timer);
this.setState({
isTimer: false,
seconds: 60
});
}else {
this.setState({
isTimer: true,
seconds: --seconds
});
}
}, 1000);
}else {
Toast.info(msg);
}
});
}
}
// 绑定手机号
handleToBindPhone = ({code, mobile}) => {
const { country: { num = 86}, handleToBargain, confirmBindPhone } = this.props;
if (!mobile) {
Toast.info('请填手机号码');
return;
}
if (!code) {
Toast.info('请填写验证码');
return;
}
const params = {
area_code: `00${num}`,
phone_num: mobile,
code: code,
};
// is_valid 是否验证 1:验证(默认),0不验证
http.post(
`${API['passport-api']}/m/personal/bindPhone`,
{
...params,
type: 1,
is_valid: 1
}
).then(res => {
const { errno, data, msg } = res.data;
if(errno === 200) {
if(data.tip_info) {
confirmBindPhone(params, data.tip_info);
}else {
handleToBargain();
}
}else {
Toast.info(msg);
}
});
}
render() {
const { country: { num = '86' } } = this.props;
const { isTimer, seconds } = this.state;
return (
<Formik
initialValues={{
mobile: '',
code: ''
}}
validate={({mobile, code}) => {
const errors = {};
if(!/^\d+$/.test(mobile)) {
errors.mobile = '请填写正确格式的手机号';
}
if (!/[0-9]{6}/.test(code)) {
errors.code = '请输入验证码';
}
return errors;
}}
onSubmit={(values, { setStatus, setSubmitting }) => {
this.handleToBindPhone(values);
}}
render={({values: {mobile, code}, errors}) => (
<Form className="bargain-bind-phone">
<h2 className="bargain-bind-phone__title">绑定手机,先砍一刀</h2>
<div className="bargain-bind-phone__item">
<Link
className="bargain-bind-phone__button--num"
to={`/country?id=${getParam('id')}&from=bargain`}
>
+{num}
<i className="iconfont iconiconfront-69"></i>
</Link>
<Field
name="mobile"
render={({field}) => (
<input
{...field}
className="bargain-bind-phone__ipt"
type="tel"
placeholder='手机号'
maxLength={11}
/>
)}
/>
</div>
<div className="bargain-bind-phone__item">
<Field
name="code"
render={({field}) => (
<input
{...field}
type="tel"
placeholder='验证码'
maxLength={6}
/>
)}
/>
{errors.mobile}
<button
type="button"
className={classnames(
'bargain-bind-phone__button--send',
{
'active': mobile && errors.mobile === undefined
}
)}
disabled={!(mobile && errors.mobile === undefined)}
onClick={() => this.handleToSendCode({mobile})}
>
{isTimer? `重新发送${seconds}s` : '发送验证码'}
</button>
</div>
<button
type="submit"
className="bargain-bind-phone__button--bargain"
disabled={!(mobile && code && JSON.stringify(errors) === '{}')}
>先砍一刀</button>
</Form>
)}
/>
)
}
}
export default BargainBindPhone;
\ No newline at end of file
.bargain-phone-popup {
width: 300px;
height: 195px;
margin: 200px auto 20px;
padding: 20px;
border-radius: 3px;
background-color: $white;
.bargain-bind-phone {
padding: 10px 20px;
}
.bargain-phone-popup__title {
.bargain-bind-phone__title {
margin: 0 0 12px;
font-size: 15px;
color: #333;
font-weight: normal;
text-align: center;
line-height: 1;
}
.bargain-phone-popup__item {
.bargain-bind-phone__item {
display: flex;
align-items: center;
width: 100%;
......@@ -24,11 +20,6 @@
border: 1px solid #ddd;
box-sizing: border-box;
&.active {
border: 1px solid $active;
color: $active;
}
input {
width: 100%;
padding-left: 10px;
......@@ -40,7 +31,7 @@
color: $color_999;
}
&.bargain-phone-popup__ipt {
&.bargain-bind-phone__ipt {
border-left: 1px solid #ddd;
}
}
......@@ -48,69 +39,44 @@
.bargain-phone-popup__button--num {
.bargain-bind-phone__button--num {
display: inline-flex;
align-items: center;
padding: 0 5px;
color: $color_999;
}
.bargain-phone-popup__button--send {
.bargain-bind-phone__button--send {
width: 136px;
border-style: none;
font-size: 13px;
color: $color_999;
color: $active;
text-align: right;
background-color: transparent;
cursor: pointer;
outline: none;
&.active {
color: $active;
&:disabled {
color: $color_999;
}
}
.bargain-phone-popup__button--bargain {
.bargain-bind-phone__button--bargain {
display: block;
width: 100%;
height: 30px;
margin-top: 20px;
border-style: none;
font-size: 15px;
color: $white;
color: #FF4000;
line-height: 30px;
text-align: center;
background-color: $bg_999;
background-color: #FADD29;
outline: none;
-webkit-appearance: none;
&.active {
color: #FF4000;
background-color: #FADD29;
}
}
.popup-bind--bargain {
.popup-bind__content {
width: 300px;
margin: 200px auto 20px;
padding: 20px;
border-radius: 3px;
}
.popup-bind__title {
margin: 0 0 12px;
font-size: 15px;
font-weight: normal;
}
.popup-bind__desc {
padding: 0;
font-size: 12px;
}
.popup-bind__button {
padding: 0;
&:disabled {
color: $white;
background-color: $bg_999;
}
}
\ No newline at end of file
......@@ -6,7 +6,9 @@ import { getCourses } from "@/components/detail/actions"
import { connect } from "react-redux"
import './index.scss'
import Overlay from '../overlay'
import BindPhone from './../bindPhone/index';
import BargainConfirmBind from './../bindPhone/confirm';
import Mask from '@/common/Mask/index';
class BtnStatus extends Component {
constructor(props) {
......@@ -17,9 +19,12 @@ class BtnStatus extends Component {
group_status: 3,
in_cart: false,
countdown: 0,
barInfo: {}
barInfo: {},
bindPhone: false,
bindConfrm: false,
bindInfo: {}, // 冲突信息
formInfo: {},
}
}
componentDidMount() {
......@@ -77,6 +82,7 @@ class BtnStatus extends Component {
// }
// })
// };
// 返现课程的立即购买
signUpNow = () => {
if(this.props.user.hasError) {
......@@ -93,6 +99,7 @@ class BtnStatus extends Component {
})
}
};
// 普通课程的立即报名 要模拟结算过程
simpleCourse = () => {
if(this.props.user.hasError) {
......@@ -108,11 +115,13 @@ class BtnStatus extends Component {
})
}
};
// 格式化开课时间
formatDate = (date) => {
let ary = date.split('-');
return `${ary[1]}${ary[2]}日开课`;
};
// 直接购买
tobuy = () => {
const {user} = this.props;
......@@ -134,6 +143,7 @@ class BtnStatus extends Component {
}
}
};
// 一键开团
keyToGroup = () => {
if(this.props.user.hasError) {
......@@ -143,6 +153,7 @@ class BtnStatus extends Component {
}
this.props.history.push(`/order?id=${getParam('id')}`, {group: 1})
};
// 砍完价去支付
bargainToOrder = () => {
if(this.props.user.hasError) {
......@@ -184,6 +195,7 @@ class BtnStatus extends Component {
}
})
}
close = () => {
this.setState({
isShowOverlay: false,
......@@ -206,7 +218,14 @@ class BtnStatus extends Component {
http.post(`${API.home}/m/bargain/toBargain`, data).then((res) => {
const {data, code, msg} = res.data;
if (code === 200) {
// user_status 用户状态 1-关注公众号,2-绑定手机号 3-再砍一刀 (是发起人没有这个字段)
if(data.user_status === 2) {
this.setState({
bindPhone: true
})
}else {
history.push(`/bargain-middle-page?id=${course_id}&bargaincode=${data.bargain_code}&is_originator=1`)
}
} else {
Toast.info(msg, 2)
}
......@@ -224,7 +243,6 @@ class BtnStatus extends Component {
}
}
//获取砍价信息
getBargainInfo = () => {
const {user} = this.props
......@@ -278,13 +296,58 @@ class BtnStatus extends Component {
}
}
// 隐藏弹窗
handleToHide = (key) => {
console.log(key);
this.setState({
[key]: false
});
}
// 绑定手机号 -- 确认
confirmBindPhone = (params, bindInfo) => {
this.setState({
bindPhone: false,
bindConfrm: true,
formInfo: params,
bindInfo
});
}
render() {
// data 课程信息;barInfo 砍价信息
const { user = {}, toCart } = this.props;
const { countdown ,barInfo, courseInfo: info = {}} = this.state;
const { user = {}, toCart, country } = this.props;
const {
countdown,
barInfo,
courseInfo: info = {},
bindPhone,
bindConfrm,
bindInfo,
formInfo,
} = this.state;
const uid = user.data && user.data.uid;
return (
<div>
{/* 绑定手机号 */}
<Mask visible={bindPhone} handleToHide={() => this.handleToHide('bindPhone')}>
<BindPhone
country={country}
handleToBargain={this.toKanjia}
confirmBindPhone={this.confirmBindPhone}
/>
</Mask>
{/* 绑定手机号--确认 */}
<Mask visible={bindConfrm} handleToHide={() => this.handleToHide('bindConfrm')}>
<BargainConfirmBind
data={formInfo}
bindInfo={bindInfo}
handleToHide={() => this.handleToHide('bindConfrm')}
handleToBargain={this.toKanjia}
/>
</Mask>
{/*正常购买*/}
{
info.is_baoming === 0 && info.group_status !== 3 &&
......@@ -320,8 +383,6 @@ class BtnStatus extends Component {
</div>
}
{/*已购买*/}
{
info.is_baoming === 1 &&
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -35,7 +35,7 @@ class ToGroup extends Component {
wxShare({
title: `【仅剩${number}个名额】我${pdd_price}元拼了《${data.course_title}》`,
desc: data.course_title,
link: location.href,
link: location.href+'&is_originator=1',
imgUrl: data.image_name,
});
......@@ -91,7 +91,16 @@ class ToGroup extends Component {
const {isBuy = false, data = {}} = this.state;
const {user, history, location} = this.props;
if (user.hasError) {
if (browser.isWeixin) {
let redirectURI = window.location.href
if (redirectURI.includes('code=') && redirectURI.includes('state=STATE')) {
let index = redirectURI.lastIndexOf('code=');
redirectURI = redirectURI.substr(0, index - 1);
}
window.location.assign(`https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=${encodeURIComponent(redirectURI)}&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect`)
} else {
history.push('/passport', {from: location})
}
return
}
......@@ -252,23 +261,22 @@ function GorupContent(props) {
!userInfo.hasError && groupon_member.map(item => {
if (item.uid == userInfo.data.uid) {
flag = true
return;
}
})
if (flag) {
tip = <p className='tip'>{`拼团省¥${data.price1 - pdd_price}元`}</p>
btn = <span className='group-btn' onClick={props.invitedFriends}>邀请好友参团 {countdown} 后结束</span>
dec = <p className='dec'>分享到3个群后,成团率高达98%</p>
} else {
if(getParam('is_originator') == 1){
tip = <p className='tip'>{`拼团省¥${data.price1 - pdd_price}元`}</p>
// btn = <Link to={{
// pathname: '/order',
// search: `?id=${data.course_id}`,
// state: {
// group: 1
// }
// }} className='group-btn'>一键参团</Link>
btn = <a href="javascript:;" className='group-btn' onClick={props.handleToGroup}>一键参团</a>
} else {
tip = <p className='tip'>{`拼团省¥${data.price1 - pdd_price}元`}</p>
btn = <span className='group-btn' onClick={props.invitedFriends}>邀请好友参团 {countdown} 后结束</span>
dec = <p className='dec'>分享到3个群后,成团率高达98%</p>
}
}
}
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -348,6 +348,7 @@ class Detail extends Component {
document.title = `${course_info.course_title} - 七月在线`;
if (course_info.group_status === 3 || course_info.group_status === 4) {
let endTime = course_info.pdd_group_info.groupon_member.end_time;
if(endTime && endTime > 0) {
let date = endTime * 1000,
hours = 0,
minutes = 0,
......@@ -362,6 +363,7 @@ class Detail extends Component {
});
}, 1000)
}
}
wxShare({
title: course_info.course_title,
desc: course_info.index_description,
......@@ -451,7 +453,6 @@ class Detail extends Component {
this.fetchCourseInfo();
} else {
history.replace('/shopcart');
ß
}
} else if (res.data.code === 15001) {
history.replace('/shopcart');
......@@ -490,7 +491,6 @@ class Detail extends Component {
singleType: 1
})
this.props.history.push(`/detail?id=${getParam('id')}`);
}
render() {
......@@ -740,6 +740,7 @@ class Detail extends Component {
{
course_info &&
<BtnStatus
country={this.props.country}
countdown={countdown}
data={course_info}
user={this.props.user}
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -127,6 +127,11 @@ class MyOrders extends Component {
id={item.course_id}
toDetail={this.toCourseDetail}
/>
{
item.course_expire && item.course_expire!='' &&
<span className='course-expire'>{item.course_expire}</span>
}
</div>
)
})
......@@ -135,12 +140,18 @@ class MyOrders extends Component {
<PayInfo item={item} cancel={this.cancel}/>
{
item.type == 5 && item.is_buy == 0 &&
item.type == 5 && item.is_buy == 0 && item.is_overdue == 0 &&
<div className={'expand-pay-wk'}>
<span className={'expand-pay-time'}>{item.final_end_time}结束付尾款</span>
<span>还需支付尾款</span>
</div>
}
{
item.type == 5 && item.is_buy == 0 && item.is_overdue == 1 &&
<div className={'expand-pay-wk'}>
<span>支付尾款时间已过</span>
</div>
}
</div>
)
})
......
......@@ -37,6 +37,21 @@
padding: 10px 12px;
background-color: $bg_fff;
border-bottom: 1px solid $border_e7eaf1;
position: relative;
.course-expire{
display: block;
width:92px;
height:20px;
line-height: 20px;
background:#FF3A3A;
border-radius:0 10px 10px 0;
position: absolute;
color: #FFF;
font-size: 12px;
left: 12px;
bottom: 20px;
text-align: center;
}
}
.order-info {
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -33,7 +33,7 @@ class Login extends Component {
hash: ''
};
const referrer = document.referrer
const redirectURI = referrer ? referrer : window.location.origin + from.pathname + from.search + from.hash;
const redirectURI = (!/^https?:\/\/m.julyedu.com\/?$/.test(referrer) && referrer) ? referrer : window.location.origin + from.pathname + from.search + from.hash;
switch (method) {
case '账号登录':
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -83,23 +83,15 @@ class PythonClass extends Component {
handleToSend = (params) => {
const { history } = this.props;
const { isShare, entryMode } = this.state;
const { isShare } = this.state;
if(browser.isWeixin) {
history.push(`/pythonShare?id=${getParam('id')}&type=${getParam('type')}&ques=${getParam('ques')}&origin=python`);
this.setState({
isGuide: true
});
let title = '';
let labelName = this.formatTitle(params);
if(entryMode !== 0 && !isShare) {
title = `我在${params.course_name}${labelName}遇到了困难`;
}
if(entryMode !== 0 && isShare) {
title = `我已在【${params.course_name}】上运行了${params.code_lines}行代码了`
}
wxShare({
title,
desc: labelName,
title: isShare? `我已在【${params.course_name}】上运行了行代码了${params.code_lines}` : `我在${params.course_name}${this.formatTitle(params)}遇到了困难`,
desc: this.formatTitle(params),
link: encodeURI(location.href),
imgUrl: params.course_img,
});
......@@ -155,7 +147,7 @@ class PythonClass extends Component {
data={data}
labelName={this.formatTitle(data)}
handleToExecute={this.handleToExecute}
handleToSend={this.handleToSend}
handleToSend={() => this.handleToSend(data)}
copyToSuccess={this.copyToSuccess}
handleToHide={this.handleToHide}
/>
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -33,8 +33,8 @@ const ShareCourse = loadable(() => import(/* webpackChunkName: 'ShareCourse'*/'@
const Country = loadable(() => import(/* webpackChunkName: 'Country' */'@/components/country/index'))
const ExpandCallback = loadable(() => import('@/components/expand/callback'))
const ExpandShare = loadable(() => import('@/components/expand/share'))
const Activity = loadable(() => import(/* webpackChunkName: 'Activity' */'@/components/activity/index'))
const Invite = loadable(() => import(/* webpackChunkName: 'Invite' */'@/components/activity/invite'))
const Activity = loadable(() => import(/* webpackChunkName: 'Activity' */'@/components/activity/1111/index'))
const Invite = loadable(() => import(/* webpackChunkName: 'Invite' */'@/components/activity/1111/invite'))
export default [
{
path: '/',
......@@ -187,7 +187,7 @@ export default [
},
{
path: '/prize-winner-list',
component: loadable(() => import(/* webpackChunkName: 'prize-winner-list' */'@/components/activity/prize-winner-list'))
component: loadable(() => import(/* webpackChunkName: 'prize-winner-list' */'@/components/activity/1111/prize-winner-list'))
},
//定金订单页面
{
......@@ -220,12 +220,37 @@ export default [
},
{
path: '/activity',
exact: true,
component: Activity,
},
{
path: '/invite',
component: Invite,
},
//双旦活动
{
path: '/activity/newyear-2019/landing',
component: loadable(() => import(/* webpackChunkName: 'newyear-2019-landing'*/ '@components/activity/newyear-2019/landing/index'))
},
// 双旦活动预热页面
{
path: '/year/yearIndex',
component: loadable(() => import(/* webpackChunkName: 'newyear-yearIndex' */ '@components/activity/newyear-2019/preheat/index'))
},
// 我的宝箱
{
path: '/year/yearTreasure',
component: loadable(() => import(/* webpackChunkName: 'newyear-yearIndex' */ '@components/activity/newyear-2019/myTreasure/index'))
}
,
// 双旦心愿单
{
path: '/year/yearWish',
component: loadable(() => import(/* webpackChunkName: 'newyear-yearIndex' */ '@components/activity/newyear-2019/year-wish/index'))
},
// python 小课页面
{
path: '/python',
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
......@@ -15,8 +15,10 @@ const accountLogin = user => dispatch => {
}
const quickLogin = user => dispatch => {
return http.post(`${API['passport-api']}/quick_login`, user)
.then(res => {
return http.post(`${API['passport-api']}/quick_login`, {
...user,
plat: 5
}).then(res => {
return storeUser(res, dispatch)
})
}
......
......@@ -3,7 +3,7 @@ import { merge } from 'lodash'
const notLoggedIn = 4030
const initialState = {
export const initialState = {
hasError: true,
code: notLoggedIn,
msg: '',
......
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
File mode changed from 100644 to 100755
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment