Commit d08fac0a by xuzhenghua

砍价课程为空处理

parent 3d0acaa7
...@@ -1650,15 +1650,15 @@ ...@@ -1650,15 +1650,15 @@
} }
}, },
"@videojs/http-streaming": { "@videojs/http-streaming": {
"version": "1.10.3", "version": "1.10.6",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.3.tgz", "resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.6.tgz",
"integrity": "sha512-fxXtwVrQBdhOFh6GymPAPCb4utCI01Zs5fdyZgtR6FSsaz/zGmnzfNS5GvNjBi/hZviMsbNPFaOTTFMMNLNA3A==", "integrity": "sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==",
"requires": { "requires": {
"aes-decrypter": "3.0.0", "aes-decrypter": "3.0.0",
"global": "^4.3.0", "global": "^4.3.0",
"m3u8-parser": "4.3.0", "m3u8-parser": "4.4.0",
"mpd-parser": "0.8.1", "mpd-parser": "0.8.1",
"mux.js": "5.1.3", "mux.js": "5.2.1",
"url-toolkit": "^2.1.3", "url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0" "video.js": "^6.8.0 || ^7.0.0"
} }
...@@ -9225,21 +9225,11 @@ ...@@ -9225,21 +9225,11 @@
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
"integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
}, },
"lodash.assign": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/lodash.assign/-/lodash.assign-4.2.0.tgz",
"integrity": "sha1-DZnzzNem0mHRm9rrkkUAXShYCOc="
},
"lodash.camelcase": { "lodash.camelcase": {
"version": "4.3.0", "version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=" "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY="
}, },
"lodash.clonedeep": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz",
"integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8="
},
"lodash.debounce": { "lodash.debounce": {
"version": "4.0.8", "version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
...@@ -9270,11 +9260,6 @@ ...@@ -9270,11 +9260,6 @@
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=" "integrity": "sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4="
}, },
"lodash.mergewith": {
"version": "4.6.2",
"resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz",
"integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ=="
},
"lodash.sortby": { "lodash.sortby": {
"version": "4.7.0", "version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
...@@ -9348,9 +9333,9 @@ ...@@ -9348,9 +9333,9 @@
} }
}, },
"m3u8-parser": { "m3u8-parser": {
"version": "4.3.0", "version": "4.4.0",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.3.0.tgz", "resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.4.0.tgz",
"integrity": "sha512-bVbjuBMoVIgFL1vpXVIxjeaoB5TPDJRb0m5qiTdM738SGqv/LAmsnVVPlKjM4fulm/rr1XZsKM+owHm+zvqxYA==", "integrity": "sha512-iH2AygTFILtato+XAgnoPYzLHM4R3DjATj7Ozbk7EHdB2XoLF2oyOUguM7Kc4UVHbQHHL/QPaw98r7PbWzG0gg==",
"requires": { "requires": {
"global": "^4.3.2" "global": "^4.3.2"
} }
...@@ -9860,9 +9845,9 @@ ...@@ -9860,9 +9845,9 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s=" "integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
}, },
"mux.js": { "mux.js": {
"version": "5.1.3", "version": "5.2.1",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.1.3.tgz", "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.2.1.tgz",
"integrity": "sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg==" "integrity": "sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ=="
}, },
"nan": { "nan": {
"version": "2.13.2", "version": "2.13.2",
...@@ -10025,9 +10010,9 @@ ...@@ -10025,9 +10010,9 @@
} }
}, },
"node-sass": { "node-sass": {
"version": "4.11.0", "version": "4.13.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz", "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
"integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==", "integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
"requires": { "requires": {
"async-foreach": "^0.1.3", "async-foreach": "^0.1.3",
"chalk": "^1.1.1", "chalk": "^1.1.1",
...@@ -10036,12 +10021,10 @@ ...@@ -10036,12 +10021,10 @@
"get-stdin": "^4.0.1", "get-stdin": "^4.0.1",
"glob": "^7.0.3", "glob": "^7.0.3",
"in-publish": "^2.0.0", "in-publish": "^2.0.0",
"lodash.assign": "^4.2.0", "lodash": "^4.17.15",
"lodash.clonedeep": "^4.3.2",
"lodash.mergewith": "^4.6.0",
"meow": "^3.7.0", "meow": "^3.7.0",
"mkdirp": "^0.5.1", "mkdirp": "^0.5.1",
"nan": "^2.10.0", "nan": "^2.13.2",
"node-gyp": "^3.8.0", "node-gyp": "^3.8.0",
"npmlog": "^4.0.0", "npmlog": "^4.0.0",
"request": "^2.88.0", "request": "^2.88.0",
...@@ -14587,11 +14570,6 @@ ...@@ -14587,11 +14570,6 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ==" "integrity": "sha512-4krF8scpejhaOgqzBEcGM7yDIEfi0/8+8zDRZhNZZ2kjmHJ4hv3zCbQWxoJGz1iw5U0Jl0nma13xzHXcncMavQ=="
}, },
"tsml": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/tsml/-/tsml-1.0.1.tgz",
"integrity": "sha1-ifghi52eJX9H1/a1bQHFpNLGj8M="
},
"tty-browserify": { "tty-browserify": {
"version": "0.0.0", "version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
...@@ -14982,25 +14960,24 @@ ...@@ -14982,25 +14960,24 @@
} }
}, },
"video.js": { "video.js": {
"version": "7.6.0", "version": "7.6.5",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.0.tgz", "resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.5.tgz",
"integrity": "sha512-A0HSKzAmcYkd1xyExqUlM6n8bkghcX54iCvW08bPvvl3UHt8d8zijuylfIWu8vo1Z8fYyk9HPOFs1i3Cldr/cw==", "integrity": "sha512-r0kC9SNJhXz9th/wwbRaLVOIZTvXkF+rhFq9/FWU+e+EJClwClRCgP8STGmfrPHDXrfWiJwH9YY21JZK61vGGQ==",
"requires": { "requires": {
"@babel/runtime": "^7.4.5", "@babel/runtime": "^7.4.5",
"@videojs/http-streaming": "1.10.3", "@videojs/http-streaming": "1.10.6",
"global": "4.3.2", "global": "4.3.2",
"keycode": "^2.2.0", "keycode": "^2.2.0",
"safe-json-parse": "4.0.0", "safe-json-parse": "4.0.0",
"tsml": "1.0.1",
"videojs-font": "3.2.0", "videojs-font": "3.2.0",
"videojs-vtt.js": "^0.14.1", "videojs-vtt.js": "^0.14.1",
"xhr": "2.4.0" "xhr": "2.4.0"
}, },
"dependencies": { "dependencies": {
"@babel/runtime": { "@babel/runtime": {
"version": "7.5.5", "version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz", "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz",
"integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==", "integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==",
"requires": { "requires": {
"regenerator-runtime": "^0.13.2" "regenerator-runtime": "^0.13.2"
} }
......
...@@ -46,13 +46,14 @@ ...@@ -46,13 +46,14 @@
"less-loader": "^4.1.0", "less-loader": "^4.1.0",
"lodash": "^4.17.15", "lodash": "^4.17.15",
"mini-css-extract-plugin": "0.5.0", "mini-css-extract-plugin": "0.5.0",
"node-sass": "^4.11.0", "node-sass": "^4.13.0",
"optimize-css-assets-webpack-plugin": "5.0.1", "optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.2.1", "pnp-webpack-plugin": "1.2.1",
"postcss-flexbugs-fixes": "4.1.0", "postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0", "postcss-loader": "3.0.0",
"postcss-preset-env": "6.5.0", "postcss-preset-env": "6.5.0",
"postcss-safe-parser": "4.0.1", "postcss-safe-parser": "4.0.1",
"prop-types": "^15.7.2",
"qrcode": "^1.3.3", "qrcode": "^1.3.3",
"qs": "^6.7.0", "qs": "^6.7.0",
"react": "^16.8.6", "react": "^16.8.6",
...@@ -79,7 +80,7 @@ ...@@ -79,7 +80,7 @@
"swiper": "^4.5.0", "swiper": "^4.5.0",
"terser-webpack-plugin": "1.2.2", "terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2", "url-loader": "1.1.2",
"video.js": "^7.6.0", "video.js": "^7.6.5",
"web-launch-app": "^2.1.9", "web-launch-app": "^2.1.9",
"webpack": "4.28.3", "webpack": "4.28.3",
"webpack-dev-server": "3.1.14", "webpack-dev-server": "3.1.14",
......
...@@ -5,5 +5,6 @@ var API = { ...@@ -5,5 +5,6 @@ var API = {
'passport-api': 'http://passport-test.julyedu.com', 'passport-api': 'http://passport-test.julyedu.com',
'base-api': 'http://api-test.julyedu.com', 'base-api': 'http://api-test.julyedu.com',
'record': 'record.julyedu.com:8001', 'record': 'record.julyedu.com:8001',
'process-api': 'ws:process-test.julyedu.com:9502' 'process-api': 'ws:process-test.julyedu.com:9502',
'm': 'http://m-test.julyedu.com',
} }
...@@ -63,6 +63,9 @@ class App extends Component { ...@@ -63,6 +63,9 @@ class App extends Component {
if (cookie.get('uid') && this.props.user.hasError) { if (cookie.get('uid') && this.props.user.hasError) {
this.getUser() this.getUser()
} }
if(location.pathname==='/passport'){
window.localStorage.setItem('binding_redirect', JSON.stringify(this.previousLocation))
}
const {pathname, state} = location const {pathname, state} = location
if (pathname.startsWith('/passport')) { if (pathname.startsWith('/passport')) {
location.state = { location.state = {
......
import React from 'react'
import ReactDOM from 'react-dom'
import './index.scss'
import classnames from 'classnames'
function ClosablePopup({
title, content, className, closable = true, close = function () {
}
} = {}) {
function unmountComponent() {
ReactDOM.unmountComponentAtNode(div)
if (div && div.parentNode) {
div.parentNode.removeChild(div)
}
}
function _close() {
let _c = close()
if (_c && _c.then) {
_c.then(() => {
unmountComponent()
})
} else {
unmountComponent()
}
}
const closablePopup = (
<div className={'closable-popup-mask'}>
<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}/>
}
</div>
</div>
)
const div = document.createElement('div')
document.body.appendChild(div)
ReactDOM.render(closablePopup, div)
return {
close: _close
}
}
export default ClosablePopup
.closable-popup-mask {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.6);
z-index: 999;
.popup-container {
position: absolute;
top: 165px;
left: 50%;
transform: translateX(-50%);
width: 300px;
padding: 20px 10px;
border-radius: 10px;
background: #fff;
.title {
font-size: 16px;
color: #525C65;
text-align: center;
}
.close {
position: absolute;
bottom: -74px;
left: 50%;
transform: translateX(-50%);
font-size: 36px;
color: #fff;
}
}
}
import React from 'react'
import { Modal } from 'antd-mobile'
import './index.scss'
export default function ({
amount,
limit_amount,
onCancel = () => {
},
onConfirm
}) {
const content = (
<>
<div className="end-expansion-alert-ques">
{`你的${amount}元优惠券正在膨胀中,
确定要结束膨胀吗?`}
</div>
<div className="end-expansion-alert-hint">
{`离${limit_amount}元只差一点点了!继续膨胀,优惠更多哦`}
</div>
</>
)
Modal.alert('温馨提示', content, [
{text: '再考虑下', onPress: onCancel, style: {color: '#333'}},
{text: '确定结束膨胀', onPress: onConfirm}
])
}
.am-modal {
width: 300px;
&-title {
font-size: 15px;
}
}
.end-expansion-alert {
&-ques {
width: 200px;
margin: 0 auto 20px;
text-align: center;
color: #666;
font-size: 15px;
}
&-hint {
color: #999;
font-size: 12px;
}
}
...@@ -5,8 +5,9 @@ export { default as OrderItem } from './OrderList' ...@@ -5,8 +5,9 @@ export { default as OrderItem } from './OrderList'
export { default as HeaderBar } from './HeaderBar' export { default as HeaderBar } from './HeaderBar'
export { default as CallApp } from './CallApp' export { default as CallApp } from './CallApp'
export { default as Captcha } from './Captcha' export { default as Captcha } from './Captcha'
export { default as ClearableInput } from "./ClearableInput"; export { default as ClearableInput } from "./ClearableInput"
export { default as Loading } from './Loading' export { default as Loading } from './Loading'
export { default as RenderTabBar } from './renderTabBar' export { default as RenderTabBar } from './renderTabBar'
export { default as Popup } from './closable-popup'
import React, {Component} from 'react'
import './index.scss'
import {http} from '@/utils'
import { Link } from "react-router-dom"
import {Toast} from "antd-mobile";
class ExpandActiveToast extends Component {
constructor(props) {
super(props);
this.state = {
expandLength: 0,
isShowExpand:true
}
}
componentDidMount() {
http.get(`${API['base-api']}/sys/deposit/notice`).then((res) => {
if (res.data.errno == 200) {
const {data} = res.data
this.setState({
expandLength: data.num
})
} else {
Toast.info(res.data.msg, 2)
}
})
}
cleseExpand = () => {
this.setState({isShowExpand: false})
}
render() {
return (
<div>
{
this.state.expandLength > 0 && this.state.isShowExpand &&
<div className="expand-active-toast">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/guanggao.png" alt=''/>
<div className="expand-toast-swiper">
<p>您有<span className="red">{this.state.expandLength}</span>待支付尾款的课程 再不支付就要过期了!</p>
</div>
<Link to='/final-deposit-order?source=1'>查看</Link>
<img
onClick={e => this.cleseExpand()}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/guanbi.png"
alt=''
/>
</div>
}
</div>
);
}
}
export default ExpandActiveToast
.expand-active-toast {
font-size: 14px;
background-color: #e8f6ff;
display: flex;
justify-content: space-between;
padding: 0 15px;
height: 33px;
line-height: 33px;
margin-bottom: 10px;
.expand-toast-swiper {
width: 240px;
overflow: hidden;
position: relative;
p {
width: 375px;
position: absolute;
-webkit-animation: scollLeft 10s linear 0s infinite;
}
}
.red {
color: #ff3131;
}
img {
width: 15px;
height: 15px;
margin-top: 9px;
}
a {
display: inline-block;
width: 44px;
height: 22px;
background: linear-gradient(90deg, #0099ff 0%, #0080ff 100%);
border-radius: 11px;
color: #fff;
font-size: 12px;
line-height: 22px;
margin-top: 5px;
text-align: center;
}
@-webkit-keyframes scollLeft {
from {
right: -100%;
}
to {
right: 100%;
}
}
@keyframes scollLeft {
from {
right: -100%;
}
to {
right: 100%;
}
}
@-moz-keyframes scollLeft {
from {
right: -100%;
}
to {
right: 100%;
}
}
@-o-keyframes scollLeft {
from {
right: -100%;
}
to {
right: 100%;
}
}
}
...@@ -11,6 +11,7 @@ import { Link } from "react-router-dom" ...@@ -11,6 +11,7 @@ import { Link } from "react-router-dom"
import { Toast } from 'antd-mobile' import { Toast } from 'antd-mobile'
import { connect } from "react-redux"; import { connect } from "react-redux";
import TopSwiper from './TopSwiper' import TopSwiper from './TopSwiper'
import ExpandActiveToast from './expandActiveToast'
// const animateTypes = Swiper.animateTypes // const animateTypes = Swiper.animateTypes
...@@ -135,6 +136,10 @@ class Index extends Component { ...@@ -135,6 +136,10 @@ class Index extends Component {
/> />
</div> </div>
<div className='zw_height'></div>
<ExpandActiveToast/>
<div className='index-swiper'> <div className='index-swiper'>
{ {
this.state.banner && this.state.banner.length > 0 && this.state.banner && this.state.banner.length > 0 &&
......
...@@ -38,8 +38,11 @@ ...@@ -38,8 +38,11 @@
} }
} }
.zw_height {
height: 44px;
}
.index-swiper { .index-swiper {
margin-top: 44px;
height: 168px; height: 168px;
.swiper-container { .swiper-container {
......
import React, { Component } from 'react'
import {connect} from "react-redux";
import { http, getParam } from '@/utils';
import cookie from 'js-cookie'
import './index.scss';
import {Toast} from "antd-mobile";
import jsCookie from 'js-cookie';
class Activity extends Component {
constructor(props) {
super(props);
this.state = {
'butText': '立即领取'
}
}
componentWillMount() {
jsCookie.set('blessing_invite_uid', getParam('shareuid'), {domain: '.julyedu.com', expires: 30});
jsCookie.set('blessing_invite_code', getParam('inviteCode'), {domain: '.julyedu.com', expires: 30});
if(cookie.get('uid')) {
this.setState(()=>({
butText: '已领取,去使用'
}));
}
}
getGift = () => {
if(this.props.user.hasError) {
this.props.history.push('/passport', {from: this.props.location.pathname});
} else {
this.props.history.push('/blessingPreheat');
}
}
render() {
const {butText} = this.state;
return (
<div className="activity__con">
<div className='banner__con'></div>
<div className='content__con'>
<div className="button__get" onClick={this.getGift}>{butText}</div>
</div>
</div>
)
}
}
export default connect(
state => ({user: state.user}),
null
)(Activity);
.activity__con {
width: 100%;
height: 100vh;
background-color: #5327FA;
overflow: auto;
.banner__con {
width: 100%;
height: 170px;
background: url('./images/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-size: 100% 100%;
position: relative;
.button__get {
width:220px;
height:40px;
background:rgba(253,203,5,1);
border-radius:10px;
font-size:18px;
font-weight:400;
color:rgba(246,53,28,1);
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: 14px;
letter-spacing: 2px;
text-align: center;
line-height: 40px;
}
}
.invite__content {
color:rgba(255,255,255,1);
font-weight:400;
.content__one {
width: 100%;
padding: 0 50px;
font-size: 14px;
display: flex;
justify-content: center;
align-items: center;
height: 20px;
margin-bottom: 12px;
p {
display: flex;
align-items: center;
justify-content: center;
}
.img__con {
width: 88px;
height: 16px;
background: url('./images/value.png') center center no-repeat;
background-size: 100% 100%;
margin-left: 4px;
}
}
.content__two {
height:16px;
line-height: 16px;
font-size:16px;
text-align: center;
text-align-last: center;
margin-bottom: 14px;
}
.box__out {
width:345px;
height:106px;
background:linear-gradient(to bottom,rgba(255,169,67,1) 0%,rgba(250,94,39,1) 100%);
border-radius:10px;
margin: 0 auto;
display: flex;
justify-content: center;
align-items: center;
}
.box__middle {
width:333px;
height:94px;
background:rgba(255,255,255,1);
box-shadow:0px 1px 3px 0px rgba(133,75,2,0.1);
border-radius:8px;
display: flex;
justify-content: center;
align-items: center;
}
.box__inner {
width:327px;
height:88px;
background:rgba(255,223,4,1);
border:1px solid rgba(253,184,46,1);
box-shadow:0px 1px 3px 0px rgba(133,75,2,0.1);
border-radius:6px;
color: #F24000;
font-size: 16px;
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
p {
font-size: 16px;
line-height: 16px;
margin-top: 12px;
color:rgba(242,64,0, .8);
font-weight: 400;
}
p.hot__value {
color: #FD3D24;
font-size: 20px;
font-weight:500;
line-height: 20px;
}
.hot__progress {
display: flex;
flex-direction: row;
max-height: 8px;
width: 280px;
align-items: center;
justify-content: center;
margin-top: 10px;
.progress__bar {
width:210px;
height:6px;
background:rgba(255,255,255,1);
border-radius:3px;
position: relative;
}
span {
display: flex;
justify-content: center;
align-items: center;
width: 48px;
height: 20px;
color: #5327FA;
font-size: 20px;
transform: scale(0.5);
}
.progress__point {
position: absolute;
height: 6px;
border-radius: 3px;
background:linear-gradient(90deg,rgba(83,39,250,1) 0%,rgba(168,39,250,1) 100%);
}
}
}
.but__con {
width:216px;
height:40px;
background:rgba(57,0,201,.5);
border-radius:8px;
margin: 20px auto 0;
display: flex;
justify-content: center;
align-items: center;
.button__content {
width:210px;
height:36px;
background:rgba(255,255,255,1);
border-radius:6px;
font-size:16px;
font-weight:400;
color:rgba(57,0,201,1);
display: flex;
justify-content: center;
align-items: center;
}
}
.list__title {
height:14px;
line-height: 14px;
font-size:14px;
font-weight:400;
color:rgba(255,255,255,1);
width: 240px;
background: url('./images/yaoqh_bj.png') center center no-repeat;
background-size: 100% 50%;
text-align: center;
text-align-last: center;
margin: 30px auto 10px;
}
.show__new {
font-size: 12px;
color: #A993FD;
text-align: center;
text-align-last: center;
}
.list__con {
width: 346px;
margin: 14px auto;
border: 1px solid rgba(255,255,255, .5);
// min-height: 190px;
border-radius:10px;
display: flex;
flex-wrap: wrap;
padding: 0 15px;
.user__item-info {
width: 156px;
height: 46px;
display: flex;
justify-content: flex-start;
align-items: center;
.item__con {
width: 100%;
height: 40px;
display: flex;
justify-content: flex-start;
align-items: center;
margin-left: 6px;
margin-right: 0;
border-bottom: 1px rgba(255, 255, 255, 0.6) dashed;
}
&:nth-child(2n+1) {
border-right: 1px solid rgba(169,147,253,1);
.item__con {
margin-right: 6px;
margin-left: 0;
}
}
.user_avatar {
width: 22px;
height: 22px;
border-radius: 50%;
margin-right: 10px;
}
.user_name {
width: 114px;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
font-size: 12px;
font-weight: 400;
color: #fff;
}
}
.item__con-only {
width: 100%;
&:nth-child(2n+1) {
border-right: none;
}
.item__con {
width: 100%;
}
}
}
}
.share__mark {
position: fixed;
width: 100%;
height: 100%;
left: 0;
top: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .4);
.share__tip {
width:290px;
height:62px;
background:rgba(255,255,255,1);
border-radius:10px;
display: flex;
justify-content: center;
align-items: center;
color: #525C65;
font-size: 16px;
position: absolute;
top: 78px;
left: 50%;
transform: translateX(-50%);
}
.share__row {
width: 60px;
height: 44px;
background: url('./images/throw_icon.png') center center no-repeat;
background-size: 100% 100%;
position: absolute;
right: 15px;
top: 10px;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import {connect} from "react-redux"
import './index.scss';
import { http, getParam, is_weixin, wxShare, getC, SendMessageToApp } from '@/utils';
import {Toast} from "antd-mobile";
import jsCookie from 'js-cookie';
class Invite extends Component {
constructor(props) {
super(props);
this.state = {
isWeiXin: false,
showTip: false,
hotValue: 0,
hot_schedule: '',
userList: [],
inviteCode: '',
}
}
componentWillMount() {
let uid = jsCookie.get('uid');
let shareuid = getParam('shareuid');
if(uid === shareuid) {
} else {
if(getParam('new')) {
this.props.history.push(`/activity?shareuid=${shareuid}&inviteCode=${getParam('inviteCode')}`);
}
}
}
componentDidMount() {
if(!this.props.user.hasError) {
this.getUserList();
this.getHotValue();
this.getInviteCode();
}
}
componentWillReceiveProps(nextProps) {
console.log('componentWillReceiveProps');
if(!nextProps.user.hasError) {
this.getUserList();
this.getHotValue();
this.getInviteCode();
}
}
getUserList = () => {
http.get(`${API.home}/sys/user/invite/list`).then(res => {
let {code, data, msg} = res.data;
if(code === 200) {
this.setState({
userList: data
});
} else {
Toast.info(msg, 2);
}
});
}
getHotValue = () => {
http.get(`${API.home}/sys/user/hot/value`).then(res => {
let {code, data, msg} = res.data;
if(code === 200) {
this.setState({
hot_schedule: data.hot_schedule,
hotValue: data.hot_value
});
} else {
Toast.info(msg, 2);
}
});
}
getInviteCode = () => {
http.get(`${API.home}/sys/user/invite/link`).then(res => {
let {code, data, msg} = res.data;
if(code === 200) {
let inviteCode = data.blessing_invite_code;
if(is_weixin()) {
wxShare({
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: encodeURI(location.origin + `/invite?shareuid=${jsCookie.get('uid')}&new=1&inviteCode=${inviteCode}`),
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
});
}
this.setState(()=>({
inviteCode: inviteCode
}))
}else if(code === 4030 || code === 4040) {
history.push('/passport');
}else{
Toast.info(msg, 2);
}
});
}
inviteFriends = () => {
const { user, history } = this.props;
const {inviteCode} = this.state;
// 未登录先去登录
if (getParam('version')) {
if(user.hasError) {
SendMessageToApp("toLogin");
}else {
let data = {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: API.m + `/invite?shareuid=${jsCookie.get('uid')}&new=1&inviteCode=${inviteCode}`,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
}
SendMessageToApp("toShare", data)
}
}else {
if(user.hasError) {
history.push('/passport');
}else {
if(is_weixin()) {
history.push(`/invite?shareuid=${jsCookie.get('uid')}&new=1&inviteCode=${inviteCode}`);
wxShare({
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: encodeURI(location.origin + `/invite?shareuid=${jsCookie.get('uid')}&new=1&inviteCode=${inviteCode}`),
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
});
this.setState({
showTip: true,
isWeiXin: true,
});
}else{
history.push(`/invite?shareuid=${jsCookie.get('uid')}&new=1&inviteCode=${inviteCode}`);
this.setState({
showTip: true,
});
}
}
}
}
closeMark = () => {
this.setState({
showTip: false,
});
}
render() {
let {userList, showTip, hotValue, hot_schedule, isWeiXin} = this.state;
return (
<div className="activity__con">
<div className='banner__con'></div>
<div className="invite__content">
<div className="content__one">
<p>邀请好友注册,每增加1人可</p>
<div className="img__con"></div>
</div>
<div className="content__two">
福气值越高,热力值越高,中奖概率越大!
</div>
<div className="box__out">
<div className="box__middle">
<div className="box__inner">
<p>当前中奖热力值:</p>
<p className="hot__value">{hotValue}</p>
<div className="hot__progress">
<div className="progress__bar">
<div className="progress__point" style={{'width': hot_schedule}}></div>
</div>
</div>
</div>
</div>
</div>
<div className="but__con">
<div className="button__content" onClick={this.inviteFriends}>
立即邀请
</div>
</div>
{
userList.length > 0 ? (
<>
<div className="list__title">
<span>邀请好友列表</span>
</div>
<p className="show__new">(仅显示新用户)</p>
</>
) : (null)
}
{
userList.length > 0 ? (
<div className="list__con">
{
userList.length === 1 && userList.map((item, index) => {
return (
<div className="user__item-info item__con-only" key={index}>
<div className="item__con">
<img className="user_avatar" src={item.head_image} />
<div className="user_name">{item.user_name}</div>
</div>
</div>
)
})
}
{
userList.length > 1 && userList.map((item, index) => {
return (
<div className="user__item-info" key={index}>
<div className="item__con">
<img className="user_avatar" src={item.head_image} />
<div className="user_name">{item.user_name}</div>
</div>
</div>
)
})
}
</div>
) : (
null
)
}
</div>
{
showTip && (
<div className="share__mark" onClick={this.closeMark}>
<div className="share__tip">
立即分享给好友增加中奖概率
</div>
{
isWeiXin ? (
<div className="share__row"></div>
) : (
null
)
}
</div>
)
}
</div>
)
}
}
export default connect(
state => ({user: state.user}),
null
)(Invite);
import React, { Component } from 'react'
import './index.scss'
import { getParam, http } from '@/utils'
import { WithFullSize } from "@/HOCs"
class PrizeWinnerList extends Component {
state = {
list: [],
title: '',
}
componentDidMount() {
http.get(`${API.home}/sys/activity/lottery_names/${getParam('tid')}`)
.then(res => {
const {data} = res
if (data.code == 200) {
const {data: response} = data
this.setState({
title: response.title,
list: response.list
})
}
})
}
render() {
const {title, list} = this.state
return (
<div id={'prize-winner-list'}>
<div className="banner">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/prize-winner-list-banner.png" alt=""
className="banner"/>
</div>
<h1>
<img className={'icon'}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/title-decorate-left.png" alt=""/>
<span>{title}</span>
<img className={'icon'}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/title-decorate-right.png" alt=""/>
</h1>
<ul>
<li className={'head title'}>
<div className="code">中奖码</div>
<div className="user-name">用户名称</div>
<div className="prize">奖品名称</div>
</li>
{
list.map(item => (
<li key={item.code}>
<div className="code">{item.code}</div>
<div className="user-name">{item.name}</div>
<div className="prize">{item.prize}</div>
</li>
))
}
</ul>
</div>
)
}
}
export default WithFullSize(PrizeWinnerList)
#prize-winner-list {
height: 100%;
background: #5327fa;
.banner {
width: 100%;
height: 168px;
margin-bottom: 30px;
img {
width: 100%;
height: 100%;
}
}
h1 {
font-size: 14px;
color: #FEFDC7;
text-align: center;
margin-bottom: 15px;
span {
margin: 0 12px;
}
.icon {
width: 25px;
height: 12px;
}
}
ul {
width: 355px;
height: 316px;
margin: 0 auto;
background: rgba(57, 0, 201, 1);
border: 1px solid rgba(89, 112, 255, 1);
border-radius: 4px;
& li:nth-of-type(2n+1) {
background: #3900C9;
}
& li:nth-of-type(2n) {
background: #4200EB;
}
li {
height: 44px;
color: #FAF9E1;
display: flex;
text-align: left;
line-height: 44px;
}
.title{
color: #95FBCA;
text-align: center;
}
.code, .user-name {
width: 110px;
padding-left: 8px;
}
.user-name{
text-align: center;
}
.prize {
width: 135px;
padding-right: 8px;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
}
}
}
import React, {Component} from 'react';
import {http, getParam, SendMessageToApp} from '@/utils';
import listFrame from './../listFrame/index';
import './index.scss';
import {Toast} from "antd-mobile"
import {connect} from "react-redux";
import {Link, withRouter} from "react-router-dom"
class ReserveCourse extends Component {
constructor(props) {
super(props);
this.state = {
courseData: [],
isShowMore: false
};
}
componentDidMount() {
this.fetchAICourse();
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if(this.props.isApp !== nextProps.isApp) {
this.fetchAICourse();
return false;
}
return true;
}
fetchAICourse = () => {
http.get(`${API.home}/sys/pre_coursee`).then(res => {
const {code, data, msg} = res.data;
if (code === 200) {
this.setState({
courseData: JSON.stringify(data) == '{}' ? []:data.filter((item, index) => index < 4),
courseDataAll: data
})
} else {
Toast.info(msg, 2);
}
});
}
// 立即付定金
expandPaydj = (courseId) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
if (!getParam('version')) {
this.props.history.push('/passport/login')
} else {
SendMessageToApp("toLogin");
}
} else {
if (!getParam('version')) {
this.props.history.push(
`/deposit-order?oid=${courseId}&source=${2}`,
{
id: courseId,
isexpand: 1,
sourcenum: 2
}
)
} else {
SendMessageToApp("earnestMoney", courseId);
}
}
}
// 立即付尾款
expandPaywk = (courseId, time,day) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
if (!getParam('version')) {
this.props.history.push('/passport/login')
} else {
SendMessageToApp("toLogin");
}
} else {
let timeStamp = Date.parse(new Date()) / 1000;
if (timeStamp >= time) {
if (!getParam('version')) {
this.props.history.push(
'/final-deposit-order?source=1',
{
id: courseId,
sourcenum: 1
}
)
} else {
SendMessageToApp("TailMoney");
}
} else {
Toast.info("付尾款时间将在" + day + "开启", 2);
}
}
}
// 去学习
tostudy = (courseId) => {
if (!getParam('version')) {
this.props.history.push(`/getDetail?id=${courseId}`)
} else {
let data = {
courseId: courseId,
type: 0 // 正常跳课程详情页type:0,积福气浏览课程详情页-没有浏览过type:1 已浏览过type:2
}
SendMessageToApp("toCourse", data);
}
}
// 查看更多
showMoreData = () => {
this.setState({
isShowMore: !this.state.isShowMore,
courseData: this.state.isShowMore ? this.state.courseDataAll.filter((item, index) => index < 4) : this.state.courseDataAll,
})
}
render() {
const {courseData, isShowMore} = this.state;
return (
<div className='reserve-course-module'>
<CourseList courseData={courseData}
expandPaydj={this.expandPaydj}
expandPaywk={this.expandPaywk}
tostudy={this.tostudy}/>
<button className="more-button" onClick={this.showMoreData}>
{isShowMore ? '收起' : '展开更多'}
</button>
</div>
)
}
}
function CourseList(props) {
const {courseData, expandPaydj, expandPaywk, tostudy} = props
return (
<div className="course-list">
<ul>
{
courseData.map((item, index) => {
return (
<li className="course-item-box" key={index}>
<a onClick={() => tostudy(item.course_id)}>
<div className="top">
<div className="square">
<p className="circular">
到手最低¥<span>{Number(item.price) - Number(item.deduction_amount) - Number(item.limit_amount)}</span>
</p>
</div>
<img className="course-img" src={item.image_name} alt=""/>
</div>
</a>
<p className="count-price">
=原价¥{item.price}
<span>-抵扣¥<i>{item.deduction_amount}</i></span>
<span>-膨胀券¥<i>{item.limit_amount}</i></span>
</p>
<div className="btn">
{
item.is_buy === 0 &&
<button className="to-expand-buy1"
onClick={() => expandPaydj(item.course_id)}>立即付定金</button>
}
{
item.is_buy === 1 &&
<button
className="to-expand-buy2"
onClick={() => expandPaywk(item.course_id, item.start_timestamp,item.final_start_time)}
>立即付尾款</button>
}
{
item.is_buy === 2 &&
<button className="to-study"
onClick={() => tostudy(item.course_id)}>开始学习</button>
}
</div>
</li>
)
})
}
</ul>
</div>
)
}
export default listFrame(connect(
state => ({
user: state.user
}),
)(withRouter(ReserveCourse)))
.reserve-course-module {
margin: 20px 15px 0 20px;
padding-bottom: 5px;
.course-list {
ul {
display: flex;
justify-content: space-between;
flex-direction: row;
flex-wrap: wrap;
.course-item-box {
width: 48%;
padding: 4px;
background-color: #fff;
border-radius: 2px;
margin-bottom: 15px;
text-align: left;
.top {
width: 100%;
height: 108px;
position: relative;
.course-img {
width: 100%;
height: 108px;
}
.square {
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/course-label-bg.png");
background-repeat: no-repeat;
background-size: cover;
width: 60px;
height: 60px;
position: absolute;
left: 0;
bottom: 0;
.circular {
height: 100%;
width: 100%;
color: #fff;
padding-top: 15px;
text-align: left;
padding-left: 5px;
span {
font-size: 16px;
margin-left: 3px;
}
}
}
}
.count-price {
text-align: left;
color: #555;
margin-top: 8px;
line-height: 15px;
span {
color: #FF4000;
i {
font-size: 16px;
font-style: normal;
margin-left: 3px;
}
}
}
.btn {
width: 100%;
padding: 0 5px;
margin-top: 8px;
margin-bottom: 5px;
button {
width: 100%;
height: 24px;
border-radius: 2px;
font-size: 12px;
color: #fff;
border: none;
}
.to-expand-buy1 {
background: linear-gradient(-90deg, #7800FF 0%, #FF4BF0 100%);
}
.to-expand-buy2 {
background: linear-gradient(-90deg, #FF8C1B 0%, #FF3B05 100%);
}
.to-study {
background: linear-gradient(-90deg, #2ECEF0 0%, #2D56F0 100%);
}
}
}
}
}
.more-button {
display: block;
width: 100px;
height: 27px;
margin: 5px auto 15px;
border: 1px solid #fff;
border-radius: 14px;
font-size: 13px;
font-weight: 300;
color: #fff;
background-color: transparent;
cursor: pointer;
outline: none;
}
}
import React, { Component } from 'react';
import { isEmpty } from 'lodash';
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 { handleToHide } = this.props;
http.post(`${API.home}/sys/collect_info`, params).then(res => {
const {code, msg} = res.data;
if (code === 200) {
handleToHide();
} else {
Toast.info(msg, 2, null, false);
}
});
}
render() {
const { isLoading, addressInfo } = this.state;
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">
<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
// 地址弹窗
.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;
width: 120px;
height: 34px;
margin: 8px auto 0;
border-radius: 17px;
border-style: none;
background-color: rgba(82, 92, 101, 0.3);
font-size: 15px;
font-weight: 500;
color: rgba(255, 255, 255, 1);
line-height: 34px;
cursor: pointer;
outline: none;
&[data-status="do"] {
background-color: #0099FF;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss';
class Banner extends Component {
navTop = 183
prevY = 0
state = {
navs: [
{
text: '积福气',
id: 'lucky-value'
},
{
text: '幸运大抽奖',
id: 'lucky-draw'
},
{
text: '预付定金',
id: 'deposit'
},
{
text: '精品特惠',
id: 'best-courses'
},
{
text: 'AI测试',
id: 'ai-test'
},
{
text: '大咖直播',
id: 'live'
},
],
index: 0,
}
// componentDidMount() {
// window.addEventListener('scroll', throttle(this.calcNavActive, 100))
// }
// componentWillUnmount() {
// window.removeEventListener('scroll', throttle(this.calcNavActive, 100))
// }
// calcNavActive = () => {
// const {navs, index} = this.state
// const y = window.scrollY
// let swipeDirection = y > this.prevY ? 'up' : 'down'
// let _index
// if (swipeDirection === 'up') {
// _index = (index + 1) >= navs.length ? index : index + 1
// } else {
// _index = (index - 1) <= 0 ? 0 : index - 1
// }
// let el = document.querySelector(`#${navs[_index].id}`)
// let nav = document.querySelector('#main-nav')
// if(el) {
// let top = el.offsetTop
// if (y <= this.navTop) {
// nav.classList.remove('fixed')
// } else {
// !nav.classList.contains('fixed') && nav.classList.add('fixed')
// }
// if (swipeDirection === 'up') {
// if (y + 30 + 30 >= top) {
// this.setState({
// index: _index
// })
// }
// } else {
// if (y + 30 + 20 <= top) {
// this.setState({
// index: _index
// })
// }
// }
// this.prevY = y
// }
// }
// toSection = (i, e) => {
// e.preventDefault()
// let top = document.querySelector(`#${this.state.navs[i].id}`).offsetTop
// this.setState({
// index: i
// })
// window.scrollTo({
// top: top - 60,
// left: 0
// })
// }
render() {
const { toSection, navs, index } = this.props;
return (
<div id={'main-banner'}>
<div className="banner"></div>
<nav id={'main-nav'}>
<ul>
{
navs.map((item, i) => {
return (
<li key={i} className={index === i ? 'active' : ''}>
<a href={`#${item.id}`} onClick={(e) => toSection(i, e)}>{item.text}</a>
</li>
)
})
}
</ul>
</nav>
</div>
)
}
}
export default Banner
#main-banner{
overflow: auto;
.banner{
width: 375px;
height: 183px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/banner.png") no-repeat;
background-size: contain;
}
#main-nav{
position: absolute;
top: 183px;
width: 100%;
margin-bottom:30px;
&.fixed{
position: fixed;
top: 0;
z-index: 100;
}
ul{
background: #3900C9;
display: flex;
}
li{
flex: 1;
width: 63px;
height: 40px;
font-size: 11px;
color: #fff;
text-align: center;
line-height: 40px;
&.active{
background: #FF42F9;
}
}
}
}
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { Link } from 'react-router-dom';
import { http, getParam, SendMessageToApp } from '@/utils';
import { Toast } from "antd-mobile";
import ListFrame from './../listFrame/index';
import ListHeader from './../listHeader';
import './index.scss';
@connect(({user})=> ({
uid: user && user.data && user.data.uid ? user.data.uid :''
}))
class CollectBlessing extends Component {
constructor(props) {
super(props);
this.state = {
rules: [
'app/h5/pc端活动页签到+5点福气值(每天一次)',
'关注七月在线微信服务号+30点福气值(仅限一次)',
'分享活动页到朋友圈、qq,分别+2点福气值(每个平台每天一次)',
'浏览指定课程详情页,一门课程+2点福气值(每天一次)',
'邀请好友注册,+10点福气值/人(无上限)',
'活动期间每购买一门课程+20点福气值',
],
welfareRuleList: [
{
range: '50~100',
rules: [
{id: 1, text: '1.每天一次抽奖机会;'},
{id: 2, text: '2.中奖概率翻2倍', des: '(热力值越高,中奖概率越大);'},
{id: 3, text: '3.满111减11、满1111减111。'},
]
},
{
range: '101~190',
rules: [
{id: 1, text: '1.每天两次抽奖机会;'},
{id: 2, text: '2.中奖概率翻3倍', des: '(热力值越高,中奖概率越大);'},
{id: 3, text: '3.满111减31、满1111减211;'},
{id: 4, text: '4.AI水平测试增加1次。'},
]
},
{
range: '>190',
rules: [
{id: 1, text: '1.每天三次抽奖机会;'},
{id: 2, text: '2.中奖概率翻4倍', des: '(热力值越高,中奖概率越大);'},
{id: 3, text: '3.满111减51、满1111减411;'},
{id: 4, text: '4.AI水平测试增加2次。'},
]
}
],
seconds: 5,
};
}
qqToShare = () => {
const { uid, history } = this.props;
if(getParam('version')) {
if(!uid) {
SendMessageToApp("toLogin");
}else {
SendMessageToApp("QQshare", {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
});
}
}else {
if(!uid) {
history.push('/passport');
}else {
history.push('/blessingPreheat?utm_source=qq&utm_medium=11&utm_campaign=QQ11&utm_content=11&utm_term=11')
this.fetchUserBlessing(3, () => {
this.handleToAddBlessing(3);
});
}
}
}
wechatToShare = () => {
const { uid, history } = this.props;
if(getParam('version')) {
if(!uid) {
SendMessageToApp("toLogin");
}else {
SendMessageToApp("WXshare", {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
});
}
}else {
if(!uid) {
history.push('/passport');
}else {
history.push('/blessingPreheat?utm_source=1&utm_medium=1&utm_campaign=11&utm_content=1&utm_term=1');
this.fetchUserBlessing(1, () => {
this.handleToAddBlessing(1);
});
}
}
}
weiboToShare = () => {
const { uid, history } = this.props;
if(getParam('version')) {
if(!uid) {
SendMessageToApp("toLogin");
}else {
SendMessageToApp("WBshare", {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
});
}
}else {
if(!uid) {
history.push('/passport');
}else {
history.push('/blessingPreheat?utm_source=sina&utm_medium=11&utm_campaign=sina11&utm_content=1&utm_term=11');
this.fetchUserBlessing(2, () => {
this.handleToAddBlessing(2);
});
}
}
}
fetchUserBlessing(key, cb) {
const { handleToShowShare } = this.props;
let { seconds } = this.state;
http.get(`${API.home}/sys/user/blessing`).then(res => {
const { code, data } = res.data;
if(code === 200) {
if(data.today_shared_platforms.some(item => item === key)) {
handleToShowShare();
Toast.info('今日已分享,记得明天来~', 2, null, false);
}else {
handleToShowShare();
this.shareTimer = setInterval(() => {
this.setState(
{
seconds: (--seconds)
},
() => {
if (seconds === 0) {
typeof cb === 'function' && cb();
clearInterval(this.shareTimer);
}
}
);
}, 1000);
}
}
});
}
handleToAddBlessing = (key) => {
http.post(`${API.home}/sys/add/blessing`, {
share_platform: key, // 1 朋友圈 2 微博 3 qq
type: 3 // 1:签到;3:分享;4:浏览课程;
}).then(res => {
const {code } = res.data;
if (code === 200) {
Toast.info('+2点福气值~', 2, null, false);
}
});
}
handleToInvite = () => {
const { uid, history } = this.props;
if(!uid) {
if(getParam('version')) {
SendMessageToApp("toLogin");
}else {
history.push('/passport')
}
}else {
if(getParam('version')) {
history.push('/invite?version=' + getParam('version'))
} else {
history.push('/invite')
}
}
}
render() {
const {
isSign,
userInfo: {blessingVal = 0, buyBlessing = 0, inviteBlessing = 0, isFollow = 0 },
isLogin,
handleToShowNotice,
handleToShowList,
toLogin,
toSection
} = this.props;
const { rules, welfareRuleList, seconds } = this.state;
return (
<div className="collect-blessing">
{
isLogin
? (
<ListHeader text={`我的福气值: ${blessingVal}分`} size="middle" styles={{margin: '20px 0 0 0'}} />
)
: (
<ListHeader size="middle" styles={{margin: '20px 0 0 0'}} >
<span className="text_nologin">我的福气值:</span>
<span onClick={toLogin} className="login__btn">登录</span>
</ListHeader>
)
}
<p className='activity__over'>活动结束前福气榜前50名可获奖品一份</p>
{
welfareRuleList.map((item, index) => (
<div className="rules__item" key={index}>
<div className="item__left">
<div className='tip__bubble'>
<div className="tip__text">福气值</div>
<div className='tip__style'></div>
</div>
<div className='range__number'>{item.range}</div>
</div>
<div className="item__right">
{
item.rules.map(item => {
return (
<p key={item.id}>
{item.text}
<span>{item.des}</span>
</p>
)
})
}
</div>
</div>
))
}
<ListHeader text="福气值积攒规则" size="middle" styles={{margin: '30px 0 0'}} />
{
rules.map((item, index) => (
<div className="collect-blessing__item" key={index}>
<i className="collect-blessing__num">{index+1}</i>
<p className="collect-blessing__title">{item}</p>
{
index === 0 &&
<>
{
(isLogin && isSign)
? (
<button className="collect-blessing__content" data-status="done">
+5<br/>福气值
</button>
)
: (
<button onClick={toLogin} className="collect-blessing__content">
点击<br/>签到
</button>
)
}
</>
}
{
index === 1 &&
<>
{
isFollow === 1
? (
<button className="collect-blessing__content" data-status="done" onClick={handleToShowNotice}>
已加30
</button>
)
: (
<button className="collect-blessing__content" onClick={handleToShowNotice}>
关注<br/>二维码
</button>
)
}
</>
}
{
index === 2 &&
<div className="collect-blessing__content" data-layout="column">
<p className="collect-blessing__label">去分享</p>
<div className="collect-blessing__share">
<button
className="collect-blessing__share-button"
data-type="qq"
onClick={this.qqToShare}
></button>
<button
className="collect-blessing__share-button"
data-type="wechat"
onClick={this.wechatToShare}
></button>
<button
className="collect-blessing__share-button"
data-type="weibo"
onClick={this.weiboToShare}
></button>
</div>
</div>
}
{
index === 3 &&
<button className="collect-blessing__content" onClick={handleToShowList}>
浏览课程<br/>详情页
</button>
}
{
index === 4 &&
<button className="collect-blessing__content" onClick={this.handleToInvite}>
<span>邀请链接</span>
{
inviteBlessing > 0 && <i>已加{inviteBlessing}</i>
}
</button>
}
{
index === 5 &&
<button className="collect-blessing__content" onClick={toSection}>
<span>去选课</span>
{
buyBlessing > 0 && <i>已加{buyBlessing}</i>
}
</button>
}
</div>
))
}
</div>
)
}
}
export default ListFrame(CollectBlessing);
\ No newline at end of file
.collect-blessing {
padding-bottom: 30px;
}
.collect-blessing__item {
display: flex;
align-items: center;
position: relative;
width: 335px;
height: 60px;
margin: 20px auto 0;
border-radius: 5px;
background-color: #fff;
}
.collect-blessing__num {
position: absolute;
top: 0;
left: 0;
width: 25px;
height: 25px;
padding-left: 6px;
box-sizing: border-box;
font-size: 12px;
font-style: normal;
font-weight: bold;
color: #FFFFFD;
line-height: 21px;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/blessing-number-bg.png');
background-size: cover;
}
.collect-blessing__title {
flex: 1;
padding: 0 8px 0 24px;
font-size: 12px;
color: #333;
line-height: 18px;
}
.collect-blessing__content {
display: inline-flex;
flex-direction: column;
align-items: center;
justify-content: center;
width: 64px;
height: 100%;
border-style: none;
border-radius: 5px;
font-size: 12px;
color: #fff;
text-align: center;
background: linear-gradient(-40deg,rgba(255,75,240,1) 0%,rgba(162,0,255,1) 100%);
i {
font-style: normal;
font-size: 12px;
}
&[data-layout="column"] {
flex-direction: column;
}
&[data-status="done"] {
background: rgba(82,92,101,.3);
}
}
.collect-blessing__label {
margin: 0 0 8px;
}
.collect-blessing__share {
display: flex;
align-items: center;
justify-content: center;
}
.collect-blessing__share-button {
display: block;
width: 20px;
height: 11px;
border-style: none;
background-color: transparent;
background-size: auto 100%;
background-repeat: no-repeat;
background-position: center;
&[data-type="qq"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/qq-icon.png');
}
&[data-type="wechat"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/wechat-icon.png');
}
&[data-type="weibo"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/icon-weibo.png');
}
}
.activity__over {
font-size:12px;
font-weight:400;
color:rgba(255,243,240,1);
margin: 10px auto;
text-align: center;
}
.login__btn {
width:34px;
height:18px;
background:linear-gradient(0deg,rgba(255,67,2,1), rgba(255,132,0,1));
border-radius:3px;
color: #FFF;
font-size: 12px;
font-weight: 400;
text-align: center;
margin-right: 12px;
}
.text_nologin {
font-size:16px;
font-weight:600;
color:rgba(255,243,240,1);
margin-left: 12px;
}
.rules__item {
background: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/fuqi_bj1.png') center center no-repeat;
background-size: 100% 100%;
width: 336px;
padding: 18px 18px 10px 18px;
margin: 10px auto 0;
box-sizing: border-box;
display: flex;
flex-direction: row;
justify-content: space-between;
align-items: center;
min-height: 106px;
.item__left {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
width: 90px;
height: 100%;
padding-right: 10px;
.tip__bubble {
position: relative;
margin-bottom: 10px;
.tip__text {
width: 54px;
height: 22px;
background:linear-gradient(90deg,rgba(245,175,172,1) 0%,rgba(241,226,229,1) 100%);
border-radius:3px;
font-weight:400;
line-height: 22px;
text-align: center;
color:rgba(255,67,2,1);
}
.tip__style {
width: 0;
height: 0;
border-left: 6px solid transparent;
border-right: 6px solid transparent;
border-top: 6px solid #F3C9C9;
position: absolute;
bottom: -6px;
left: 50%;
transform: translateX(-50%);
}
}
.range__number {
font-size:16px;
font-weight:500;
color:rgba(255,67,2,1);
}
}
.item__right {
border-left: 1px dashed rgba(255,255,255, .5);
flex: 1 1 auto;
font-size:12px;
font-weight:400;
color:rgba(242,240,250,1);
line-height:15px;
padding: 8px 0 8px 20px ;
p {
margin-bottom: 10px;
line-height: 1;
&:last-child {
margin-bottom: 0;
}
span {
font: size 12px;
font-weight:400;
color:rgba(255,223,4,1);
line-height:15px;
}
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss';
class CourseItem extends Component {
render() {
const { image,toCourse,id} = this.props;
return (
<div className="course-container">
<div className="course__cover">
<img src={image} alt="cover" onClick={() => toCourse(id)}/>
</div>
{this.props.children}
</div>
);
}
}
export default CourseItem;
\ No newline at end of file
.course-container {
width: 168px;
// height: 156px;
margin: 0 4px 15px;
border-radius: 2px;
background-color: #fff;
}
.course__cover {
height: 108px;
padding: 4px 4px 0;
overflow: hidden;
img {
display: block;
width: 100%;
height: 100%;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import { http , getParam, SendMessageToApp} from '@/utils';
import { Toast } from "antd-mobile";
import ListFrame from './../listFrame/index';
import CourseItem from './../courseItem/index';
import ListHeader from './../listHeader';
import './index.scss';
import cookie from "js-cookie";
class CourseList extends Component {
constructor(props) {
super(props);
this.state = {
basic: {
course: [],
courseList: [],
isMore: false,
},
advanced: {
course: [],
courseList: [],
isMore: false,
},
higher: {
course: [],
courseList: [],
isMore: false,
},
expand: {
course: [],
courseList: [],
isMore: false,
},
group: {
course: [],
courseList: [],
isMore: false,
},
training: {
course: [],
courseList: [],
isMore: false,
}
};
}
componentDidMount() {
// 精品课程-集训营、就业班/AI特训营
this.fetchCourseData();
// AI之路-基础
this.fetchAICourse('one');
// AI之路-进阶
this.fetchAICourse('two');
// AI之路-高阶
this.fetchAICourse('three');
// AI之路-拓展
this.fetchAICourse('four');
}
shouldComponentUpdate(nextProps, nextState, nextContext) {
if(this.props.isApp !== nextProps.isApp) {
// 精品课程-集训营、就业班/AI特训营
this.fetchCourseData();
// AI之路-基础
this.fetchAICourse('one');
// AI之路-进阶
this.fetchAICourse('two');
// AI之路-高阶
this.fetchAICourse('three');
// AI之路-拓展
this.fetchAICourse('four');
return false;
}
return true;
}
fetchAICourse = (key) => {
const { basic, advanced, higher, expand } = this.state;
http.get(`${API.home}/sys/ai_grow_up_courses/${key}`).then(res => {
const {code, data} = res.data;
if (code === 200) {
if (data.length > 4) {
if (key === 'one') {
this.setState({
basic: Object.assign({}, basic, {
isMore: true,
course: data.filter((item, index) => index < 4),
courseList: data,
})
});
}
if (key === 'two') {
this.setState({
advanced: Object.assign({}, advanced, {
isMore: true,
course: data.filter((item, index) => index < 4),
courseList: data,
})
});
}
if (key === 'three') {
this.setState({
higher: Object.assign({}, higher, {
isMore: true,
course: data.filter((item, index) => index < 4),
courseList: data,
})
});
}
if (key === 'four') {
this.setState({
expand: Object.assign({}, expand, {
isMore: true,
course: data.filter((item, index) => index < 4),
courseList: data,
})
});
}
} else {
if (key === 'one') {
this.setState({
basic: Object.assign({}, basic, {
isMore: false,
course: data,
courseList: data,
})
});
}
if (key === 'two') {
this.setState({
advanced: Object.assign({}, advanced, {
isMore: false,
course: data,
courseList: data,
})
});
}
if (key === 'three') {
this.setState({
higher: Object.assign({}, higher, {
isMore: false,
course: data,
courseList: data,
})
});
}
if (key === 'four') {
this.setState({
expand: Object.assign({}, expand, {
isMore: false,
course: data,
courseList: data,
})
});
}
}
}
});
}
fetchCourseData = () => {
const { group, training } = this.state;
http.get(`${API.home}/sys/preheat_data`).then(res => {
const {code, data} = res.data;
if (code === 200) {
if (data.excellent_course.length > 2) {
this.setState({
group: Object.assign({}, group, {
isMore: true,
course: data.excellent_course.filter((item, index) => index < 2),
courseList: data.excellent_course,
})
});
} else {
this.setState({
group: Object.assign({}, group, {
isMore: false,
course: data.excellent_course,
courseList: data.excellent_course,
})
});
}
if (data.ai_elite_courses.length > 2) {
this.setState({
training: Object.assign({}, training, {
isMore: true,
course: data.ai_elite_courses.filter((item, index) => index < 2),
courseList: data.ai_elite_courses,
})
});
} else {
this.setState({
training: Object.assign({}, training, {
isMore: false,
course: data.ai_elite_courses,
courseList: data.ai_elite_courses,
})
});
}
}
});
}
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']
};
this.setState({
...data
});
}else {
if(key === 'group' || key === 'training') {
data[key] = {
isMore: !this.state[key]['isMore'],
course: this.state[key]['courseList'].filter((item, index) => index < 2),
courseList: this.state[key]['courseList']
};
}else {
data[key] = {
isMore: !this.state[key]['isMore'],
course: this.state[key]['courseList'].filter((item, index) => index < 4),
courseList: this.state[key]['courseList']
};
}
this.setState({
...data
});
}
}
toReceiveCoupon(id, key = '') {
const {isLogin, toLogin} = this.props;
if(isLogin) {
http.post(`${API.home}/sys/activity/coupon/receive`, {
course_id: id
}).then(res => {
const { code, msg } = res.data;
if(code === 200) {
Toast.info('领取成功~', 2, null, false);
let obj = {};
obj[key] = {
isMore: this.state[key]['isMore'],
course: this.state[key]['course'].map(item => {
if(item.course_id === id) {
return Object.assign({}, item, {
course_status: 2
});
}
return item;
}),
courseList: this.state[key]['courseList'].map(item => {
if(item.course_id === id) {
return Object.assign({}, item, {
course_status: 2
});
}
return item;
}),
}
this.setState({
...obj
});
} else {
Toast.info(msg, 2, null, false);
}
});
}else{
toLogin();
}
}
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 {
let data = {
courseId: courseId,
type: 0 // 正常跳课程详情页type:0,积福气浏览课程详情页-没有浏览过type:1 已浏览过type:2
};
SendMessageToApp("toCourse", data);
}
}
render() {
const { isFormal } = this.props;
const { basic, advanced, higher, expand, group, training } = this.state;
return (
<div className="boutique-course">
<ListHeader text="集训营、就业班" size="middle" styles={{margin: '20px 0 15px'}} />
{/* 集训营、就业班 */}
{
(group.course && group.course.length > 0) &&
<>
<div data-layout="row">
{
group.course.map(item => (
<CourseItem image={item.image_name} key={item.course_id} id={item.course_id} toCourse={this.toCourse}>
<div className="coupon-course__footer">
<a onClick={() => this.toQQque()} className="course-button">立抢超低团购价</a>
</div>
</CourseItem>
))
}
</div>
{
(group.courseList && group.courseList.length > 2) &&
<button className="more-button" onClick={() => this.handleToMore('group')}>
{group.isMore? '展开更多' : '收起'}
</button>
}
</>
}
<ListHeader text="AI特训营" size="middle" styles={{margin: '0 0 15px'}} />
{/* AI特训营 */}
{
(training.course && training.course.length > 0) &&
<>
<div data-layout="row">
{
training.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.course_status === 1 &&
<a
className={classnames("coupon-course__button", "coupon-course__button--receive")}
onClick={() => this.toReceiveCoupon(item.course_id, 'training')}
>
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">立即领券</span>
</a>
}
{
(isFormal === 0 && item.course_status === 2) &&
<a className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">11.11开始使用</span>
</a>
}
{
(isFormal === 1 && item.course_status === 2) &&
<a
onClick={() => this.toCourse(item.course_id)}
className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">开始使用</span>
</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)}
className="course-button"
data-type="study"
>开始学习</a>
}
</div>
</CourseItem>
))
}
</div>
{
(training.courseList && training.courseList.length > 2) &&
<button className="more-button" onClick={() => this.handleToMore('training')}>
{training.isMore? '展开更多' : '收起'}
</button>
}
</>
}
{/* AI成长之路--基础 */}
<ListHeader text="AI成长之路" size="middle" styles={{margin: '0 0 15px'}} />
{
(basic.course && basic.course.length > 0) &&
<>
<h4 className="ai-course__subtitle">基础</h4>
<div data-layout="row">
{
basic.course.map(item => (
<CourseItem image={item.image_name} key={item.course_id} id={item.course_id} toCourse={this.toCourse}>
{
item.type === 0 &&
<div className="coupon-course__footer">
{
item.course_status === 1 &&
<a
className={classnames("coupon-course__button", "coupon-course__button--receive")}
onClick={() => this.toReceiveCoupon(item.course_id, 'basic')}
>
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">立即领券</span>
</a>
}
{
(isFormal === 0 && item.course_status === 2) &&
<a className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">11.11开始使用</span>
</a>
}
{
(isFormal === 1 && item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">开始使用</span>
</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)}
className="course-button"
data-type="study"
>开始学习</a>
}
</div>
}
{
item.type === 1 &&
<div className="cent-course__footer">
{
(item.course_status === 1 || item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button">1分钱开团</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button" data-type="study">开始学习</a>
}
</div>
}
</CourseItem>
))
}
</div>
{
(basic.courseList && basic.courseList.length > 4) &&
<button className="more-button" onClick={() => this.handleToMore('basic')}>
{basic.isMore? '展开更多' : '收起'}
</button>
}
</>
}
{/* AI成长之路--进阶 */}
{
(advanced.course && advanced.course.length > 0) &&
<>
<h4 className="ai-course__subtitle">进阶</h4>
<div data-layout="row">
{
advanced.course.map(item => (
<CourseItem image={item.image_name} key={item.course_id} id={item.course_id} toCourse={this.toCourse}>
{
item.type === 0 &&
<div className="coupon-course__footer">
{
item.course_status === 1 &&
<a
className={classnames("coupon-course__button", "coupon-course__button--receive")}
onClick={() => this.toReceiveCoupon(item.course_id, 'advanced')}
>
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">立即领券</span>
</a>
}
{
(isFormal === 0 && item.course_status === 2) &&
<a className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">11.11开始使用</span>
</a>
}
{
(isFormal === 1 && item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">开始使用</span>
</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)}
className="course-button"
data-type="study"
>开始学习</a>
}
</div>
}
{
item.type === 1 &&
<div className="cent-course__footer">
{
(item.course_status === 1 || item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button">1分钱开团</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button" data-type="study">开始学习</a>
}
</div>
}
</CourseItem>
))
}
</div>
{
(advanced.courseList && advanced.courseList.length > 4) &&
<button className="more-button" onClick={() => this.handleToMore('advanced')}>
{advanced.isMore? '展开更多' : '收起'}
</button>
}
</>
}
{/* AI成长之路--高阶 */}
{
(higher.course && higher.course.length > 0) &&
<>
<h4 className="ai-course__subtitle">高阶</h4>
<div data-layout="row">
{
higher.course.map(item => (
<CourseItem image={item.image_name} key={item.course_id} id={item.course_id} toCourse={this.toCourse}>
{
item.type === 0 &&
<div className="coupon-course__footer">
{
item.course_status === 1 &&
<a
className={classnames("coupon-course__button", "coupon-course__button--receive")}
onClick={() => this.toReceiveCoupon(item.course_id, 'higher')}
>
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">立即领券</span>
</a>
}
{
(isFormal === 0 && item.course_status === 2) &&
<a className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">11.11开始使用</span>
</a>
}
{
(isFormal === 1 && item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">开始使用</span>
</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)}
className="course-button"
data-type="study"
>开始学习</a>
}
</div>
}
{
item.type === 1 &&
<div className="cent-course__footer">
{
(item.course_status === 1 || item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button">1分钱开团</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button" data-type="study">开始学习</a>
}
</div>
}
</CourseItem>
))
}
</div>
{
(higher.courseList && higher.courseList.length > 4) &&
<button className="more-button" onClick={() => this.handleToMore('higher')}>
{higher.isMore? '展开更多' : '收起'}
</button>
}
</>
}
{/* AI成长之路--扩展 */}
{
(expand.course && expand.course.length > 0) &&
<>
<h4 className="ai-course__subtitle">扩展</h4>
<div data-layout="row">
{
expand.course.map(item => (
<CourseItem image={item.image_name} key={item.course_id} id={item.course_id} toCourse={this.toCourse}>
{
item.type === 0 &&
<div className="coupon-course__footer">
{
item.course_status === 1 &&
<a
className={classnames("coupon-course__button", "coupon-course__button--receive")}
onClick={() => this.toReceiveCoupon(item.course_id, 'expand')}
>
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">立即领券</span>
</a>
}
{
(isFormal === 0 && item.course_status === 2) &&
<a className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">11.11开始使用</span>
</a>
}
{
(isFormal === 1 && item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="coupon-course__button">
<span className="coupon-course__button-price">
<em>¥{item.coupon}</em>
<i>代金券</i>
</span>
<span className="coupon-course__button-label">开始使用</span>
</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)}
className="course-button"
data-type="study"
>开始学习</a>
}
</div>
}
{
item.type === 1 &&
<div className="cent-course__footer">
{
(item.course_status === 1 || item.course_status === 2) &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button">1分钱开团</a>
}
{
item.course_status === 3 &&
<a onClick={() => this.toCourse(item.course_id)} className="course-button" data-type="study">开始学习</a>
}
</div>
}
</CourseItem>
))
}
</div>
{
(expand.courseList && expand.courseList.length > 4) &&
<button className="more-button" onClick={() => this.handleToMore('expand')}>
{expand.isMore? '展开更多' : '收起'}
</button>
}
</>
}
</div>
)
}
}
export default ListFrame(CourseList);
.boutique-course {
padding-bottom: 5px;
}
.course-button {
display: block;
width: 138px;
height: 24px;
margin: 0 auto;
border-radius: 2px;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 24px;
background: linear-gradient(90deg,rgba(255,140,27,1) 0%,rgba(255,59,5,1) 100%);
&[data-type="study"] {
background: linear-gradient(269deg,rgba(7,240,255,1) 0%,rgba(0,153,255,1) 100%);
}
}
.coupon-course__footer {
padding: 10px 0;
.course-button {
//margin: 5px auto 0;
}
}
.cent-course__footer {
padding: 15px 0 10px;
}
.coupon-course__button {
display: flex;
align-items: center;
width: 138px;
height: 34px;
margin: 0 auto;
font-size: 12px;
color: #fff;
text-align: center;
line-height: 1;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/coupon-bg-0.png');
background-repeat: no-repeat;
background-size: cover;
}
.coupon-course__button--receive {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/coupon-bg-1.png');
}
.coupon-course__button-price {
flex: 1;
display: inline-flex;
flex-direction: column;
justify-content: center;
align-items: center;
i {
font-size: 8px;
font-style: normal;
}
}
.coupon-course__button-label {
width: 86px;
}
.more-button {
display: block;
width: 100px;
height: 27px;
margin: 0 auto 15px;
padding: 0;
border: 1px solid #fff;
border-radius: 14px;
font-size: 13px;
font-weight: 300;
color: #fff;
line-height: 27px;
background-color: transparent;
cursor: pointer;
outline: none;
}
.ai-course__subtitle {
width: 83px;
height: 24px;
margin: 0 auto 15px;
border-radius: 12px;
font-size: 14px;
font-weight: 500;
color: #fff;
text-align: center;
line-height: 24px;
background: linear-gradient(-90deg,rgba(46,206,240,1) 0%,rgba(45,86,240,1) 100%);
}
[data-layout="row"] {
display: flex;
flex-wrap: wrap;
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import { http, SendMessageToApp } from "@/utils";
import './index.scss';
import { getParam } from '../../../utils';
class CoursePopup extends Component {
constructor(props) {
super(props);
this.state = {
courseList: []
};
}
componentDidMount() {
this.fetchCourseData();
}
fetchCourseData = () => {
Promise.all([
http.get(`${API.home}/sys/browse/blessing/courses`),
http.get(`${API.home}/sys/user/blessing`)
]).then(res => {
const { code, data } = res[0].data;
const doneCourse = res[1].data.data.today_browsed_courses || [];
if(code === 200) {
this.setState({
courseList: data.map(item => {
if(doneCourse.some(id => id == item.course_id)) {
return Object.assign({}, item, {
blessing: 2
});
}
return item;
})
});
}
});
}
toCourseDetail = (item) => {
console.log(this.props);
const {isLogin, history, toLogin} = this.props;
// to={`/detail?id=${item.course_id}&ac=11`}
if(isLogin) {
if(!getParam('version')) {
history.push(`/detail?id=${item.course_id}&ac=11`);
}else{
let type = 0;
if(item.blessing) {
type = 2;
}else{
type = 1;
}
let data = {
courseId: item.course_id,
type: type // 正常跳课程详情页type:0,积福气浏览课程详情页-没有浏览过type:1 已浏览过type:2
}
SendMessageToApp("toCourse", data);
}
}else{
toLogin();
}
}
render() {
const { courseList } = this.state;
const { handleToHide } = this.props;
return (
<div className="course-popup__container">
<div className="course-popup">
<h2 className="course-popup__title">指定课程</h2>
<div className="course-popup__list">
{
courseList.map(item => (
<span
className={classnames("course-popup__item", {
"course-popup__item--active": item.blessing
})}
key={item.course_id}
onClick={()=>{this.toCourseDetail(item)}}
>
<span className="course-popup__name">{item.course_title}</span>
{
item.blessing &&
<span>+2</span>
}
</span>
))
}
</div>
</div>
<i className="iconfont iconiconfront-2" onClick={handleToHide}></i>
</div>
);
}
}
export default CoursePopup;
\ No newline at end of file
.course-popup__container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
.iconfont {
margin: 16px 0 0;
font-size: 28px;
color: #fff;
cursor: pointer;
}
}
.course-popup {
width: 300px;
height: 275px;
padding: 20px 0 0;
border-radius: 10px;
box-sizing: border-box;
background-color: #fff;
}
.course-popup__title {
margin: 0 0 20px;
font-size: 16px;
font-weight: 500;
color: #525C65;
text-align: center;
line-height: 1;
}
.course-popup__list {
height: 190px;
padding: 0 15px;
overflow-y: auto;
}
.course-popup__item {
display: flex;
align-items: center;
justify-content: space-between;
width: 100%;
height: 30px;
padding: 0 10px;
border-radius: 4px;
box-sizing: border-box;
color: rgba(82, 92, 101, .6);
background-color: #E7EDF2;
&:nth-child(n+2) {
margin-top: 10px;
}
&:hover {
color: #fff;
background-color: rgba(0, 153, 255, .6);;
}
}
.course-popup__item--active {
.course-popup__name {
color:rgba(82,92,101,.6);
}
}
.course-popup__name {
width: 200px;
font-size: 12px;
color:rgba(82,92,101,1);
white-space: nowrap;
text-overflow: ellipsis;
overflow: hidden;
}
\ No newline at end of file
import React, { Component } from 'react'
import QRCode from 'qrcode'
import { http, SendMessageToApp, wxShare, is_weixin, getParam } from '@/utils'
import { Link } from 'react-router-dom'
import { throttle, findIndex, debounce } from 'lodash'
import RulePopup from './rulePopup/index'
import CoursePopup from './coursePopup/index'
import RecordPopup from './recordPopup/index'
import CourseList from './courseList/index'
import SharePopup from './sharePopup/index'
import LuckDraw from './luckDraw/index'
import CollectBlessing from './collectBlessing/index'
import ReserveCourse from './ReserveCourse/index'
import ListHeader from './listHeader/index'
import LevelTest from './levelTest/index'
import RankList from './rankList/index'
import './index.scss'
import { Popup } from '@/common'
import { Toast } from "antd-mobile"
import Live from './live'
import Banner from './banner'
import cookie from "js-cookie"
import { setCurrentUser, startFetchUser } from "@/store/userAction"
import { addDays } from "date-fns"
import { compose } from "redux"
import { connect } from "react-redux"
class BlessingPreheat extends Component {
constructor(props) {
super(props)
this.navTop = 183
this.prevY = 0
this.state = {
userInfoList: [],
// userInfoList: [{
// token:'fcfef221e60ab7a2-92a80d5d30196999',
// uid:'545292',
// uname:'xzhtest2',
// avatar_file:''
// }],
isRule: false,
isCourse: false,
inviteUrl: '',
inviteVisible: false,
joinLotteryVisible: false,
timelineShareVisible: false,
showRecordList: false,
isFormal: false, // 1正式 0 预热
isServer: false,
serverUrl: '',
shareMark: false,
userInfo: {},
isSign: false,
navs: [
{
text: '积福气',
id: 'lucky-value'
},
{
text: '幸运大抽奖',
id: 'lucky-draw'
},
{
text: '预付定金',
id: 'deposit'
},
{
text: '精品特惠',
id: 'best-courses'
},
{
text: 'AI测试',
id: 'ai-test'
},
{
text: '大咖直播',
id: 'live'
},
],
index: 0,
userHasError: props.user.hasError,
isApp: false,
isClose: false,
testSum: 0,
}
}
componentDidMount() {
this.fetchUserBlessing()
this.setInitialNavActiveStatus()
window.addEventListener('scroll', throttle(this.calcNavActive, 100))
if (is_weixin()) {
wxShare({
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: window.location.href,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
})
}
// 获取App登录信息
window['loginInfo'] = result => {
this.loginInfo(result)
}
window['getNewData'] = result => {
this.fetchUserBlessing()
}
window['QQWXWBshare'] = result => {
http.post(`${API.home}/sys/add/blessing`, {
share_platform: result, // 1 朋友圈 2 微博 3 qq
type: 3 // 1:签到;3:分享;4:浏览课程;
}).then(res => {
const {code} = res.data
if (code === 200) {
Toast.info('+2点福气值~', 2, null, false)
this.fetchUserBlessing()
}
})
}
}
// 获取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.fetchUserBlessing()
this.setState({
isApp: 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
}
getActiveIndex = (arr, n) => {
for (let i = 0, len = arr.length; i < len; i++) {
if (arr[i] > n) {
if (!i) {
return i
} else {
if (Math.abs(n - arr[i]) < Math.abs(n - arr[i - 1])) {
return i
} else {
return i - 1
}
}
}
}
}
fetchMoudleId = (str) => {
const {navs} = this.state
return findIndex(navs, item => item.id === str)
}
setInitialNavActiveStatus = () => {
const observer = new MutationObserver(debounce((list, observer) => {
const navs = this.state.navs.map(item => document.querySelector(`#${item.id}`))
if (navs.every(item => item)) {
const navsTop = navs.map(item => item.offsetTop)
const index = this.getActiveIndex(navsTop, window.pageYOffset)
this.setState({index, navsTop}, () => {
this.calcNavActive()
observer.disconnect()
})
}
}, 30))
observer.observe(document.querySelector('#blessing-preheat'), {childList: true, subtree: true})
}
initNav = (isFormal) => {
const {navs} = this.state
if (isFormal) {
this.setState({
navs: navs.filter(item => item.id !== 'deposit')
})
}
}
fetchMoudleId = (str) => {
const {navs} = this.state
return findIndex(navs, item => item.id === str)
}
fetchUserBlessing = () => {
const {userInfo} = this.state
http.get(`${API.home}/sys/user/blessing`).then(res => {
const {code, data} = res.data
if (code === 200) {
this.setState({
isSign: !!data.today_signed,
isFormal: data.is_activity,
testSum: parseInt(data.user_test_total, 10) || 0,
userInfo: Object.assign({}, userInfo, {
isFollow: data.subscribed,
blessingVal: data.user_blessing_value,
buyBlessing: (data.types_total_blessing_value && data.types_total_blessing_value.buy_course) ? data.types_total_blessing_value.buy_course : 0,
inviteBlessing: (data.types_total_blessing_value && data.types_total_blessing_value.invite) ? data.types_total_blessing_value.invite : 0,
})
})
if (data.is_login === 1) {
this.handleToSign()
}
this.initNav(data.is_activity)
}
})
}
handleToAddBlessing = (key) => {
http.post(`${API.home}/sys/add/blessing`, {
share_platform: key, // 1 朋友圈 2 微博 3 qq
type: 3 // 1:签到;3:分享;4:浏览课程;
}).then(res => {
const {code} = res.data
if (code === 200) {
Toast.info('+2点福气值~', 2, null, false)
}
})
}
handleToSign = () => {
const { userInfo } = this.state;
http.post(`${API.home}/sys/add/blessing`, {
type: 1 // 1:签到;3:分享;4:浏览课程;
}).then(res => {
const {code} = res.data
if (code === 200) {
this.setState({
isSign: true,
userInfo: Object.assign({}, userInfo, {
blessingVal: userInfo.blessingVal + 5
})
});
Toast.info('+5点福气值~', 2, null, false)
}
})
}
handleToHide = (key) => {
let obj = {}
obj[key] = false
this.setState({
...obj
})
}
handleToShow = (key, isLogin = false) => {
// 需要用户登录 并且用户未登录
const isLoginnew = !this.props.user.hasError
if (isLogin && !isLoginnew) {
this.toLogin()
} else {
if(key === 'shareMark') {
this.setState({
isClose: false
});
setTimeout(() => {
this.setState({
isClose: true
});
}, 5000);
}
let obj = {}
obj[key] = true
this.setState({
...obj
})
}
}
handleToShowNotice = () => {
http.get(`${API['base-api']}/sys/activity/create_blessing_qrcode`).then(res => {
const {errno, data, msg} = res.data;
if (errno === 200) {
QRCode.toDataURL(data.url, {
width: 120,
height: 120,
margin: 1
}).then(url => {
Popup({
title: '扫码关注“七月在线”服务号',
content: <img src={url} alt="barcode" className="qr-code"/>,
className: 'invite-popup'
})
})
.catch(err => {
console.error(err)
})
} else if (errno === 4030 || errno === 4040) {
this.toLogin()
}else {
Toast.info(msg, 2, null, false);
}
})
}
toLogin = () => {
const {history} = this.props
if (!getParam('version')) {
history.push('/passport')
} else {
SendMessageToApp("toLogin")
}
}
onCopy = () => {
Toast.info('复制成功', 2, null, false)
}
toSection = (i, e) => {
const {navs} = this.state
e.preventDefault()
let top = document.querySelector(`#${navs[i].id}`).offsetTop
this.setState({
index: i
})
window.scrollTo({
top: top - 60,
left: 0
})
}
calcNavActive = () => {
const {navs, index} = this.state
const y = window.scrollY
let swipeDirection = y > this.prevY ? 'up' : 'down'
let _index
if (swipeDirection === 'up') {
_index = (index + 1) >= navs.length ? index : index + 1
} else {
_index = (index - 1) <= 0 ? 0 : index - 1
}
let el = document.querySelector(`#${navs[_index].id}`)
let nav = document.querySelector('#main-nav')
if (el) {
let top = el.offsetTop
if (y <= this.navTop) {
nav.classList.remove('fixed')
} else {
!nav.classList.contains('fixed') && nav.classList.add('fixed')
}
if (swipeDirection === 'up') {
if (y + 30 + 30 >= top) {
this.setState({
index: _index
})
}
} else {
if (y + 30 + 20 <= top) {
this.setState({
index: _index
})
}
}
this.prevY = y
}
}
render() {
const {
navs,
userInfo,
isRule,
isCourse,
isFormal,
isSign,
showRecordList,
shareMark,
index,
isApp,
isClose,
testSum
} = this.state;
const {history} = this.props
const isLogin = !this.props.user.hasError
return (
<div id={'blessing-preheat'}>
<Banner
isFormal={isFormal}
navs={navs}
toSection={this.toSection}
index={index}
/>
{/* 积福气 */}
<ListHeader id={'lucky-value'} text="积福气,享受更多福利" styles={{margin: '60px 0 15px'}}/>
<Link className="luck-draw__button" to="/blessingRank">福气排行榜></Link>
<CollectBlessing
isSign={isSign}
userInfo={userInfo}
isLogin={isLogin}
history={this.props.history}
toSection={(e) => this.toSection(this.fetchMoudleId('best-courses'), e)}
handleToShowList={() => this.handleToShow('isCourse')}
handleToShowNotice={this.handleToShowNotice}
toLogin={this.toLogin}
handleToShowShare={() => this.handleToShow('shareMark')}
/>
{/* 幸运大抽奖--预热 */}
<ListHeader id={'lucky-draw'} text="幸运大抽奖" styles={{margin: '30px 0 10px'}}/>
<p className="luck-draw__tip">- 将于111110点开启 -</p>
<button className="luck-draw__button" onClick={() => this.handleToShow('isRule')}>活动规则></button>
<LuckDraw/>
{/*定金--只在预热期间显示*/}
{
isFormal === 0 &&
<>
<ListHeader id={'deposit'} text="预付1元定金,最高可省100元" styles={{margin: '30px 0 15px'}}/>
<ReserveCourse isApp={isApp}/>
</>
}
{/* 精品课程特惠专区 */}
<ListHeader id={'best-courses'} text="精品课程特惠专区" styles={{margin: '30px 0 15px'}}/>
<CourseList
isApp={isApp}
isFormal={isFormal}
isLogin={isLogin}
history={this.props.history}
toLogin={this.toLogin}
/>
{
isRule &&
<RulePopup handleToHide={() => this.handleToHide('isRule')}/>
}
{
isCourse &&
<CoursePopup toLogin={this.toLogin} history={history} isLogin={isLogin}
handleToHide={() => this.handleToHide('isCourse')}/>
}
{
showRecordList &&
<RecordPopup handleToHide={() => this.handleToHide('showRecordList')}/>
}
{
shareMark &&
<SharePopup isClose={isClose} toClose={() => this.handleToHide('shareMark')}/>
}
{/*
<Popup visible={this.state.joinLotteryVisible}
title={'你已成功参与本时段抽奖'}
className={'join-lottery'}
>
<div className="text">
<div className="code">抽奖码为:99999999</div>
<div className="time">本时段的中奖结果将在xx:xx公布</div>
<div className="hint">你可关注‘七月在线’服务号第一时间获得中奖信息。</div>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/tinypng-common/right_weixin.png"
className='qr-code' alt=""/>
</div>
<button onClick={() => {
this.setState({joinLottery: false})
}}>知道了
</button>
</Popup>
<Popup title={'微信扫码分享到微信朋友圈'}
visible={this.state.timelineShareVisible}
className={'timeline-share'}
>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/tinypng-common/right_weixin.png" alt=""
className="qr-code"/>
</Popup>*/}
<ListHeader id={'ai-test'} text="全国AI工程师水平测试" styles={{margin: '30px 0 15px'}}/>
<div className="test__record" onClick={() => this.handleToShow('showRecordList', true)}>
测试记录>
</div>
<LevelTest
history={history}
testSum={testSum}
isLogin={isLogin}
toLogin={this.toLogin}
/>
<RankList></RankList>
<Live isFormal={isFormal} isLogin={isLogin}></Live>
</div>
)
}
}
export default compose(
connect(
state => ({user: state.user}),
{setCurrentUser, startFetchUser}
)
)(BlessingPreheat)
#blessing-preheat {
background: #5327FA;
}
.timeline-share{
height: 215px;
padding-bottom: 30px;
.title{
margin-bottom: 20px;
}
.content{
text-align: center;
.qr-code{
width: 120px;
height: 120px;
}
}
}
.test__record {
width: 106px;
height: 26px;
border:1px solid rgba(255,246,4,1);
border-radius:13px;
font-size:14px;
font-weight:400;
color:rgba(255,246,4,1);
margin: 10px auto 14px;
display: flex;
justify-content: center;
align-items: center;
}
.sort__rules {
font-size:12px;
font-weight:400;
color:rgba(255,255,255,1);
text-align: center;
text-align-last: center;
}
.join-lottery {
background: #5327FA;
text-align: center;
.title {
color: #fff;
margin-bottom: 15px;
}
.text {
width: 275px;
height: 248px;
padding: 36px 30px 0;
margin-bottom: 10px;
text-align: center;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/join-lottery-bg.png");
background-size: contain;
font-size: 14px;
.code {
color: #FF0000;
margin-bottom: 8px;
}
.time, .hint {
font-size: 12px;
color: #525C65;
}
.time {
margin-bottom: 20px;
}
.hint{
color: rgba(82, 92, 101, .8);
margin-bottom: 10px;
text-align: left;
}
.qr-code {
width: 90px;
height: 90px;
}
}
button {
width: 133px;
height: 30px;
background: #fff;
border-radius: 15px;
font-size: 14px;
color: #5327FA;
-webkit-appearance: none;
outline: none;
border: none;
}
}
.invite-popup {
.content {
display: flex;
flex-flow: column;
align-items: center;
margin-top: 29px;
.qr-code {
width: 120px;
height: 120px;
margin-bottom: 20px;
}
button {
width: 133px;
height: 30px;
background: rgba(83, 39, 250, 1);
border-radius: 15px;
font-size: 14px;
color: #fff;
-webkit-appearance: none;
outline: none;
border: none;
}
}
}
// 幸运大抽奖--预热
.luck-draw__tip {
margin: 0 0 10px;
font-size: 12px;
color: #FFF604;
text-align: center;
}
.luck-draw__button {
display: block;
width: 106px;
height: 26px;
margin: 0 auto 15px;
padding: 0;
border: 1px solid #FFF604;
border-radius: 13px;
box-sizing: border-box;
font-size: 13px;
color: #FFF604;
text-align: center;
line-height: 24px;
background-color: transparent;
cursor: pointer;
outline: none;
}
import React, { Component } from 'react'
import './index.scss'
import listFrame from './../listFrame/index';
import { http, SendMessageToApp} from "@/utils"
class LevelTest extends Component {
constructor(props) {
super(props);
this.state = {
testNumber: '',
number: 1,
prizeListUrl: [
{
url:
"https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/AIExam/top1.png"
},
{
url:
"https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/AIExam/top2.png"
},
{
url:
"https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/AIExam/top3-4.png"
},
{
url:
"https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/AIExam/top5-7.png"
},
{
url:
"https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/AIExam/top8-10.png"
}
],
}
}
componentDidMount() {
const {isLogin} = this.props;
if(isLogin) {
http.get(`${API.home}/sys/ai_test/get_user_testinfo`).then(res => {
let {code, data: {user_test_total, user_residue_number}} = res.data;
if(code === 200) {
this.setState({
testNumber: user_test_total,
number: user_residue_number
})
}
});
}
}
startTest = () => {
const {history, isLogin, toLogin} = this.props;
if(isLogin) {
// history.push('/levelTest/test');
// if(getParam('version')) {
window.location.href = `${API.m}/levelTest/test`;
// }else{
// history.push('/levelTest/test');
// }
}else{
toLogin();
}
}
render() {
let {
testNumber,
number,
prizeListUrl,
} = this.state;
const {isLogin, testSum} = this.props;
return (
<>
<div className="level__test_module">
<div className='start__test' onClick={this.startTest}>
<img className='test-img' src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/test_icon.png" />
<div className="button__text">
<p>点击测试</p>
</div>
</div>
<div className='test__number'>
已有
<span className='number'>
{testNumber || testSum}
</span>
人参加测试
</div>
<div className='prize__rules'>
<div className="prize__title"> 活动奖品 </div>
<div className="prize__list">
{
prizeListUrl.map((item, index) => {
return (
<div className='prize__container' key={index}>
<img src={item.url} />
</div>
)
})
}
</div>
<div className="prize__title"> 活动规则 </div>
<div className="rules__text">
<p>1. 115日至1113日之间每人有一次测试机会,可通过“集福气”活动额外获得2次测试机会;</p>
<p>2. 单次测试时间为一小时,超时自动提交试卷;</p>
<p>3. 试卷内容为Python基础(8道题*3分)、机器学习(12道题*3分)、深度学习(10道题*4分),总分100分;</p>
<p>4. 无固定试卷,参与测试时从试题库中随机抽题组卷;</p>
<p>5. 排行榜实时更新,分数相同则用时短者排名更高,多次测试保留最高分;</p>
<p>6. 如发现某账号有作弊嫌疑,七月在线有权清空账号测试成绩;</p>
<p>7. 活动最终解释权归七月在线所有。</p>
</div>
</div>
</div>
</>
)
}
}
export default listFrame(LevelTest)
.level__test_module {
width: 100%;
// height:580px;
padding-bottom: 20px;
.start__test {
width:174px;
height:33px;
background:linear-gradient(-90deg,rgba(255,140,27,1) 0%,rgba(255,59,5,1) 100%);
border-radius:17px;
margin: 20px auto 8px;
display: flex;
justify-content: center;
align-items: center;
font-size:14px;
font-weight:500;
color:rgba(255,255,255,1);
.button__text {
font-size:14px;
font-weight:500;
color:rgba(255,255,255,1);
display: flex;
flex-direction: row;
justify-content: center;
align-items: baseline;
margin-left: 5px;
span {
font-size:12px;
}
}
.test-img {
width: 14px;
height: 14px;
}
}
.test__number {
font-size:12px;
font-weight:400;
color:rgba(255,255,255,1);
margin: 0 auto;
display: flex;
justify-content: center;
align-items: baseline;
.number {
font-size: 16px;
margin: 0 5px;
}
}
.prize__rules {
width:335px;
// height:461px;
background:rgba(89,112,255,1);
border-radius:5px;
margin: 16px auto;
padding: 15px 10px;
.prize__title {
font-size:14px;
font-weight:400;
color:rgba(255,255,255,1);
text-align: center;
text-align-last: center;
margin-bottom: 10px;
}
.prize__list {
display: flex;
flex-direction: row;
justify-content: flex-start;
align-items: flex-start;
flex-wrap: wrap;
margin-bottom: 16px;
.prize__container {
width: 100px;
height: 100px;
margin: 0 6px 8px 0;
&:nth-child(3n) {
margin: 0 0 8px 0;
}
}
}
.rules__text {
font-size:12px;
font-weight:400;
color:rgba(240,241,255,1);
line-height:17px;
}
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss';
function ListFrame(WrappedComponent) {
return class extends Component {
render() {
return (
<div className="list-frame">
<div className="list-frame__content">
<WrappedComponent {...this.props}/>
</div>
</div>
)
}
};
}
export default ListFrame;
.list-frame {
margin: 0 10px;
border: 1px solid #5970FF;
border-radius: 5px;
background-color: #3900C9;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/frame-bg-top.png');
background-repeat: no-repeat;
}
.list-frame__content {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/frame-bg-bottom.png');
background-repeat: no-repeat;
background-position: bottom right;
}
\ No newline at end of file
import React, { Component } from 'react';
import classnames from 'classnames';
import './index.scss';
class ListHeader extends Component {
render() {
const { text, size, styles, id } = this.props;
const cls = size? `list-header--${size}` : '';
return (
<div id={id} className={classnames("list-header", cls)} style={styles}>
<i className="list-header__decorate" data-position="left"></i>
{
text
? <h2 className="list-header__content">{text}</h2>
: this.props.children
}
<i className="list-header__decorate" data-position="right"></i>
</div>
)
}
}
export default ListHeader;
.list-header {
display: flex;
align-items: center;
justify-content: center;
}
.list-header--middle {
.list-header__decorate {
width: 25px;
height: 12px;
}
.list-header__content {
padding: 0 12px;
font-size: 16px;
font-weight: 500;
color: #fff;
}
}
.list-header__decorate {
display: inline-block;
width: 37px;
height: 18px;
background-size: cover;
&[data-position="left"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/list-header-l.png');
}
&[data-position="right"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/list-header-r.png');
}
}
.list-header__content {
margin: 0;
padding: 0 15px;
font-size: 18px;
font-weight: 600;
color: #FFF604;
line-height: 1;
}
\ No newline at end of file
import React, { Component } from 'react'
import './index.scss'
import { Tabs, Toast } from "antd-mobile"
import { getParam, http, SendMessageToApp, browser } from "@/utils"
import { Popup } from "@common/index"
import QRCode from 'qrcode'
import { uniqBy } from 'lodash'
import { connect } from 'react-redux'
import { withRouter } from 'react-router-dom'
@connect(state => ({user: state.user}))
class Live extends Component {
popupInstance = null
state = {
tabs: [],
lives: {},
preheatLives: [],
today: '',
isApp: getParam('version'),
QRCodeUrl: '',
}
componentDidMount() {
http.get(`${API.home}/sys/get_live_info`)
.then(res => {
const {data} = res
if (data.code == 200) {
const lives = data.data['data_active'].reduce((accu, current) => {
if (!(current.date in accu)) {
accu[current.date] = [current]
} else {
accu[current.date].push(current)
}
return accu
}, {})
const preheatLives = data.data['data_hot'].reduce((accu, current) => {
if (!(current.date in accu)) {
accu[current.date] = [current]
} else {
accu[current.date].push(current)
}
return accu
}, {})
let tabs, today
if (this.props.isFormal) {
tabs = Object.keys(lives).map(item => ({title: item}))
today = uniqBy(data.data['data_active'], value => value.date).findIndex(item => item['is_today'])
} else {
tabs = Object.keys(preheatLives).map(item => ({title: item}))
today = uniqBy(data.data['data_hot'], value => value.date).findIndex(item => item['is_today'])
}
this.setState({
tabs,
lives,
today,
preheatLives
})
} else {
Toast.info(data.msg, 2, null, false)
}
})
}
toLiveRoom = id => {
const {history, isLogin} = this.props
if (this.state.isApp) {
if (isLogin) {
SendMessageToApp('toLiveRoom', id)
} else {
SendMessageToApp("toLogin")
}
} else {
if (isLogin) {
window.location.href = `${window.location.protocol}//www.julyedu.com/live/m_room/${id}`
} else {
history.push('/passport')
}
}
}
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)
}
}
makeSubscribe = id => {
const {user, history} = this.props
if (user.hasError) {
history.push('/passport/login')
}
http.get(`${API['base-api']}/sys/createLiveQrcode/${id}`)
.then(res => {
const {data} = res
if (data.errno == 200) {
this.setState(() => ({
QRCodeUrl: data.data.url,
}))
QRCode.toDataURL(data.data.url, (err, url) => {
if (!this.popupInstance) {
this.popupInstance = Popup({
title: '扫码关注“七月在线”服务号即可预约',
content: (
<>
<img id={'live-qr-code'} src={url} alt=""/>
{
browser.isAndroidApp ? (
<button className={'save-image'} onClick={this.saveImage}>保存二维码</button>
) : null
}
</>
),
close: () => new Promise(resolve => {
this.popupInstance = null
resolve()
})
})
}
})
} else {
Toast.info(data.msg, 2, null, false)
}
})
}
render() {
const {tabs, lives, preheatLives, today} = this.state
return (
<div id={'live'}>
<div className="title">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/title-decorate-left.png" alt=""/>
<span>大咖直播</span>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/title-decorate-right.png" alt=""/>
</div>
<div className="live-container">
{
today !== '' &&
<Tabs
tabs={tabs}
tabBarBackgroundColor={'transparent'}
tabBarActiveTextColor={'#5600DF'}
tabBarInactiveTextColor={'#FFF604'}
tabBarUnderlineStyle={{display: 'none'}}
initialPage={today}
swipeable={false}
>
{
this.props.isFormal
? tabs.map((item, index) => {
const todayLives = lives[item.title]
return (
<div key={index}>
{
todayLives.map((item, index) => {
return (
<LiveContent item={item} key={index} makeSubscribe={this.makeSubscribe}
toLiveRoom={this.toLiveRoom}/>
)
})
}
</div>
)
})
: tabs.map((item, index) => {
const todayLives = preheatLives[item.title]
return (
<div key={index}>
{
todayLives.map((item, index) => {
return (
<LiveContent item={item} key={index} makeSubscribe={this.makeSubscribe}
toLiveRoom={this.toLiveRoom}/>
)
})
}
</div>
)
})
}
</Tabs>
}
</div>
</div>
)
}
}
function LiveContent({item, makeSubscribe, toLiveRoom}) {
return (
<div className="content">
{
item['is_teacher']
? <div className="tag teacher">讲师分享</div>
: <div className="tag student">学员分享</div>
}
<div className="person-info">
<div className="left">
<img
src={item.avatar}
alt="头像"
className="avatar"/>
</div>
<div className="right">
<div className="name">讲师:{item['teacher']}</div>
<div className="profession">{item['teacher_desc']}</div>
</div>
</div>
<div className="title">{item.title}</div>
<div className="time">直播时间:{item.time}</div>
<div className="outline">
<div className="outline-title">内容大纲:</div>
<ul>
{
item['content'].map((content, index) => {
return <li key={index}>{content}</li>
})
}
</ul>
</div>
{
item['on_live']
? <button className={'on-living'} onClick={() => {
toLiveRoom(item['room_url'])
}}>正在直播</button>
:
item['is_end']
? <button className={'subscribed'}>已结束</button>
: item['is_subscribe']
? <button className={'subscribed'}>已预约</button>
: <button className={'subscribe'}
onClick={makeSubscribe.bind(this, item['live_id'])}>立即预约</button>
}
</div>
)
}
export default withRouter(Live)
#live {
margin-top: 30px;
.title {
display: flex;
justify-content: center;
align-items: center;
font-size: 18px;
color: #FFF604;
text-align: center;
margin-bottom: 20px;
span {
margin: 0 15px;
}
img {
width: 37px;
height: 18px;
}
}
.live-container {
width: 355px;
margin: 0 auto;
background: rgba(57, 0, 201, 1);
border: 1px solid rgba(89, 112, 255, 1);
border-radius: 5px;
padding-bottom: 30px;
.content {
position: relative;
width: 325px;
height: 312px;
padding: 26px 30px 0;
margin-top: 50px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/live-bg.png") no-repeat;
background-size: contain;
color: #333;
text-align: center;
overflow: hidden;
}
.tag {
position: absolute;
right: -75px;
top: 10px;
width: 200px;
height: 36px;
font-size: 11px;
color: #fff;
line-height: 36px;
text-align: center;
transform: rotate(45deg);
&.teacher {
background: linear-gradient(rgba(178, 47, 175, 1) 0%, rgba(246, 64, 152, 1) 100%);
}
&.student {
background: linear-gradient(rgba(10, 72, 245, 1) 0%, rgba(0, 153, 255, 1) 100%);
}
}
.person-info {
display: flex;
}
.name {
color: #3900C9;
font-size: 20px;
text-align: left;
}
.avatar {
width: 55px;
height: 55px;
margin-right: 20px;
border-radius: 50%;
border: 1px solid #5970FF;
overflow: hidden;
img {
width: 100%;
height: 100%;
}
}
.profession {
color: #666;
font-size: 12px;
}
.title {
font-size: 15px;
color: #333;
text-align: left;
margin-bottom: 10px;
display: block;
}
.time {
margin-bottom: 10px;
color: #666;
font-size: 12px;
text-align: left;
}
.outline {
text-align: left;
margin-bottom: 10px;
&-title {
font-size: 14px;
margin-bottom: 6px;
}
li {
font-size: 11px;
color: #666;
}
}
button {
position: absolute;
bottom: 20px;
left: 50%;
margin-left: -67px;
width: 134px;
height: 33px;
border: none;
border-radius: 17px;
outline: none;
font-size: 15px;
color: #fff;
&.subscribe {
padding-left: 25px;
background: linear-gradient(90deg, rgba(255, 140, 27, 1) 0%, rgba(255, 59, 5, 1) 100%);
&::before {
content: '';
display: block;
position: absolute;
left: 25px;
top: 9px;
width: 15px;
height: 15px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/subscribe-icon.png") no-repeat;
background-size: contain;
}
}
&.subscribed {
background: #CBCED0;
}
&.on-living {
padding-left: 25px;
background: linear-gradient(-90deg, rgba(7, 240, 255, 1) 0%, rgba(0, 153, 255, 1) 100%);
&::before {
content: '';
display: block;
position: absolute;
top: 10px;
left: 25px;
width: 11px;
height: 12px;
background: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/live-play-icon.png") no-repeat;
background-size: contain;
}
}
}
}
.am-tabs {
width: 330px;
margin: 0 auto;
color: #fff;
& .am-tabs-default-bar-tab:nth-last-of-type(2) {
&::after {
display: none;
}
}
.am-tabs-tab-bar-wrap {
height: 33px;
}
.am-tabs-default-bar-tab {
height: auto;
line-height: 1;
&::after {
content: '';
display: block;
position: absolute;
right: 0;
left: unset;
top: 50%;
margin-top: -7px;
width: 1px;
height: 14px;
background: #FFF604;
transform: none;
}
}
.am-tabs-default-bar-tab-active {
background: #FFF604;
border-radius: 0 0 5px 5px;
}
.am-tabs-default-bar-top{
.am-tabs-default-bar-content{
border: 1px solid rgba(255, 246, 4, 1);
border-radius: 0 0 6px 6px;
}
}
}
}
.popup-container {
.title {
color: #525C65;
}
.content {
display: flex;
flex-direction: column;
align-items: center;
img {
width: 120px;
height: 120px;
margin-top: 10px;
}
}
.save-image {
width: 133px;
height: 30px;
margin-top: 16px;
background: rgba(83, 39, 250, 1);
border-radius: 15px;
font-size: 14px;
color: #fff;
-webkit-appearance: none;
outline: 0;
border: none;
}
}
import React, { Component } from 'react';
import { http } from '@/utils';
import { Tabs } from 'antd-mobile';
import ListFrame from './../listFrame/index';
import './index.scss';
class LuckDraw extends Component {
constructor(props) {
super(props);
this.state = {
tabs: [],
prizes: []
};
}
componentDidMount() {
this.fetchActivityPrize();
}
fetchActivityPrize = () => {
http.get(`${API.home}/sys/activity/prize_data`).then(res => {
const { code , data: { list = [] } } = res.data;
if(code === 200) {
this.setState({
tabs: list.map(item => {
return {
title: item.date
}
}),
prizes: list
});
}
});
}
render() {
const { tabs, prizes } = this.state;
return (
<div className="luck-draw__container">
<Tabs swipeable={false}
tabs={tabs}
tabBarBackgroundColor="transparent"
tabBarUnderlineStyle={{
display: 'none'
}}
>
{
prizes.map(({ son }, index) => {
return (
<div className="tab__body" key={index}>
{
son.map(val => (
<div key={val.id}>
<h2 className="prize__label">
<i className="prize__label-icon"></i>
<span>{val.time}</span>
</h2>
<div className="prize__content">
{
val.data.map((v, k) => (
<div className="prize__container" key={`${val.id}-${k}`}>
<div className="prize__image">
<img src={v.img} alt="image"/>
</div>
<p className="prize__desc">{v.name}</p>
<p className="prize__desc">*{v.num}</p>
</div>
))
}
</div>
</div>
))
}
</div>
)
})
}
</Tabs>
</div>
)
}
}
export default ListFrame(LuckDraw);
\ No newline at end of file
.luck-draw__container {
.am-tabs {
width: 330px;
margin: 0 auto;
color: #fff;
.am-tabs-tab-bar-wrap {
height: 33px;
border: 1px solid rgba(255, 246, 4, 1);
border-radius: 0 0 6px 6px;
.am-tabs-default-bar {
.am-tabs-default-bar-tab:nth-of-type(3) {
&::after {
display: none;
}
}
.am-tabs-default-bar-tab {
height: auto;
line-height: 1;
&::after {
content: '';
display: block;
position: absolute;
right: 0;
left: unset;
top: 50%;
margin-top: -7px;
width: 1px !important;
height: 14px;
background: #FFF604;
transform: none;
}
}
.am-tabs-default-bar-tab-active {
background: #FFF604;
border-radius: 0 0 6px 6px;
}
}
}
}
}
.tab__body {
padding-bottom: 19px;
}
.prize__label {
display: flex;
align-items: center;
justify-content: center;
width: 125px;
height: 24px;
margin: 20px auto 0;
border-radius: 12px;
font-size: 12px;
font-weight: 500;
color: #fff;
background: linear-gradient(269deg,rgba(7,240,255,1) 0%,rgba(0,153,255,1) 100%);
}
.prize__label-icon {
width: 12px;
height: 14px;
margin-right: 7px;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/icon-clock.png');
background-size: cover;
}
.prize__content {
display: flex;
flex-wrap: nowrap;
padding: 10px 7px 0 0;
overflow-y: auto;
}
.prize__image {
width: 100px;
height: 78px;
margin: 0 3px 10px;
padding: 2px;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/prize-border.png');
background-size: cover;
overflow: hidden;
img {
display: block;
width: 100%;
height: 100%;
}
}
.prize__desc {
width: 100px;
font-size: 12px;
color: #fff;
white-space: nowrap;
text-overflow: ellipsis;
text-align: center;
line-height: 15px;
overflow: hidden;
}
\ No newline at end of file
import React, { Component } from 'react'
import './index.scss'
import {http} from "@/utils"
import ListHeader from './../listHeader';
export default class RankList extends Component {
constructor(props) {
super(props);
this.state = {
rankList: []
}
}
componentDidMount() {
http.get(`${API.home}/sys/ai_test/ranking/10`).then(res => {
let data = res.data.data;
let code = res.data.code;
if(code === 200) {
this.setState({
rankList: data.rankings
})
}
});
}
formart = (time) => {
let date = time * 1000,
hours = 0,
minutes = 0,
seconds = 0;
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);
return `${minutes}'${seconds}"`;
}
render() {
let {rankList} = this.state;
return (
<>
<ListHeader text="测试排行榜" styles={{margin: '20px 0 10px'}} size='middle' />
<div className="sort__rules">
仅显示前10
</div>
<div className="rank__list_module">
<div className="rank__table_head">
<div className="table_head table_head__sort">排名</div>
<div className="table_head table_head__user_info">用户</div>
<div className="table_head table_head__time">用时</div>
<div className="table_head table_head__score">成绩</div>
<div className="table_head table_head__prize">奖品</div>
</div>
<div className="rank__table_body">
{
rankList.map((item, index)=>{
return (
<div className="table__tr" key={index}>
<div className='table__body table_head__sort'>
{
index > 2 ? (index + 1) : (
null
)
}
</div>
<div className='table__body table_head__user_info'>
<img className="user__avatar" src={item.avatar} />
<span className="user__name">{item.user_name}</span>
</div>
<div className='table__body table_head__time'>{this.formart(item.cost_time)}</div>
<div className='table__body table_head__score'>{item.score}</div>
<div className='table__body table_head__prize'>{item.prize}</div>
</div>
)
})
}
</div>
</div>
</>
)
}
}
.rank__list_module {
width:366px;
height:523px;
background:rgba(71,28,230,1);
border-radius:6px;
margin: 16px auto 0;
.rank__table_head {
width: 100%;
height:38px;
background:rgba(89,112,255,1);
border-radius:5px 5px 0px 0px;
display: flex;
justify-content: center;
align-items: center;
.table_head {
display: flex;
justify-content: center;
align-items: center;
color: #fff;
font-size: 14px;
font-weight: 400;
}
}
.rank__table_body {
.table__tr {
height: 48px;
display: flex;
justify-content: center;
align-items: center;
&:nth-child(1) {
.table_head__sort {
background: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/gold.png') 50% 50% no-repeat;
background-size: 14px 18px;
}
}
&:nth-child(2) {
.table_head__sort {
background: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/silver.png') 50% 50% no-repeat;
background-size: 14px 18px;
}
}
&:nth-child(3) {
.table_head__sort {
background: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/copper.png') 50% 50% no-repeat;
background-size: 14px 18px;
}
}
&:nth-child(2n) {
background:#3900C9;
}
.table__body {
font-size:12px;
font-weight:400;
color:rgba(255,255,254,1);
display: flex;
align-items: center;
justify-content: center;
height: 100%;
}
.table_head__user_info {
.user__avatar {
width: 18px;
height: 18px;
border-radius: 50%;
margin-right: 6px;
}
.user__name {
width: 86px;
display: inline-block;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
.table_head__prize {
display: inline-block;
line-height: 48px;
text-align: start;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
}
}
.table_head__sort {
width: 50px;
}
.table_head__user_info {
width: 110px;
}
.table_head__time {
width: 58px;
}
.table_head__score {
width: 58px;
}
.table_head__prize {
width: 90px;
}
}
\ No newline at end of file
import React, { Component } from 'react'
import './index.scss'
import { http } from '@/utils';
export default class RecordPopup extends Component {
constructor(props) {
super(props);
this.state = {
recordList: [],
}
}
componentDidMount () {
http.get(`${API.home}/sys/ai_test/get_user_testinfo`).then(res => {
let {code, data: {user_test_record}} = res.data;
if(code === 200) {
this.setState({
recordList: user_test_record
})
}
});
}
render() {
let {recordList} = this.state;
const { handleToHide } = this.props;
return (
<div className='record__mark'>
<div className="gift__record">
<div className="close__button" onClick={handleToHide}>
<i className="icon iconfont iconiconfront-77"></i>
</div>
<p className="mark__title">测试记录</p>
<p className="mark__tip">多次测试保留最高分,可查看最近一次答题记录</p>
<div>
<div className="table__head">
<span className="tr">测试时间</span>
<span className="tr">分数</span>
<span className="tr">操作</span>
</div>
<div className="table__body">
{
recordList.length>0?
recordList.map((item, index) => {
return (<div className="tr__container" key={index}>
<span className="tr">{item.submit_time}</span>
<span className="tr">{item.score}</span>
<span className="tr">
{
index === 0 ? (
<a href={`/levelTest/report?id=${item.id}`}>测试记录</a>
) : (null)
}
</span>
</div>
)
}):
<div className={'notdata'}>暂无测试记录</div>
}
</div>
</div>
</div>
</div>
)
}
}
.record__mark {
position: fixed;
left: 0;
top: 0;
bottom: 0;
right: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .6);
display: flex;
justify-content: center;
align-items: center;
}
.gift__record {
width: 300px;
background: rgba(255, 255, 255, 1);
border-radius: 5px;
padding: 18px 24px 30px 24px;
position: relative;
span.tr {
display: flex;
justify-content: center;
align-items: center;
display: inline-block;
&:first-child {
width: 120px;
padding-left: 12px;
text-align: start;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
&:nth-child(2n) {
width: 55px;
}
&:last-child {
width: 75px;
padding-right: 12px;
text-align: right;
a {
font-size: 12px;
color: #0099ff;
text-decoration: underline;
}
}
}
.table__head {
width: 250px;
height: 34px;
background: rgba(82, 92, 101, 0.1);
border-radius: 1px 1px 0px 0px;
display: flex;
justify-content: space-between;
align-items: center;
font-size: 12px;
font-weight: 400;
color: rgba(82, 92, 101, 1);
}
.table__body {
width: 250px;
border: 1px solid rgba(207, 219, 229, 0.4);
border-radius: 0px 0px 1px 1px;
box-sizing: border-box;
overflow: auto;
.tr__container {
display: flex;
justify-content: center;
align-items: center;
height: 34px;
border-bottom: 1px solid rgba(207, 219, 229, 0.4);
&:last-child {
border-bottom: none;
}
p {
color: #525c65;
}
}
}
.notdata{
text-align: center;
color: #999999;
line-height: 35px;
}
.close__button {
width: 24px;
height: 24px;
border-radius: 50%;
position: absolute;
left: 50%;
transform: translateX(-50%);
bottom: -56px;
border: 1px solid #fff;
display: flex;
justify-content: center;
align-items: center;
i {
font-size: 24px;
color: #fff;
}
}
.mark__title {
width: 100%;
font-size: 16px;
line-height: 16px;
font-weight: 500;
color: rgba(82, 92, 101, 1);
margin-bottom: 16px;
text-align: center;
text-align-last: center;
}
.mark__tip {
font-size: 12px;
font-weight: 400;
color: rgba(153, 153, 153, 1);
line-height: 18px;
text-align: start;
text-align-last: start;
margin-bottom: 16px;
}
}
\ No newline at end of file
import React, { Component } from 'react';
import './index.scss';
class BlessingPrehead extends Component {
constructor(props) {
super(props);
this.state = {
rules: [
'• 抽奖的次数可通过积福气获得,福气值越高,抽奖的次数越多;',
'• 本次抽奖形式为开奖制,下一时段开启抽奖前会公布上一次中奖结果及名单,可关注“七月在线”服务号及时获取中奖结果,提醒参与下次抽奖;',
'• 每个时段仅可使用一次抽奖机会,每日抽奖次数限当日用,抽奖次数不累加至次日;',
'• 中奖后请及时填写邮寄信息,不填写视为主动放弃奖品;',
'• 解释权归北京七月在线所有。',
]
}
}
render() {
const { rules } = this.state;
const { handleToHide } = this.props;
return (
<div className="rule-popup__container">
<div className="rule-popup">
<h2 className="rule-popup__title">活动规则</h2>
<ul className="rule-popup__list">
{rules.map((item, index) => (
<li className="rule-popup__item" key={index}>{item}</li>
))}
</ul>
</div>
<i className="iconfont iconiconfront-2" onClick={handleToHide}></i>
</div>
);
}
}
export default BlessingPrehead;
\ No newline at end of file
.rule-popup__container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, .5);
z-index: 999;
.iconfont {
margin: 16px 0 0;
font-size: 24px;
color: #fff;
cursor: pointer;
}
}
.rule-popup {
width: 300px;
height: 323px;
padding: 20px 0 0;
border-radius: 10px;
box-sizing: border-box;
text-align: center;
background-color: #fff;
}
.rule-popup__title {
margin: 0 0 15px;
font-size: 16px;
font-weight: 500;
color: #525C65;
text-align: center;
line-height: 1;
}
.rule-popup__list {
padding: 0 20px;
}
.rule-popup__item {
font-size: 14px;
color: rgba(82, 92, 101, .9);
text-align: left;
line-height: 21px;
}
\ No newline at end of file
import React, { Component } from 'react';
import { browser } from '@/utils';
import './index.scss'
export default class SharePopup extends Component {
render() {
return (
<div className="share__container" onClick={() => {
if(this.props.isClose) {
this.props.toClose();
}
}}>
{
browser.isWeixin &&
<div className="share__row">
<img src='https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/throw_icon.png' />
</div>
}
<div className="share__content">
<p className="share__text">分享活动页到朋友圈、qq、微博分别</p>
<div className='share__rule'>
<img className={'share__add2'} src='https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/add2.png' />
<span>(每个平台每天一次)</span>
</div>
</div>
</div>
)
}
}
.share__container {
position: fixed;
left: 0;
right: 0;
top: 0;
bottom: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, .6);
z-index: 999;
.share__row {
width: 60px;
height: 44px;
position: absolute;
right: 16px;
top: 10px;
}
.share__content {
width:290px;
height:71px;
background:rgba(255,255,255,1);
border-radius:10px;
position: absolute;
top: 70px;
left: 50%;
transform: translateX(-50%);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
.share__text {
font-size:16px;
font-weight:400;
color:rgba(82,92,101,1);
}
.share__rule {
height: 18px;
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
font-size: 12px;
color: #525C65;
}
.share__add2{
width: 95px;
}
}
}
\ No newline at end of file
import React, {Component} from 'react'
import {SendMessageToApp,wxShare} from '@/utils'
import {setCurrentUser, startFetchUser} from "@/store/userAction"
import {Button, Toast, WhiteSpace} from 'antd-mobile'
import cookie from 'js-cookie'
import {addDays} from "date-fns"
import {compose} from "redux";
import {connect} from "react-redux";
class ToAppDemo extends Component {
state = {
userInfoList: [],
}
componentDidMount() {
this.getData()
// 获取App登录信息
window['loginInfo'] = result => {
this.loginInfo(result)
}
}
getData = () => {
Toast.info('获取福气值', 2)
}
// 获取app登录数据
loginInfo = (result) => {
this.setState({
userInfoList: result
})
if (this.state.userInfoList.length !== 0) {
this.props.startFetchUser()
this.appLogin()
}
}
// 保存cookie
appLogin = () => {
let expires = addDays(new Date(), 90)
this.state.userInfoList.map((item, index) => {
Toast.info(item.version, 3)
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'});
});
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
}
testShare = () => {
wxShare({
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: encodeURI(location.href),
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
})
}
// 跳转App登录
toLogin = () => {
SendMessageToApp("toLogin");
}
// 立即付定金
earnestMoney = (courseId) => {
SendMessageToApp("earnestMoney", courseId);
}
// 去课程详情页
toCourse = (courseId, type) => {
let data = {
courseId: courseId,
type: type // 正常跳课程详情页type:0,积福气浏览课程详情页-没有浏览过type:1 已浏览过type:2
}
SendMessageToApp("toCourse", data);
}
// 人工咨询
toQQ = () => {
SendMessageToApp("toQQ", 'https://q.url.cn/AB8aue?_type=wpa&qidian=true')
}
// 直播间
toLiveRoom = (toLiveRoom) => {
SendMessageToApp("toLiveRoom", toLiveRoom)
}
// QQ分享
QQshare = () => {
// 内容需要和产品确认
let data = {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
}
SendMessageToApp("QQshare", data)
}
// 微信分享
WXshare = () => {
// 内容需要和产品确认
let data = {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
}
SendMessageToApp("WXshare", data)
}
// 邀请好友注册
toShare = () => {
let data = {
title: 'AI充电节,积福气享1折秒课,超10万元奖品来就送!!',
desc: '把这门超5万人报名的【Python基础入门 升级版】课程送给你,附200元红包,请笑纳!--七月在线',
link: 'https://m.julyedu.com/blessingPreheat',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/index-share-img.png',
}
SendMessageToApp("toShare", data)
}
render() {
return (
<div>
<Button type={'primary'} onClick={() => this.testShare()}>测试分享</Button><WhiteSpace/>
<p>登录</p>
<Button type={'primary'} onClick={() => this.toLogin()}>App登录</Button><WhiteSpace/>
<p>去课程详情页</p>
<Button type={'primary'} onClick={() => this.toCourse(165, 0)}>课程详情页</Button><WhiteSpace/>
<p>积福气</p>
<Button type={'primary'} onClick={() => this.toCourse(165, 1)}>浏览课程详情页</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.QQshare()}>分享(QQ</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.WXshare()}>分享(微信)</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.toShare()}>邀请好友注册</Button><WhiteSpace/>
<p>定金相关</p>
<Button type={'primary'} onClick={() => this.earnestMoney(165)}>立即付定金</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.toCourse(165, 0)}>去学习(跳课程详情页)</Button><WhiteSpace/>
<p>精品特惠</p>
<Button type={'primary'} onClick={() => this.toQQ()}>立抢超低团购价(跳人工咨询)</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.toCourse(165, 0)}>开始使用(跳课程详情页)</Button><WhiteSpace/>
<Button type={'primary'} onClick={() => this.toCourse(165, 0)}>一分钱开团(跳课程详情页)</Button><WhiteSpace/>
<p>大咖直播</p>
<Button type={'primary'} onClick={() => this.toLiveRoom(100)}>正在直播</Button><WhiteSpace/>
</div>
)
}
}
export default compose(
connect(
state => ({user: state.user}),
{setCurrentUser, startFetchUser}
)
)(ToAppDemo)
\ No newline at end of file
import React, { Component } from 'react'
import { connect } from 'react-redux'
import { http } from "@/utils"
import { Popup } from '@/common'
import AddressPopup from './../blessingPreheat/addressPopup/index'
import './index.scss'
@connect(({user}) => (
{
uid: user.data.uid || ''
}
))
class BlessingRank extends Component {
popupInstance = null
constructor(props) {
super(props)
this.state = {
rankList: [],
rules: [
'1、排行榜名次以2019年11月13日24点七月在线公布的排行榜为准,榜单确认后,得奖小伙伴请及时填写邮寄信息,7个自然日内不填写,视为主动放弃奖品;',
'2、福气值只在本活动期间享受抽奖、提高中奖概率、购课优化、增加AI水平测试等福利;',
'3、如有发现恶意刷榜,刷虚假数据等行为将取消其领奖资格;',
'4、本活动解释权归北京七月在线科技有限公司所有。',
],
}
}
componentDidMount() {
this.fetchRankData()
}
fetchRankData = () => {
http.get(`${API.home}/sys/blessing/ranking`).then(res => {
const {code, data} = res.data
if (code === 200) {
this.setState({
rankList: data,
})
}
})
}
handleToSwitch = (bool) => {
const {history, uid} = this.props
if (bool && !uid) {
history.push('/passport')
} else {
if (bool && !this.popupInstance) {
this.popupInstance = Popup({
title: '收货信息',
content: <AddressPopup handleToHide={() => this.handleToSwitch(false)}/>
})
} else {
this.popupInstance.close()
this.popupInstance = null
}
}
}
formatString = (str, len) => {
return str.length > len ? `${str.substr(0, len)}...` : str
}
render() {
const {rankList, rules} = this.state
return (
<>
<div className="rank__banner"></div>
<div className="rank__body">
<button className="rank__address" onClick={() => this.handleToSwitch(true)}>填写收货地址></button>
<div className="rank__table">
<dl className="rank__table-header">
<dd className="rank__table-column">排名</dd>
<dd className="rank__table-column">用户</dd>
<dd className="rank__table-column">成绩</dd>
<dd className="rank__table-column">奖品</dd>
</dl>
{
rankList.map((item, index) => {
return (
<dl className="rank__table-body" key={index}>
<dd className="rank__table-column">
{
index < 3
? (
<i className="rank__table-num" data-num={index + 1}></i>
)
: index + 1
}
</dd>
<dd className="rank__table-column">
<div className="rank__table-user">
<i className="rank__table-portrait" style={{backgroundImage: `url(${item.head_image})`}}></i>
<span>{this.formatString(item.user_name, 5)}</span>
</div>
</dd>
<dd className="rank__table-column">{item.blessing_value}</dd>
<dd className="rank__table-column">{this.formatString(item.prize_name, 7)}</dd>
</dl>
)
})
}
</div>
<div className="rank__rule">
<h2 className="rank__rule-title">活动规则</h2>
{
rules.map((item, index) => (
<p className="rank__rule-desc" key={index}>{item}</p>
))
}
</div>
</div>
</>
)
}
}
export default BlessingRank
.rank__banner {
height: 168px;
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/rank-banner.png');
background-size: cover;
}
.rank__body {
padding: 20px 5px 39px;
background-color: #5327FA;
}
.rank__address {
display: block;
width: 133px;
height: 26px;
margin: 0 auto 10px;
padding: 0;
border: 1px solid #FFF604;
border-radius: 13px;
box-sizing: border-box;
font-size: 13px;
color: #FFF604;
line-height: 26px;
background-color: transparent;
outline: none;
cursor: pointer;
}
.rank__table {
display: table;
width: 100%;
margin: 0 0 20px;
border-radius: 5px;
overflow: hidden;
}
.rank__table-header {
display: table-row;
height: 38px;
border-radius: 5px 5px 0px 0px;
background-color: #5970FF;
}
.rank__table-body {
display: table-row;
height: 38px;
background-color: #471CE6;
&:nth-child(odd) {
background-color: #3900C9;
}
}
.rank__table-column {
display: table-cell;
font-size: 14px;
color: #fff;
text-align: center;
vertical-align: middle;
&:nth-child(1) {
width: 15%;
}
&:nth-child(2) {
width: 30%;
}
&:nth-child(3) {
width: 20%;
}
&:nth-child(4) {
width: 35%;
}
}
.rank__table-num {
display: inline-block;
width: 14px;
height: 16px;
background-size: cover;
&[data-num="1"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-diyiming.png');
}
&[data-num="2"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-dierming.png');
}
&[data-num="3"] {
background-image: url('https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/-s-disanming.png');
}
}
.rank__table-user {
display: inline-flex;
align-items: center;
justify-content: center;
}
.rank__table-portrait {
display: inline-block;
width: 18px;
height: 18px;
margin-right: 5px;
border-radius: 50%;
background-size: cover;
}
.rank__rule {
margin: 0 5px;
padding: 20px 20px 48px;
border-radius: 5px;
background-color: #5970FF;
}
.rank__rule-title {
position: relative;
width: 103px;
margin: 0 auto 15px;
font-size: 14px;
font-weight: 400;
color: #fff;
text-align: center;
line-height: 1;
&::after {
content: '';
position: absolute;
top: 50%;
left: 0;
width: 10px;
height: 1px;
background-color: #fff;
}
&::before {
content: '';
position: absolute;
top: 50%;
right: 0;
width: 10px;
height: 1px;
background-color: #fff;
}
}
.rank__rule-desc {
font-size: 12px;
color: #F0F1FF;
line-height: 18px;
}
\ No newline at end of file
$bg_type1: #FE6161; $bg_voucher: #FE6161;
$bg_type2: #E0B97B; $bg_free: #E0B97B;
$bg_expand: #8361FE;
.coupon { .coupon {
position: relative; position: relative;
margin-bottom: 15px; margin-bottom: 15px;
...@@ -27,13 +28,14 @@ $bg_type2: #E0B97B; ...@@ -27,13 +28,14 @@ $bg_type2: #E0B97B;
} }
} }
.course-title{ .course-title {
width: 68.37%; width: 68.37%;
margin: 0 auto 4px; margin: 0 auto 4px;
white-space: nowrap; white-space: nowrap;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
font-size: $font_16; font-size: $font_16;
text-align: center;
} }
.expire { .expire {
...@@ -43,14 +45,18 @@ $bg_type2: #E0B97B; ...@@ -43,14 +45,18 @@ $bg_type2: #E0B97B;
} }
&.coupon-type1 { &.coupon-type1 {
background: $bg_type1; background: $bg_voucher;
} }
&.coupon-type2 { &.coupon-type2 {
background: $E0B97B; background: $E0B97B;
} }
&.invalid{ &.coupon-type4 {
background: $bg_expand;
}
&.invalid {
background: $color_999; background: $color_999;
} }
...@@ -87,6 +93,44 @@ $bg_type2: #E0B97B; ...@@ -87,6 +93,44 @@ $bg_type2: #E0B97B;
transform: translateY(50%); transform: translateY(50%);
} }
} }
.progress-container {
width: 299px;
margin: 0 auto;
.denomination {
font-size: 15px;
line-height: 1.3em;
color: #F8E71C;
span{
transform: scale(0.9);
}
}
.progress-bar-container {
position: relative;
height: 7px;
background: #5C2FFF;
border-radius: 4px;
overflow: hidden;
margin-bottom: 6px;
.progress-bar {
position: absolute;
left: 0;
top: 0;
height: 100%;
background: #F8E71C;
border-radius: 4px;
}
}
.money {
display: flex;
justify-content: space-between;
}
}
} }
.coupon-des { .coupon-des {
...@@ -117,5 +161,15 @@ $bg_type2: #E0B97B; ...@@ -117,5 +161,15 @@ $bg_type2: #E0B97B;
background: transparent; background: transparent;
-webkit-appearance: none; -webkit-appearance: none;
} }
.stop-expanding {
padding: 3px 8px;
border: 1px solid #FF3131;
border-radius: 10px;
-webkit-appearance: none;
background: transparent;
color: #FF3131;
font-size: 10px;
}
} }
} }
import React, { PureComponent } from 'react' import React, { PureComponent } from 'react'
import './coupon.scss' import './coupon.scss'
import classnames from 'classnames' import classnames from 'classnames'
import { http } from "@/utils"
import showAlert from '@common/deposit/end-expansion-alert'
import { Toast } from 'antd-mobile'
import { withRouter } from "react-router-dom"
class Coupon extends PureComponent { class Coupon extends PureComponent {
pick = () => { VOUCHER = 1 //代金券
let {useCoupon, invalid} = this.props FREE = 2 //免单券
EXPAND = 4 //膨胀全
pick = (e) => {
let {useCoupon, invalid, start_amount, id, location, history, code} = this.props
const {state} = location
if(state && state.from && state.from === '/my' && typeof start_amount !== 'undefined'){
history.push(`/expand/index?deposit_code=${code}`)
return
}
if (start_amount) {
this.stopExpanding(id, e)
} else {
!invalid && useCoupon && useCoupon(this.props.id) !invalid && useCoupon && useCoupon(this.props.id)
}
} }
...@@ -14,33 +33,171 @@ class Coupon extends PureComponent { ...@@ -14,33 +33,171 @@ class Coupon extends PureComponent {
this.props.useCoupon(this.props.id) this.props.useCoupon(this.props.id)
} }
ExchangeCourse = (e) => { ExchangeCourse = (e) => {
this.props.toExchangeCourse(e,this.props.code) this.props.toExchangeCourse(e, this.props.code)
}
stopExpanding = (id, e) => {
const {amount, limit_amount} = this.props
e.stopPropagation()
showAlert({
amount,
limit_amount,
onConfirm: () => {
http.post(`${API.home}/m/end_expansion`, {
id
})
.then(res => {
const {data} = res
if (data.code == 200) {
this.props.endExpansion(id, data.data.coupon_id)
} else {
Toast.info(data.msg)
}
})
}
})
} }
render() { render() {
let { let {
ctype, ctype,
amount, amount,
format_expire_time,
limit_course,
invalid,
course_title, course_title,
showUseButton,
id, id,
code, format_expire_time,
selectedCouponId, start_amount,
showUseButton limit_amount
} = this.props } = this.props
return ( let top, bottom
<li className='coupon' onClick={this.pick}>
<div className={classnames('coupon-info', invalid ? 'invalid' : `coupon-type${ctype}`)}> switch (ctype) {
<p className='type'>{ctype === 1 ? '代金券' : '课程券'}</p> case this.VOUCHER:
top = (
<>
<p className='denomination'>{amount} <span></span></p>
<p className='expire'>有效期至:{format_expire_time}</p>
</>
)
bottom = (
<>
<span className={'limit'}>可用于大于代金券金额的课程</span>
{ {
ctype === 1 ? <p className='denomination'>{amount} <span></span></p> showUseButton && ctype == this.VOUCHER &&
: <p className='course-title'>{course_title}</p> <button
className='use'
onClick={this.GoToUse}
>立即使用
</button>
}
</>
)
break
case this.FREE:
top = (
<>
<p className='course-title'>{course_title}</p>
<p className='expire'>有效期至:{format_expire_time}</p>
</>
)
bottom = (
<>
<span className={'limit'}>{`仅适用于《${course_title}》`}</span>
{
showUseButton && ctype == this.FREE &&
<button
className='use'
onClick={(e) => this.ExchangeCourse(e)}
>立即兑换
</button>
} }
</>
)
break
case this.EXPAND:
if (!start_amount) {
top = (
<>
<p className='denomination'>{amount} <span></span></p>
<p className='expire'>有效期至:{format_expire_time}</p> <p className='expire'>有效期至:{format_expire_time}</p>
</>
)
} else {
top = (
<>
<div className="progress-container">
<p className='denomination'>{amount} <span></span></p>
<div className={'progress-bar-container'}>
<span className={'progress-bar'}
style={{width: `${Math.round((amount - start_amount) / limit_amount * 100)}%`}}
></span>
</div>
<div className={'money'}>
<span>{start_amount}</span>
<span>{limit_amount}</span>
</div>
</div>
</>
)
}
bottom = (
<>
<span className={'limit'}>全场通用</span>
{
start_amount
&& <button className='stop-expanding'
onClick={this.stopExpanding.bind(this, id)}>立即结束膨胀</button>
}
</>
)
break
}
return (
<BaseCoupon
{...this.props}
top={top}
VOUCHER={this.VOUCHER}
FREE={this.FREE}
EXPAND={this.EXPAND}
pick={this.pick}
bottom={bottom}
/>
)
}
}
function BaseCoupon(
{
pick,
ctype,
invalid,
top,
VOUCHER,
FREE,
EXPAND,
selectedCouponId,
id,
bottom
}) {
let couponTypes = {
[VOUCHER]: '代金券',
[FREE]: '课程券',
[EXPAND]: '膨胀券'
}
return (
<li className='coupon' onClick={pick}>
<div className={classnames('coupon-info', invalid ? 'invalid' : `coupon-type${ctype}`)}>
<p className='type'>{couponTypes[ctype]}</p>
{top}
{ {
selectedCouponId === id && selectedCouponId === id &&
<i className={classnames('iconfont icondanseshixintubiao-5', { <i className={classnames('iconfont icondanseshixintubiao-5', {
...@@ -57,30 +214,10 @@ class Coupon extends PureComponent { ...@@ -57,30 +214,10 @@ class Coupon extends PureComponent {
</ul> </ul>
</div> </div>
<div className="coupon-des"> <div className="coupon-des">
<span className='limit'>{ {bottom}
limit_course === 0 ? '可用于大于代金券金额的课程' : `仅适用于《${course_title}》`
}</span>
{
showUseButton && ctype == 1 &&
<button
className='use'
onClick={this.GoToUse}
>立即使用
</button>
}
{
showUseButton && ctype == 2 &&
<button
className='use'
onClick={(e)=>this.ExchangeCourse(e)}
>立即兑换
</button>
}
</div> </div>
</li> </li>
); )
}
} }
export default Coupon export default withRouter(Coupon)
\ No newline at end of file
import React, { PureComponent } from 'react'
import './coupon.scss'
import classnames from 'classnames'
class Coupon extends PureComponent {
VOUCHER = 1 //代金券
FREE = 2 //免单券
EXPAND = 4 //膨胀全
pick = () => {
let {useCoupon, invalid} = this.props
!invalid && useCoupon && useCoupon(this.props.id)
}
GoToUse = () => {
this.props.useCoupon(this.props.id)
}
ExchangeCourse = (e) => {
this.props.toExchangeCourse(e, this.props.code)
}
render() {
let {
ctype,
amount,
format_expire_time,
limit_course,
invalid,
course_title,
id,
code,
selectedCouponId,
showUseButton
} = this.props
return (
<li className='coupon' onClick={this.pick}>
<div className={classnames('coupon-info', invalid ? 'invalid' : `coupon-type${ctype}`)}>
<p className='type'>{ctype === this.VOUCHER ? '代金券' : '课程券'}</p>
{
ctype === this.VOUCHER ? <p className='denomination'>{amount} <span>元</span></p>
: <p className='course-title'>{course_title}</p>
}
<p className='expire'>有效期至:{format_expire_time}</p>
{
selectedCouponId === id &&
<i className={classnames('iconfont icondanseshixintubiao-5', {
check: !invalid
})}
/>
}
<ul>
{
new Array(19).fill('a').map((item, index) => {
return <li key={index}/>
})
}
</ul>
</div>
<div className="coupon-des">
<span className='limit'>{
limit_course === 0 ? '可用于大于代金券金额的课程' : `仅适用于《${course_title}》`
}</span>
{
showUseButton && ctype == this.VOUCHER &&
<button
className='use'
onClick={this.GoToUse}
>立即使用
</button>
}
{
showUseButton && ctype == this.FREE &&
<button
className='use'
onClick={(e) => this.ExchangeCourse(e)}
>立即兑换
</button>
}
</div>
</li>
)
}
}
function BaseCoupon(
{
pick,
ctype,
invalid,
top,
VOUCHER,
FREE,
EXPAND,
limitMessage,
bottomButton
}) {
let couponTypes = {
[VOUCHER]: '代金券',
[FREE]: '课程券',
[EXPAND]: '膨胀券'
}
return (
<li className='coupon' onClick={pick}>
<div className={classnames('coupon-info', invalid ? 'invalid' : `coupon-type${ctype}`)}>
<p className='type'>{couponTypes[ctype]}</p>
{top}
<ul>
{
new Array(19).fill('a').map((item, index) => {
return <li key={index}/>
})
}
</ul>
</div>
<div className="coupon-des">
<span className='limit'>
{limitMessage}
</span>
{bottomButton}
</div>
</li>
)
}
export default Coupon
import React, {PureComponent} from 'react'; import React, { PureComponent } from 'react'
import './index.scss' import './index.scss'
import RedeemBar from "../RedeemBar"; import RedeemBar from "../RedeemBar"
import Coupon from '../Coupon' import Coupon from '../Coupon'
import {http, getParam} from '@/utils' import { http, getParam } from '@/utils'
import {WithFullSize} from '@/HOCs' import { WithFullSize } from '@/HOCs'
import {Toast} from 'antd-mobile' import { Toast } from 'antd-mobile'
import {isEmpty} from 'lodash' import { connect } from 'react-redux'
import {connect} from 'react-redux';
@connect() @connect()
class UseCoupon extends PureComponent { class UseCoupon extends PureComponent {
...@@ -30,7 +29,7 @@ class UseCoupon extends PureComponent { ...@@ -30,7 +29,7 @@ class UseCoupon extends PureComponent {
const {state} = this.props.location const {state} = this.props.location
if (state && state.from) { if (state && state.from) {
if (state.from === '/my') { if (state.from === '/my') {
this.getMyCoupons(); this.getMyCoupons()
this.setState({ this.setState({
showUseButton: true showUseButton: true
}) })
...@@ -38,7 +37,7 @@ class UseCoupon extends PureComponent { ...@@ -38,7 +37,7 @@ class UseCoupon extends PureComponent {
if (!this.state.courseId) { if (!this.state.courseId) {
location.state && location.state.from ? history.replace(location.state.from) : history.goBack() location.state && location.state.from ? history.replace(location.state.from) : history.goBack()
} }
this.getAllCoupons(); this.getAllCoupons()
} }
} }
} }
...@@ -50,7 +49,7 @@ class UseCoupon extends PureComponent { ...@@ -50,7 +49,7 @@ class UseCoupon extends PureComponent {
// 兑换 // 兑换
exchange = () => { exchange = () => {
const {location: {state = {}}} = this.props; const {location: {state = {}}} = this.props
if (this.state.redeemCode !== '') { if (this.state.redeemCode !== '') {
http.post(`${API.home}/m/coupon/exchange`, { http.post(`${API.home}/m/coupon/exchange`, {
code: this.state.redeemCode, code: this.state.redeemCode,
...@@ -88,7 +87,7 @@ class UseCoupon extends PureComponent { ...@@ -88,7 +87,7 @@ class UseCoupon extends PureComponent {
invalid_coupons: [...this.state.invalid_coupons, coupon], invalid_coupons: [...this.state.invalid_coupons, coupon],
showUseButton: null, showUseButton: null,
redeemCode: '' redeemCode: ''
}); })
} else { } else {
this.setState({ this.setState({
valid_coupons: [...this.state.valid_coupons, coupon], valid_coupons: [...this.state.valid_coupons, coupon],
...@@ -109,33 +108,59 @@ class UseCoupon extends PureComponent { ...@@ -109,33 +108,59 @@ class UseCoupon extends PureComponent {
} }
getMyCoupons = () => { getMyCoupons = () => {
Promise.all([
http.get(`${API.home}/m/coupon/expansion`),
http.get(`${API.home}/m/coupon/all`) http.get(`${API.home}/m/coupon/all`)
.then(res => { ]).then((coupons) => {
const data = res.data let myCoupons = []
if (data.code === 200) { const [expansionCoupons, allCoupons] = coupons
this.setState({ const {data: all} = allCoupons
couponList: isEmpty(data.data) ? [] : data.data const {data: expansion} = expansionCoupons
}) if (expansion.code == 200) {
Array.isArray(expansion.data)
&& (expansion.data = expansion.data.map(item => (item.ctype = 4, item)))
&& (myCoupons = myCoupons.concat(expansion.data))
} else { } else {
Toast.info(data.msg) Toast.info(expansion.msg)
}
if (all.code == 200) {
Array.isArray(all.data) && (myCoupons = myCoupons.concat(all.data))
} else {
Toast.info(all.msg)
} }
this.setState({
couponList: myCoupons
})
}) })
} }
getAllCoupons = () => { getAllCoupons = () => {
Promise.all([
http.get(`${API.home}/m/coupon/expansion`),
http.post(`${API.home}/m/coupon/select`, {course_id: this.state.courseId}) http.post(`${API.home}/m/coupon/select`, {course_id: this.state.courseId})
.then(res => { ]).then((coupons) => {
const data = res.data const [expansionCoupons, selectCoupons] = coupons
if (data.code === 200) { const {data: select} = selectCoupons
const {data: expansion} = expansionCoupons
const inuse_coupon = data.data['inuse_coupon']; let PzCoupon = this.state.valid_coupons.concat(expansion.data)
if (expansion.code == 200) {
Array.isArray(expansion.data)
&& (expansion.data = expansion.data.map(item => (item.ctype = 4, item)))
&& (this.setState({
valid_coupons: this.state.valid_coupons.concat(expansion.data)
}))
} else {
Toast.info(expansion.msg)
}
if (select.code === 200) {
const inuse_coupon = select.data['inuse_coupon']
let PzCoupon2 = inuse_coupon
? [...inuse_coupon, ...select.data.valid_coupons]
: select.data.valid_coupons
this.setState({ this.setState({
valid_coupons: inuse_coupon valid_coupons: PzCoupon.concat(PzCoupon2),
? [...inuse_coupon, ...data.data.valid_coupons] invalid_coupons: select.data.invalid_coupons,
: data.data.valid_coupons,
invalid_coupons: data.data.invalid_coupons,
selectedCouponId: inuse_coupon.length ? inuse_coupon[0].id : 0 selectedCouponId: inuse_coupon.length ? inuse_coupon[0].id : 0
}) })
...@@ -147,7 +172,7 @@ class UseCoupon extends PureComponent { ...@@ -147,7 +172,7 @@ class UseCoupon extends PureComponent {
// 立即兑换课程 // 立即兑换课程
toExchangeCourse = (e, code) => { toExchangeCourse = (e, code) => {
e.stopPropagation(); e.stopPropagation()
http.post(`${API['base-api']}/pay/miandan/${code}`, {}).then(res => { http.post(`${API['base-api']}/pay/miandan/${code}`, {}).then(res => {
const data = res.data const data = res.data
if (data.errno === 200) { if (data.errno === 200) {
...@@ -163,7 +188,7 @@ class UseCoupon extends PureComponent { ...@@ -163,7 +188,7 @@ class UseCoupon extends PureComponent {
} }
useCoupon = val => { useCoupon = val => {
const {history, dispatch} = this.props const {history} = this.props
const coupon = this.state.couponList.find(item => item.id === val) const coupon = this.state.couponList.find(item => item.id === val)
if (val) { if (val) {
...@@ -172,8 +197,8 @@ class UseCoupon extends PureComponent { ...@@ -172,8 +197,8 @@ class UseCoupon extends PureComponent {
if (coupon['limit_course'] === 0) { if (coupon['limit_course'] === 0) {
history.push(`/classify`) history.push(`/classify`)
} else { } else {
history.push(`/detail?id=${coupon['limit_course']}`); history.push(`/detail?id=${coupon['limit_course']}`)
return false; return false
} }
} else { } else {
...@@ -233,7 +258,7 @@ class UseCoupon extends PureComponent { ...@@ -233,7 +258,7 @@ class UseCoupon extends PureComponent {
// 开始学习 // 开始学习
toStudy = (vCourseId, isHaveVideo) => { toStudy = (vCourseId, isHaveVideo) => {
const {history} = this.props; const {history} = this.props
if (isHaveVideo == 0) { if (isHaveVideo == 0) {
Toast.info('尚未开课,开课后立即上传课程~', 2) Toast.info('尚未开课,开课后立即上传课程~', 2)
} else { } else {
...@@ -251,6 +276,19 @@ class UseCoupon extends PureComponent { ...@@ -251,6 +276,19 @@ class UseCoupon extends PureComponent {
}) })
} }
endExpansion = (id, validId) => {
this.setState({
valid_coupons: this.state.valid_coupons.map(item => {
if (item.id === id) {
delete item.start_amount
item.id = validId
}
return item
})
})
}
render() { render() {
const {state} = this.props.location const {state} = this.props.location
const {showUseButton, selectedCouponId} = this.state const {showUseButton, selectedCouponId} = this.state
...@@ -273,6 +311,7 @@ class UseCoupon extends PureComponent { ...@@ -273,6 +311,7 @@ class UseCoupon extends PureComponent {
select={this.select} select={this.select}
useCoupon={this.useCoupon} useCoupon={this.useCoupon}
toExchangeCourse={this.toExchangeCourse} toExchangeCourse={this.toExchangeCourse}
endExpansion={this.endExpansion}
/> />
{ {
this.state.invalid_coupons.length > 0 && this.state.invalid_coupons.length > 0 &&
...@@ -296,7 +335,7 @@ class UseCoupon extends PureComponent { ...@@ -296,7 +335,7 @@ class UseCoupon extends PureComponent {
courseCouponData={this.state.courseCouponData}/> courseCouponData={this.state.courseCouponData}/>
} }
</div> </div>
); )
} }
} }
...@@ -313,6 +352,7 @@ function Content({coupons, ...rest}) { ...@@ -313,6 +352,7 @@ function Content({coupons, ...rest}) {
{ {
coupons.map(item => { coupons.map(item => {
return ( return (
item.id &&
<Coupon <Coupon
key={item.id} key={item.id}
{...item} {...item}
...@@ -351,4 +391,4 @@ function FreeCouponCourse(props) { ...@@ -351,4 +391,4 @@ function FreeCouponCourse(props) {
) )
} }
export default WithFullSize(UseCoupon); export default WithFullSize(UseCoupon)
\ No newline at end of file
...@@ -243,6 +243,41 @@ class BtnStatus extends Component { ...@@ -243,6 +243,41 @@ class BtnStatus extends Component {
}) })
} }
// 付定金 付尾款
expandPay = (info,type)=>{
// type 等于1是定金 等于2是尾款
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
if(type == 1){
this.props.history.push(
`/deposit-order?oid=${getParam('id')}&source=${1}`,
{
id: getParam('id'),
isexpand: 1,
sourcenum: 1
}
)
} else {
let timeStamp = Date.parse(new Date()) / 1000;
if (timeStamp >= info.start_timestamp) {
this.props.history.push(
'/final-deposit-order?source=1',
{
id: getParam('id'),
sourcenum: 1
}
)
} else {
Toast.info("付尾款时间将在" + info.final_start_time + "开启",2);
}
}
}
}
render() { render() {
// data 课程信息;barInfo 砍价信息 // data 课程信息;barInfo 砍价信息
const { user = {}, toCart } = this.props; const { user = {}, toCart } = this.props;
...@@ -271,6 +306,22 @@ class BtnStatus extends Component { ...@@ -271,6 +306,22 @@ class BtnStatus extends Component {
</div> </div>
} }
{/* 定金课程 is_deposit 是否定金课程 0-否 1-付定金 2-付尾款*/}
{
info.is_baoming === 0 && info.is_deposit != 0 &&
<div className='btns-box'>
<a className='consult consult-m' href="https://q.url.cn/AB8aue?_type=wpa&qidian=true">
<i className='iconfont iconerji' />
<span>课程咨询</span>
</a>
<div className='btn btn-m bg-FD7700' onClick={()=>this.expandPay(info.deposit_info,info.is_deposit)}>
{info.is_deposit == 1 ? '立即付定金':'立即付尾款'}
</div>
</div>
}
{/*已购买*/} {/*已购买*/}
{ {
info.is_baoming === 1 && info.is_baoming === 1 &&
......
import React, {Component} from 'react'
import './index.scss'
import {connect} from "react-redux"
import {withRouter} from 'react-router-dom'
import {compose} from "redux"
class Deposit extends Component {
constructor(props) {
super(props)
this.state = {}
}
render() {
const {courseInfo} = this.props;
let info = ''
if (courseInfo) {
info = courseInfo.deposit_info
}
return (
<div className="buy-expand">
<p className="buy-time">付定金时间:{info.deposit_start_time}-{info.deposit_end_time}</p>
<p className="buy-time">付尾款时间:{info.final_start_time}-{info.final_end_time}</p>
<div className="expand-bgimg">
<img
className="four-year"
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/dj-1111.png"
alt=''
/>
<span className="dingjin">定金{info.deposit_amount}元,可抵扣{info.deduction_amount}</span>
<p className="small">
到手价最低:¥
<span>{info.low_price}</span>
</p>
<p className="else-tip">另可获得最高{info.deposit_coupon}元代金券进行叠加</p>
</div>
</div>
);
}
}
export default compose(
connect(
state => ({
user: state.user
}),
null
),
withRouter
)(Deposit)
.buy-expand {
margin-top: 5px;
.buy-time {
color: #999;
font-size: 12px;
text-align: left;
padding-left: 15px;
margin-bottom: 8px;
}
.expand-bgimg {
position: relative;
width: 100%;
height: 70px;
background-size: cover;
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/detail-expand-bg.png");
.four-year {
width: 104px;
height: 32px;
position: absolute;
left: 12px;
top: 7px;
}
.dingjin {
color: #f5f5f5;
font-size: 15px;
position: absolute;
right: 12px;
top: 20px;
}
.small {
color: #f5f5f5;
font-size: 14px;
position: absolute;
left: 12px;
bottom: 6px;
span {
font-size: 18px;
}
}
.else-tip {
color: #f5f5f5;
font-size: 12px;
position: absolute;
right: 12px;
bottom: 10px;
}
}
}
...@@ -21,6 +21,7 @@ class ToGroup extends Component { ...@@ -21,6 +21,7 @@ class ToGroup extends Component {
number: 0, // 差几人成团 number: 0, // 差几人成团
isBuy: false, isBuy: false,
modal: false, modal: false,
pddOrderId:''
} }
} }
...@@ -57,22 +58,26 @@ class ToGroup extends Component { ...@@ -57,22 +58,26 @@ class ToGroup extends Component {
person_num: res.data.data.person_num, person_num: res.data.data.person_num,
course_list: res.data.data.course_list, course_list: res.data.data.course_list,
number: res.data.data.number, number: res.data.data.number,
pddOrderId: res.data.data.pdd_order_id,
countdown: '', countdown: '',
isBuy: res.data.data.is_buy isBuy: res.data.data.is_buy
}); });
if (res.data.data.is_success === 0) { if (res.data.data.is_success === 0) {
let date = res.data.data.end_time * 1000, let date = res.data.data.end_time * 1000,
day = 0,
hours = 0, hours = 0,
minutes = 0, minutes = 0,
seconds = 0; seconds = 0;
setInterval(() => { setInterval(() => {
date -= 1000 date -= 1000
hours = `${parseInt(date / (60 * 60 * 1000))}`.padStart(2, 0); day = `${parseInt(date / (3600000 * 24))}`.padStart(2, 0);
minutes = `${parseInt((date - hours * 3600000) / 60000)}`.padStart(2, 0); hours = `${parseInt((date- day * 3600000 * 24)/3600000)}`.padStart(2, 0);
seconds = `${parseInt((date - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0); minutes = `${parseInt((date - day * 3600000 * 24 - hours * 3600000) / 60000)}`.padStart(2, 0);
seconds = `${parseInt((date - day * 3600000 * 24 - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0);
this.setState({ this.setState({
countdown: `${hours}:${minutes}:${seconds}` // countdown: `${day}:${hours}:${minutes}:${seconds}`
countdown: `${day}${hours}${minutes}分`
}); });
}, 1000) }, 1000)
} }
...@@ -98,7 +103,8 @@ class ToGroup extends Component { ...@@ -98,7 +103,8 @@ class ToGroup extends Component {
history.push( history.push(
`/order?id=${data.course_id}`, `/order?id=${data.course_id}`,
{ {
group: 1 group: 1,
pdd_order_id:this.state.pddOrderId
} }
) )
} else { } else {
......
...@@ -10,6 +10,7 @@ import Single from "./single" ...@@ -10,6 +10,7 @@ import Single from "./single"
import SingleSuccess from './single/singleSuccess'; import SingleSuccess from './single/singleSuccess';
import BtnStatus from "./btnstatus" import BtnStatus from "./btnstatus"
import Barrage from './barrage' import Barrage from './barrage'
import Deposit from './deposit'
import {connect} from "react-redux" import {connect} from "react-redux"
import {getCourses, addCourseToCart} from "./actions" import {getCourses, addCourseToCart} from "./actions"
import {getParam, http, browser, wxShare} from "@/utils" import {getParam, http, browser, wxShare} from "@/utils"
...@@ -19,6 +20,7 @@ import {delCountryNum} from './../country/countryRedux'; ...@@ -19,6 +20,7 @@ import {delCountryNum} from './../country/countryRedux';
import RedPacket from './redPacket'; import RedPacket from './redPacket';
import {Link} from "react-router-dom"; import {Link} from "react-router-dom";
import ExpandActiveToast from "../Index/expandActiveToast";
class Detail extends Component { class Detail extends Component {
...@@ -46,7 +48,9 @@ class Detail extends Component { ...@@ -46,7 +48,9 @@ class Detail extends Component {
nowPrice: 0, nowPrice: 0,
laterPrice: 0, laterPrice: 0,
isPdd: 0, // 是否是拼团课程 控制首次单集购买后的 全集购买 接口: 拼团课程走拼团接口,否则直接走购买接口 isPdd: 0, // 是否是拼团课程 控制首次单集购买后的 全集购买 接口: 拼团课程走拼团接口,否则直接走购买接口
isRedPacket: true isRedPacket: true,
countDownTime: '20s',
} }
} }
...@@ -71,6 +75,51 @@ class Detail extends Component { ...@@ -71,6 +75,51 @@ class Detail extends Component {
isRedPacket: true isRedPacket: true
}); });
} }
if(getParam('ac') && Number(getParam('ac')) === 11) {
this.getBorwerCourse();
}
}
getBorwerCourse = () => {
http.get(`${API.home}/sys/user/blessing`, {type: 4, course_id: getParam('id')}).then(res => {
let {code, data: {today_browsed_courses}} = res.data;
if(code === 200) {
let currentCourseId = getParam('id');
if(today_browsed_courses.includes(Number(currentCourseId))) {
this.setState({
countDownTime: '任务完成'
});
}else{
this.startActivity();
}
}
})
}
startActivity = () => {
let _this = this;
let countDownInterval = setInterval(function() {
let countDown = parseInt(_this.state.countDownTime);
countDown--;
if(countDown > 0) {
_this.setState({
countDownTime: countDown + 's'
});
} else if(countDown === 0) {
clearInterval(countDownInterval);
countDownInterval = null;
http.post(`${API.home}/sys/add/blessing`, {type: 4, course_id: getParam('id')}).then(res => {
let {code} = res.data;
if(code === 200) {
_this.setState({
countDownTime: '任务完成'
});
}
})
}
}, 1000)
} }
// 判断时候未红包课程 // 判断时候未红包课程
...@@ -296,16 +345,19 @@ class Detail extends Component { ...@@ -296,16 +345,19 @@ class Detail extends Component {
if (course_info.group_status === 3 || course_info.group_status === 4) { if (course_info.group_status === 3 || course_info.group_status === 4) {
let endTime = course_info.pdd_group_info.groupon_member.end_time; let endTime = course_info.pdd_group_info.groupon_member.end_time;
let date = endTime * 1000, let date = endTime * 1000,
day = 0,
hours = 0, hours = 0,
minutes = 0, minutes = 0,
seconds = 0; seconds = 0;
setInterval(() => { setInterval(() => {
date -= 1000 date -= 1000
hours = `${parseInt(date / (60 * 60 * 1000))}`.padStart(2, 0); day = `${parseInt(date / (3600000 * 24))}`.padStart(2, 0);
minutes = `${parseInt((date - hours * 3600000) / 60000)}`.padStart(2, 0); hours = `${parseInt((date- day * 3600000 * 24)/3600000)}`.padStart(2, 0);
seconds = `${parseInt((date - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0); minutes = `${parseInt((date - day * 3600000 * 24 - hours * 3600000) / 60000)}`.padStart(2, 0);
seconds = `${parseInt((date - day * 3600000 * 24 - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0);
this.setState({ this.setState({
countdown: `${hours}:${minutes}:${seconds}` // countdown: `${day}:${hours}:${minutes}:${seconds}`
countdown: `${day}${hours}${minutes}分`
}); });
}, 1000) }, 1000)
} }
...@@ -441,7 +493,7 @@ class Detail extends Component { ...@@ -441,7 +493,7 @@ class Detail extends Component {
} }
render() { render() {
const {course: {course_info = {}}, barInfo, singleBox, singleType, isRedPacket} = this.state; const {course: {course_info = {}}, barInfo, singleBox, singleType, isRedPacket, countDownTime} = this.state;
let courseInfo = '', let courseInfo = '',
service = '', service = '',
...@@ -466,8 +518,17 @@ class Detail extends Component { ...@@ -466,8 +518,17 @@ class Detail extends Component {
if (getParam('dist_code')) { if (getParam('dist_code')) {
href = '/' href = '/'
} }
let isCent = course_info.pdd_group_info && course_info.pdd_group_info.price != '0.01';
return ( return (
<div> <div>
{
Number(getParam('ac')) === 11 ? (
<div className='activity__blessing'>
<img src='https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/count_donw.png' />
<span className='count__down__time'>{`${countDownTime}`}</span>
</div>
) : (null)
}
<div className='detail-box'> <div className='detail-box'>
<HeaderBar <HeaderBar
title='课程详情' title='课程详情'
...@@ -475,6 +536,10 @@ class Detail extends Component { ...@@ -475,6 +536,10 @@ class Detail extends Component {
cart={true} cart={true}
toHref={href} toHref={href}
/> />
<ExpandActiveToast/>
<CallApp className='toapp' path={`/detail/id=${getParam('id')}`} /> <CallApp className='toapp' path={`/detail/id=${getParam('id')}`} />
{/*弹幕*/} {/*弹幕*/}
...@@ -500,10 +565,13 @@ class Detail extends Component { ...@@ -500,10 +565,13 @@ class Detail extends Component {
<span className="old">¥{course_info.price0}</span> <span className="old">¥{course_info.price0}</span>
</p> </p>
} }
{/*{*/} {
{/*course_info.is_baoming === 1 &&*/} !!course_info.is_deposit && course_info.is_deposit!= 0 &&
{/*<span className="isbuy">已购买</span>*/} <div className="openExpand">
{/*}*/} 支付定金¥{course_info.deposit_info.deposit_amount},可抵扣¥{course_info.deposit_info.deduction_amount}
</div>
}
</div> </div>
</div> </div>
</div> </div>
...@@ -550,6 +618,15 @@ class Detail extends Component { ...@@ -550,6 +618,15 @@ class Detail extends Component {
</div> </div>
} }
{/*定金相关信息*/}
{
!!course_info.is_deposit && course_info.is_deposit!= 0 &&
<Deposit courseInfo={course_info}/>
}
{/*服务承诺*/} {/*服务承诺*/}
<div className='promise'> <div className='promise'>
<label>服务承诺</label> <label>服务承诺</label>
...@@ -623,17 +700,19 @@ class Detail extends Component { ...@@ -623,17 +700,19 @@ class Detail extends Component {
* 拼团 * 拼团
* is_aist: 是否AI特训营 * is_aist: 是否AI特训营
* group_status: 团状态,3:课程有小团 用户没参加小团;4:用户参加了小团 * group_status: 团状态,3:课程有小团 用户没参加小团;4:用户参加了小团
* 拼团价格为1分钱时,不允许参团
*/ */
} }
{ {/*双十一期间不需要显示 不要删除*/}
!course_info.is_aist && (course_info.group_status === 3 || course_info.group_status === 4) && {/*{*/}
<Group {/*isCent && !course_info.is_aist && (course_info.group_status === 3 || course_info.group_status === 4) &&*/}
courseInfo={course_info} {/*<Group*/}
history={this.props.history} {/*courseInfo={course_info}*/}
countdown={countdown} {/*history={this.props.history}*/}
invitedFriends={this.invitedFriends} {/*countdown={countdown}*/}
/> {/*invitedFriends={this.invitedFriends}*/}
} {/*/>*/}
{/*}*/}
{/* {/*
* 砍价 * 砍价
......
...@@ -60,6 +60,7 @@ ...@@ -60,6 +60,7 @@
font-size: 14px; font-size: 14px;
color: $color_666; color: $color_666;
margin-top: 10px; margin-top: 10px;
line-height: 16px;
} }
.des { .des {
...@@ -222,4 +223,34 @@ ...@@ -222,4 +223,34 @@
} }
} }
} }
.openExpand {
font-size: 14px;
color: #ff2121;
font-weight: 500;
width: 215px;
}
}
.activity__blessing {
position: fixed;
bottom: 170px;
right: 4px;
width: 76px;
height: 64px;
z-index: 999;
.count__down__time {
width: 62px;
height: 20px;
font-size: 12px;
font-weight: 600;
color:rgba(36,0,119,1);
display: flex;
justify-content: center;
align-items: center;
position: absolute;
bottom: 4px;
left: 8px;
}
} }
\ No newline at end of file
...@@ -39,6 +39,9 @@ ...@@ -39,6 +39,9 @@
} }
.dec { .dec {
margin-top: 15px; margin-top: 15px;
a{
word-break:break-all;
}
} }
} }
......
import React, {Component} from 'react'
import './callback.scss'
import {http, getParam} from '@/utils'
import {Toast} from 'antd-mobile'
import {connect} from "react-redux";
class ExpandCallback extends Component {
state = {
data: ''
}
componentDidMount() {
this.getIndexData()
}
// 获取膨胀券相关
getIndexData = () => {
http.post(`${API['base-api']}/m/deposit/coupon`, {order_id: getParam('order_id')}).then((res) => {
if (res.data.errno == 200) {
const {data} = res.data
this.setState({
data: data,
})
} else {
Toast.info(res.data.msg, 2)
}
})
}
// 邀请好友助力
invitation = (url) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
window.location.href = url
}
}
render() {
let data = this.state.data
return (
<div className="callback-box">
<div className="banner"></div>
<div className="content">
<div className="title">恭喜你,获得一张</div>
<div className="coupon">
<p className="coupon-name">膨胀券</p>
<p className="coupon-price"><span>{data.amount}</span>元</p>
<p className="coupon-time">有效期至:{data.expire_time}</p>
</div>
<div className="tip">
<ul>
{
new Array(19).fill('1').map((item, index) => {
return <li key={index}/>
})
}
</ul>
全场通用
</div>
<div className="expand">
<span className="expand-small">{data.amount}</span>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand.png" alt=""/>
<span className="expand-big">{data.limit_amount}</span>
</div>
<button className="invitation"
onClick={() => this.invitation(data.share_url)}>邀请好友助力,{data.amount}元变{data.limit_amount}
</button>
<div className="active-time">活动时间:{data.start_time}-{data.end_time}</div>
<div className="active-tip">送助力好友{data.limit_amount}元!</div>
</div>
</div>
)
}
}
export default connect(
state => ({
user: state.user
}),
)(ExpandCallback)
.callback-box {
width: 100%;
height: 100%;
position: relative;
.banner {
width: 100%;
height: 258px;
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/bg-img.png");
background-repeat: no-repeat;
background-size: contain;
}
.content {
position: absolute;
top: 13px;
left: 10px;
width: 355px;
background-color: #fff;
border-radius: 4px;
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, .06);
padding: 18px 10px 25px 10px;
.title {
text-align: center;
color: #FF3131;
font-size: 18px;
font-weight:500;
}
.coupon {
background-color: #8361FE;
width: 335px;
height: 95px;
border-radius: 3px 3px 0 0;
margin-top: 10px;
padding: 10px 12px;
color: #fff;
p {
width: 100%;
text-align: center;
font-size: 12px;
}
.coupon-name {
text-align: left;
font-size: 14px;
height: 16px;
line-height: 16px;
}
.coupon-price {
height: 28px;
line-height: 28px;
span {
font-size: 26px;
}
}
.coupon-time {
margin-top: 3px;
}
}
.tip {
width: 335px;
height: 37px;
padding-left: 12px;
text-align: left;
font-size: 12px;
color: #666;
line-height: 37px;
background-color: #fff;
box-shadow: 0 2px 6px 0 rgba(0, 0, 0, .1);
border-radius: 0 0 3px 3px;
position: relative;
ul {
position: absolute;
top: -5px;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
li {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #fff;
}
}
}
.expand {
color: #FF3131;
margin-top: 15px;
font-size: 22px;
text-align: center;
img {
margin: 0 15px;
}
.expand-big {
font-size: 30px;
}
}
.invitation {
width: 320px;
height: 44px;
background-color: #8361FE;
border-radius: 4px;
font-size: 16px;
color: #fff;
margin-top: 15px;
border: none;
}
.active-time {
color: #999;
font-size: 14px;
margin-top: 10px;
text-align: center;
}
.active-tip {
color: #8361FE;
font-size: 16px;
margin-top: 13px;
text-align: center;
}
}
}
import React, {Component} from 'react'
import './share.scss'
import {http, getParam, browser, wxShare,is_weixin} from '@/utils'
import {Toast} from 'antd-mobile'
import {connect} from "react-redux";
import {Link} from "react-router-dom";
import showAlert from '@common/deposit/end-expansion-alert'
class ExpandShare extends Component {
state = {
isShow: false, //活动规则
step: 0, // 区分弹窗
data: '', //膨胀券相关
courseList: [], // 预售课程列表
isshowMore: true, // 是否显示查看更多
pageCount: 1, // 页码
helpData: '',// 帮助好友助力数据
courseListMore: '', // 所有课程
}
componentDidMount() {
this.getListorData()
this.getCourseList()
if(is_weixin()) {
wxShare({
title: 'AI充电节,预热来袭!80元红包送给你,手要快!',
desc: '积福气享1折秒课,超10万元奖品来就送--七月在线',
link: window.location.href,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/dj-share-img.png',
})
}
}
// 获取膨胀券相关
getListorData = () => {
http.get(`${API['base-api']}/sys/help_list/${getParam('deposit_code')}`).then((res) => {
const {data, errno, msg} = res.data
if (errno == 200) {
this.setState({
data: data
})
} else {
Toast.info(msg, 2)
}
})
}
// 获取课程列表
getCourseList = () => {
const _this = this
http.get(`${API['base-api']}/anniversary2019/pre_course`).then((res) => {
const {data, errno, msg} = res.data
if (errno == 200) {
if (JSON.stringify(data) == '{}') {
_this.setState({
isshowMore: false,
courseList: []
})
} else if (data.length <= 6) {
_this.setState({
isshowMore: false,
courseList: data
})
} else {
_this.setState({
isshowMore: true,
courseList: data.slice(0, 6),
courseListMore: data
})
}
} else {
Toast.info(msg, 2)
}
})
}
// 获取更多课程
getMoreCourseList = () => {
this.setState({
courseList: this.state.courseListMore,
isshowMore: false
})
}
// 立即付定金
expandPaydj = (courseId) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
this.props.history.push(
`/deposit-order?oid=${getParam('id')}&source=${1}`,
{
id: courseId,
isexpand: 1,
sourcenum: 1
}
)
}
}
// 立即付尾款
expandPaywk = (courseId, time, day) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
let timeStamp = Date.parse(new Date()) / 1000;
if (timeStamp >= time) {
this.props.history.push(
'/final-deposit-order?source=1',
{
id: courseId,
sourcenum: 1
}
)
} else {
Toast.info("付尾款时间将在" + day + "开启", 2);
}
}
}
// 去学习
tostudy = (courseId) => {
this.props.history.push(`/getDetail?id=${courseId}`)
}
// 显示活动规则
showRule = () => {
this.setState({
isShow: true,
step: 1
})
}
// 邀请好友
share = () => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
this.setState({
isShow: true,
step: 0
})
}
}
// 帮好友助力
helpFriend = (id) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
http.post(`${API['base-api']}/sys/help/${id}`).then((res) => {
const {data, errno, msg} = res.data
if (errno == 200) {
this.setState({
isShow: true,
step: 2,
helpData: data
})
this.getListorData()
} else if (errno === 17018 || errno === 17020) {
this.setState({
isShow: true,
step: 4
})
} else {
Toast.info(msg, 2)
}
})
}
}
// 结束助力
isendExpand = (data) => {
const {user, history} = this.props;
const uid = user && user.data && user.data.uid;
if (!uid) {
this.props.history.push('/passport/login')
} else {
const {amount, limit_amount, id} = data
showAlert({
amount,
limit_amount,
onCancel: () => {
this.setState({
isShow: false
})
},
onConfirm: () => {
http.post(`${API['base-api']}/sys/end_expansion`, {
id
})
.then(res => {
const {errno, msg} = res.data
if (errno == 200) {
this.setState({
isShow: false
})
this.getListorData()
} else {
Toast.info(msg)
}
})
}
})
}
}
// 关闭弹窗
close = () => {
this.setState({
isShow: false
})
}
render() {
const {isShow, step, data, courseList, isshowMore, helpData} = this.state
return (
<div className="expand-box">
<div className="banner">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/dj-banner.png" alt=""/>
<span onClick={() => this.showRule()}/>
</div>
<div className="all-contnet">
<div className="content">
{/*进度||膨胀券*/}
{
<ExpansionStatus data={data}/>
}
{/*button*/}
{
<ButtonStatus data={data} share={this.share} helpFriend={this.helpFriend}
isendExpand={this.isendExpand}/>
}
</div>
{/*好友助力列表*/}
{
(data.oneself === 1 || data.help_list && data.help_list.length !== 0) &&
<FriendList data={data}/>
}
{/*预售课程列表*/}
{
<CourseList data={courseList}
isshowMore={isshowMore}
getMoreCourseList={this.getMoreCourseList}
expandPaydj={this.expandPaydj}
expandPaywk={this.expandPaywk}
tostudy={this.tostudy}
/>
}
</div>
{
isShow &&
<div className='mbc-box'>
{
step === 0 &&
<ShareBox close={this.close} share={this.share} data={data}/>
}
{
step === 1 &&
<ActiveRule/>
}
{
step === 2 &&
<AssistanceSuccess share={this.share} data={data} helpData={helpData}/>
}
{
step === 4 &&
<AssistanceErron close={this.close}/>
}
{
(step === 1 || step === 2) &&
<img className="close"
onClick={() => this.close()}
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/Public/img/guanbi_icon.png"
alt=""/>
}
</div>
}
</div>
)
}
}
// 活动规则
function ActiveRule() {
return (
<div className='content active-rule'>
<div className="title">活动规则</div>
<p>1、本活动期间,可以助力1位好友不同课程发起的膨胀,但是只能为同一好友;</p>
<p>2、好友发起膨胀后,可以随时终止膨胀;</p>
<p>3、膨胀券膨胀完成后,以优惠券形式发放到参与活动的账号(包括所有助力好友),该膨胀券为全场通用券,可在购买任一课程后进行抵扣(包括已付定金课程);</p>
<p>4、如有疑问,可联系七月在线客服微信:julyedukefu</p>
<p>*本活动最终解释权归七月在线所有</p>
</div>
)
}
// 邀请好友 分享弹窗
function ShareBox(props) {
const {close, data} = props
return (
<div className='content'>
<div onClick={() => close()} className="fiexd"></div>
<div className="share-box">
{
browser.isWeixin &&
<img src="//julyedu-cdn.oss-cn-beijing.aliyuncs.com/share/throw_icon.png" alt=""/>
}
<p>邀请好友助力</p>
<p>膨胀券翻倍膨胀,{data.start_amount}元变{data.limit_amount}元!</p>
<span>送助力好友{data.limit_amount}</span>
</div>
</div>
)
}
//助力成功弹窗
function AssistanceSuccess(props) {
const {helpData, share, data} = props
return (
<div className='content assistance-success'>
<div className="title">助力成功</div>
<p className="add-price">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/add-money.png" alt=""/>
+{helpData.help_amount}
</p>
<p className="all-price">
<span>{helpData.sale_amount}</span>
</p>
<p className="assistance-tip">感谢你的助力,你们离{data.limit_amount}元又更近了哦!<br/>可以邀请其他小伙伴一起助力~</p>
<button onClick={() => share()}>邀请更多好友拿{data.limit_amount}</button>
</div>
)
}
// 助力失败弹窗
function AssistanceErron(props) {
const {close} = props
return (
<div className="content assistance-erron">
<div className="title">温馨提示</div>
<p>很遗憾~</p>
<p>你已经帮别的好友助过力了,</p>
<p>不能再帮这位好友助力!</p>
<button onClick={() => close()}>知道了</button>
</div>
)
}
// 判断是否结束膨胀
function ExpansionStatus(props) {
const {data} = props
//is_end: 0 判断活动是否结束 0否1是
// is_end_expansion: 0,是否是自己结束膨胀 0否1是
if (data.is_end === 0 && data.is_end_expansion === 0) {
return (
<ProgressData data={data}/>
)
} else {
return (
<EndExpansion data={data}/>
)
}
}
// 没有结束膨胀的情况
function ProgressData(props) {
const data = props.data
return (
<div>
<div className="user-mess">
<img src={data.avatar_file} alt="user"/>
帮我助力,送你{data.limit_amount}
</div>
<div className="progress-box">
<div className="progress-base">
<span className="progress-active"
style={{width: (data.amount - data.start_amount) / data.limit_amount * 100 + '%'}}>
<span className="ending">
<span className="tip">{data.amount} <i/></span>
</span>
</span>
</div>
<div className="progress-price">
<span>{data.start_amount}</span>
<span>{data.limit_amount}</span>
</div>
</div>
{
data.help_list.length === 0 &&
<div className="help-mess no">还没有好友为{data.oneself === 1 ? '你' : 'Ta'}助力哦~</div>
}
{
data.help_list.length > 0 &&
<div className="help-mess has">已有<span className="FF19A0">{data.help_list.length}</span>位好友助力</div>
}
</div>
)
}
// 结束膨胀的情况
function EndExpansion(props) {
const data = props.data
return (
<div className='coupon-box'>
<div className="coupon">
<p className="coupon-name">红包膨胀优惠券</p>
<p className="coupon-price"><span>{data.amount}</span>元</p>
<p className="coupon-time">有效期至:{data.expire_time}</p>
</div>
<div className="tip">
<ul>
{
new Array(19).fill('1').map((item, index) => {
return <li key={index}/>
})
}
</ul>
全场通用
</div>
<p className="over-mess">该礼券已成功发放至账户</p>
<p className="over-mess">可在七月在线pc/app-我的-优惠券查看</p>
</div>
)
}
// 按钮
function ButtonStatus(props) {
const {data, share, helpFriend, isendExpand} = props
// data.oneself 判断是否是自己 0帮好友助力 1自己
// data.is_help 是否已经帮好友助力 0 未助力 1已助力
// data.s_end: 0 判断活动是否结束 0否1是
// data.is_end_expansion: 0,是否是自己结束膨胀 0否1是
return (
<div>
{
data.is_end === 0 &&
<div className='btns'>
{
data.oneself === 1 && data.is_end_expansion === 0 &&
<button className="active" onClick={() => share()}>邀请好友助力</button>
}
{
data.oneself === 1 && data.is_end_expansion === 1 && data.amount !== data.limit_amount &&
<button className="over">您已结束膨胀</button>
}
{
data.oneself === 1 && data.is_end_expansion === 1 && data.amount === data.limit_amount &&
<button className="over">达到膨胀上限,快去使用吧</button>
}
{
data.oneself === 0 && data.is_help === 0 && data.is_end_expansion === 0 &&
<button className="active" onClick={() => helpFriend(data.id)}>ta助力</button>
}
{
data.oneself === 0 && data.is_help === 1 && data.is_end_expansion === 0 &&
<button className="active" onClick={() => share()}>邀请更多好友拿{data.limit_amount}</button>
}
{
data.oneself === 0 && data.is_end_expansion === 1 && data.amount === data.limit_amount &&
<button className="over">达到膨胀上限,快去使用吧</button>
}
{
data.oneself === 0 && data.is_end_expansion === 1 && data.amount !== data.limit_amount &&
<button className="over">你的好友已结束助力</button>
}
</div>
}
{
data.is_end === 1 &&
<div className="btns">
<button className="over">活动已结束</button>
</div>
}
{
data.is_end === 0 && data.is_end_expansion === 0 && data.oneself === 1 &&
<div className="overBtn">
<p onClick={() => isendExpand(data)}>结束助力使用礼券</p>
</div>
}
</div>
)
}
// 好友助力列表
function FriendList(props) {
const data = props.data
return (
<div className="friend-list">
<p className="title">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand-right.png" alt=""/>
<span>好友助力</span>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand-left.png" alt=""/>
</p>
{
data.help_list.length === 0 &&
<div className="null-list">
<p className="tips first-tips">还没有好友为你助力,</p>
<p className="tips">赶紧去邀请好友吧!</p>
</div>
}
{
data.help_list.length > 0 &&
<div className="all-list">
<p className="friend-status"><span className="FF19A0">{data.help_list.length}</span>位好友共助力<span
className="FF19A0">{data.amount - data.start_amount}</span>元</p>
<ul className="all-list-box">
{
data.help_list.map((item, index) => {
return (
<li className="item" key={index}>
<img className="avait" src={item.avatar} alt=""/>
<span className="time">助力时间:{item.add_time}</span>
<span className="zlprice FF19A0">{item.amount}</span>
</li>
)
})
}
</ul>
</div>
}
</div>
)
}
//预售课程
function CourseList(props) {
const {data, isshowMore, getMoreCourseList, expandPaydj, expandPaywk, tostudy} = props
return (
<div className="advance-sale-course">
<p className="title">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand-right.png" alt=""/>
<span>预售课程</span>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand-left.png" alt=""/>
</p>
<div className="course-list">
<ul>
{
data.map((item, index) => {
return (
<li className="course-item" key={index}>
<Link to={`/getDetail?id=${item.course_id}`}>
<img className="course-img" src={item.image_name} alt=""/>
</Link>
<p className="old-price">原价:<span>¥{item.price}</span></p>
<p className="handsel">定金¥{item.deposit_amount},可抵扣¥{item.deduction_amount}</p>
<div className="btn">
{
item.is_buy === 0 &&
<a className="to-expand-buy1"
onClick={() => expandPaydj(item.course_id)}>立即付定金</a>
}
{
item.is_buy === 1 &&
<a className="to-expand-buy2"
onClick={() => expandPaywk(item.course_id, item.start_timestamp, item.final_start_time)}>立即付尾款</a>
}
{
item.is_buy === 2 &&
<button className="to-study"
onClick={() => tostudy(item.course_id)}>开始学习</button>
}
</div>
</li>
)
})
}
</ul>
</div>
{
isshowMore &&
<div className="more">
<div onClick={() => getMoreCourseList()}>
查看更多
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/expand-btm.png"
alt=""/>
</div>
</div>
}
</div>
)
}
export default connect(
state => ({
user: state.user
}),
)(ExpandShare)
.expand-box {
width: 100%;
height: 100%;
position: relative;
.FF19A0{
color: #FF19A0;
}
.banner {
width: 100%;
height: 323px;
position: relative;
z-index: 1;
span {
position: absolute;
top: 48px;
right: 22px;
width: 30px;
height: 83px;
}
}
.all-contnet {
position: absolute;
top: 180px;
width: 100%;
background-color: #f5f5f5;
.content {
position: relative;
z-index: 2;
background-color: #fff;
width: 355px;
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, .06);
padding: 17px 19px;
border-radius: 8px 8px 4px 4px;
margin-left: 10px;
.user-mess {
text-align: left;
color: #111;
font-size: 14px;
img {
width: 24px;
height: 24px;
border-radius: 50%;
vertical-align: middle;
margin-right: 9px;
}
}
.progress-box {
margin-top: 50px;
.progress-base {
width: 318px;
height: 8px;
line-height: 8px;
background-color: #DCDCDC;
border-radius: 4px;
text-align: left;
.progress-active {
display: inline-block;
height: 100%;
border-radius: 4px;
background-color: #FF19A0;
padding-left: 10px;
position: relative;
.ending {
display: inline-block;
width: 14px;
height: 14px;
border-radius: 50%;
background-color: #fff;
position: absolute;
right: 0;
top: -3px;
border: 3px solid #FF19A0;
.tip {
display: inline-block;
width: 55px;
height: 20px;
line-height: 21px;
background-color: #FF19A0;
border-radius: 3px;
position: absolute;
top: -30px;
left: -23px;
text-align: center;
color: #fff;
i {
display: inline-block;
width: 6px;
height: 6px;
background-color: #FF19A0;
transform: rotate(45deg);
position: absolute;
bottom: -3px;
left: 50%;
margin-left: -3px;
}
}
}
}
}
.progress-price {
width: 100%;
display: flex;
justify-content: space-between;
color: #FF19A0;
font-size: 14px;
margin-top: 3px;
}
}
.help-mess {
font-size: 15px;
margin-top: 10px;
text-align: center;
}
.no {
color: #666;
}
.has {
color: #000011;
}
.coupon-box {
.coupon {
background-color: #8361FE;
width: 316px;
height: 85px;
border-radius: 3px 3px 0 0;
padding: 10px 12px;
color: #fff;
p {
width: 100%;
text-align: center;
font-size: 12px;
}
.coupon-name {
text-align: left;
font-size: 14px;
height: 16px;
line-height: 16px;
}
.coupon-price {
height: 28px;
line-height: 28px;
span {
font-size: 26px;
}
}
}
.tip {
width: 316px;
height: 33px;
padding-left: 12px;
text-align: left;
font-size: 12px;
color: #666;
line-height: 33px;
background-color: #fff;
box-shadow: 0 6px 12px 0 rgba(131, 97, 254, 0.1);
border-radius: 0 0 3px 3px;
position: relative;
margin-bottom: 16px;
ul {
position: absolute;
top: -5px;
left: 0;
width: 100%;
display: flex;
justify-content: space-around;
li {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #fff;
}
}
}
.over-mess {
text-align: center;
font-size: 12px;
color: #333;
}
}
.btns {
button {
width: 318px;
height: 44px;
border-radius: 22px;
box-shadow: 0 6px 12px 0 rgba(131, 97, 254, 0.1);
color: #fff;
font-size: 16px;
border: none;
}
.active {
margin-top: 25px;
background-color: #8361FE;
}
.over {
margin-top: 15px;
background-color: #CCCCCC;
}
}
.overBtn {
width: 100%;
margin-top: 15px;
font-size: 14px;
color: #666;
text-decoration: underline;
text-align: center;
}
}
.friend-list {
width: 100%;
margin-top: 12px;
padding: 17px 28px 24px 28px;
background-color: #fff;
.title {
font-size: 18px;
color: #111;
font-weight: 500;
text-align: center;
margin: 0 5px;
img {
width: 59px;
height: 11px;
vertical-align: middle;
}
span {
margin: 0 10px;
}
}
.null-list {
text-align: center;
margin-bottom: 20px;
.tips {
font-size: 15px;
color: #999;
margin-top: 5px;
}
.first-tips {
margin-top: 35px;
}
}
.all-list {
margin-top: 10px;
.friend-status {
font-size: 14px;
color: #333;
text-align: center;
}
.all-list-box {
margin-top: 7px;
width: 100%;
.item {
margin-top: 15px;
height: 24px;
line-height: 24px;
text-align: left;
font-size: 14px;
.avait {
width: 24px;
height: 24px;
border-radius: 50%;
vertical-align: middle;
}
.time {
margin-left: 26px;
}
.zlprice {
float: right;
}
}
}
}
}
.advance-sale-course {
width: 100%;
margin-top: 12px;
background-color: #fff;
padding: 15px 10px 20px 10px;
.title {
text-align: center;
font-size: 18px;
color: #111;
font-weight: 500;
img {
width: 59px;
height: 11px;
vertical-align: middle;
}
span {
margin: 0 10px;
}
}
.course-list {
margin-top: 15px;
ul {
display: flex;
justify-content: space-between;
flex-direction: row;
flex-wrap: wrap;
.course-item {
width: 48.4%;
background-color: #fff;
padding-bottom: 14px;
box-shadow: 0 3px 6px 0 rgba(0, 0, 0, .06);
border-radius: 2px;
margin-bottom: 10px;
text-align: left;
margin-top: 0;
.course-img {
width: 100%;
height: 124px;
border-radius: 2px;
}
.old-price {
margin-top: 8px;
font-size: 12px;
color: #999;
padding-left: 10px;
span {
font-size: 15px;
color: #FF3131;
}
}
.handsel {
margin-top: 5px;
font-size: 12px;
color: #666;
padding-left: 10px;
}
.btn {
width: 100%;
padding: 0 10px;
margin-top: 12px;
button {
width: 100%;
height: 27px;
border-radius: 2px;
font-size: 12px;
color: #fff;
border: none;
}
.to-expand-buy1, .to-expand-buy2 {
display: inline-block;
width: 100%;
text-align: center;
height: 27px;
line-height: 27px;
border-radius: 2px;
font-size: 12px;
color: #fff;
}
.to-expand-buy1 {
background-color: #8361FE;
}
.to-expand-buy2 {
background-color: #FF4000;
}
.to-study {
background-color: #0099FF;
}
}
}
}
}
.more {
font-size: 14px;
color: #666;
height: 56px;
line-height: 56px;
text-align: center;
div {
width: 130px;
margin: auto;
}
img {
width: 13px;
height: 12px;
margin-left: 8px;
margin-top: -3px;
vertical-align: middle;
}
}
}
}
.mbc-box {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
background: rgba(0, 0, 0, .6);
z-index: 3;
.content {
border-radius: 8px;
background-color: #fff;
margin: 0 auto 24px auto;
width: 300px;
.title {
text-align: center;
font-size: 21px;
color: #333;
font-weight: 600;
}
}
.active-rule {
margin-top: 122px;
padding: 20px;
p {
text-align: left;
font-size: 14px;
color: #666;
margin-top: 15px;
}
}
.fiexd {
position: fixed;
top: 0;
bottom: 0;
right: 0;
left: 0;
}
.share-box {
padding: 17px 0 20px 0;
margin-top: 100px;
text-align: center;
position: relative;
img {
position: absolute;
width: 60px;
height: 44px;
right: 0;
top: -48px;
}
p {
color: #333;
font-size: 15px;
margin-bottom: 10px;
height: 17px;
line-height: 17px;
}
span {
display: inline-block;
color: #999;
font-size: 12px;
margin-top: 10px;
height: 14px;
line-height: 14px;
}
}
.assistance-success {
margin-top: 197px;
text-align: center;
padding: 20px 0;
.add-price {
margin-top: 10px;
color: #FF3131;
font-size: 12px;
img {
width:8px;
height: 12px;
vertical-align: text-top;
}
}
.all-price {
margin-top: 10px;
color: #FF3131;
font-size: 12px;
span {
font-size: 30px;
}
}
.assistance-tip {
margin-top: 10px;
color: #999;
font-size: 14px;
}
button {
width: 225px;
height:36px;
background-color: #8361FE;
box-shadow: 0 6px 12px 0 rgba(131, 97, 254, .1);
border-radius: 18px;
color: #fff;
font-size: 15px;
margin-top: 20px;
border: none;
}
}
.assistance-erron {
margin-top: 220px;
text-align: center;
padding: 20px 0;
.title {
margin-bottom: 15px;
}
p {
color: #666;
font-size: 14px;
margin-top: 8px;
}
button {
margin-top: 15px;
width: 146px;
height: 33px;
background-color: #8361FE;
border-radius: 17px;
color: #fff;
font-size: 15px;
border: none;
}
}
.close {
width: 30px;
height: 30px;
position: absolute;
left: 50%;
margin-left: -15px;
}
}
}
\ No newline at end of file
...@@ -16,6 +16,7 @@ const alert = Modal.alert ...@@ -16,6 +16,7 @@ const alert = Modal.alert
@connect() @connect()
class MyOrders extends Component { class MyOrders extends Component {
page = 1 page = 1
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
...@@ -31,7 +32,7 @@ class MyOrders extends Component { ...@@ -31,7 +32,7 @@ class MyOrders extends Component {
} }
getMore = debounce(() => { getMore = debounce(() => {
if(this.state.data.length % 10 === 0){ if (this.state.data.length % 10 === 0) {
this.getList(++this.page) this.getList(++this.page)
} }
}, 200) }, 200)
...@@ -74,7 +75,7 @@ class MyOrders extends Component { ...@@ -74,7 +75,7 @@ class MyOrders extends Component {
} }
toCourseDetail = (id) => { toCourseDetail = (id) => {
const { dispatch, history } = this.props; const {dispatch, history} = this.props;
// dispatch(getCourses(id, () => { // dispatch(getCourses(id, () => {
history.push(`/detail?id=${id}`); history.push(`/detail?id=${id}`);
return false; return false;
...@@ -88,7 +89,7 @@ class MyOrders extends Component { ...@@ -88,7 +89,7 @@ class MyOrders extends Component {
<HeaderBar title='我的订单' arrow={true} cart={false}></HeaderBar> <HeaderBar title='我的订单' arrow={true} cart={false}></HeaderBar>
<Loading isLoading={this.state.isLoading}> <Loading isLoading={this.state.isLoading}>
{ {
this.state.data && JSON.stringify(this.state.data) !== '[{}]'? this.state.data && JSON.stringify(this.state.data) !== '[{}]' ?
<InfiniteScroll <InfiniteScroll
pageStart={0} pageStart={0}
hasMore={true} hasMore={true}
...@@ -104,10 +105,9 @@ class MyOrders extends Component { ...@@ -104,10 +105,9 @@ class MyOrders extends Component {
item.course && item.course.length > 0 && item.course.map((item, index) => { item.course && item.course.length > 0 && item.course.map((item, index) => {
const Info = ( const Info = (
<div className="order-info"> <div className="order-info">
<p className='order-title text-overflow-one' onClick={() => this.toCourseDetail(item.course_id)}> <p className='order-title text-overflow-one'
{/* <Link to={`/detail?id=${item.course_id}`}> */} onClick={() => this.toCourseDetail(item.course_id)}>
{item.course_title} {item.course_title}
{/* </Link> */}
</p> </p>
<p className='order-content text-overflow-2'>{item.description}</p> <p className='order-content text-overflow-2'>{item.description}</p>
<p className='order-des'> <p className='order-des'>
...@@ -133,6 +133,14 @@ class MyOrders extends Component { ...@@ -133,6 +133,14 @@ class MyOrders extends Component {
} }
<PayInfo item={item} cancel={this.cancel}/> <PayInfo item={item} cancel={this.cancel}/>
{
item.type == 5 && item.is_buy == 0 &&
<div className={'expand-pay-wk'}>
<span className={'expand-pay-time'}>{item.final_end_time}结束付尾款</span>
<span>还需支付尾款</span>
</div>
}
</div> </div>
) )
}) })
...@@ -167,16 +175,25 @@ function OrderInfo(props) { ...@@ -167,16 +175,25 @@ function OrderInfo(props) {
} }
function PayInfo(props) { function PayInfo(props) {
// type 0普通订单 1团购 2小团 3砍价 4单集购买 5定金课定金 6定金课尾款
let type = ''
if (props.item.type == 5) {
type = '(定金)'
}
if (props.item.type == 6) {
type = '(尾款)'
}
return ( return (
<div className='order-btm'> <div className='order-btm'>
<div className='price-info'> <div className='price-info'>
<p> <p>
<span className='payable'>应付:</span> <span className='payable'>应付{type}</span>
<span className='price'>¥{props.item.pay_amount}</span> <span className='price'>¥{props.item.pay_amount}</span>
</p> </p>
<p> <p>
<span className='payable'>已优惠:</span> <span className='payable'>已优惠:</span>
<span className='price'>¥{props.item.deposit_cut}</span> <span className='price'>¥{props.item.discount}</span>
</p> </p>
</div> </div>
......
...@@ -25,7 +25,8 @@ ...@@ -25,7 +25,8 @@
font-size: 14px; font-size: 14px;
color: $redprice; color: $redprice;
} }
.oid-success{
.oid-success {
font-size: 14px; font-size: 14px;
color: $color_333; color: $color_333;
} }
...@@ -37,8 +38,9 @@ ...@@ -37,8 +38,9 @@
background-color: $bg_fff; background-color: $bg_fff;
border-bottom: 1px solid $border_e7eaf1; border-bottom: 1px solid $border_e7eaf1;
} }
.order-info { .order-info {
.order-des{ .order-des {
position: absolute; position: absolute;
bottom: 0; bottom: 0;
} }
...@@ -53,7 +55,7 @@ ...@@ -53,7 +55,7 @@
justify-content: space-between; justify-content: space-between;
.price-info { .price-info {
width: 120px; width: 150px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-self: center; align-self: center;
...@@ -105,6 +107,26 @@ ...@@ -105,6 +107,26 @@
} }
} }
} }
.expand-pay-wk {
height: 35px;
background-color: $bg_fff;
line-height: 35px;
padding: 0 10px;
font-size: 12px;
display: flex;
justify-content: space-between;
border-top: 1px solid #E7EAF1;
span {
color: #999;
}
.expand-pay-time {
color: #09f;
}
}
} }
.cart-tip { .cart-tip {
......
import React, { Component } from 'react'
import { Flex, List, Toast } from 'antd-mobile'
import { OrderItem } from '@common/index'
import { Link } from 'react-router-dom'
import { http, getParam } from "@/utils"
import { HeaderBar } from '@common/index'
import "./index.scss"
const Item = List.Item
function OrderList(props) {
const listData = props.list
return (
<div>
{
listData.map((item, index) => {
const {is_coupon, course_id, image_name, sale_price, simpledescription, course_title, coupon_num, coupon_desc} = item
let NewPrice = (<span className='order-newprice'>¥{sale_price}</span>)
if (props.locationState && props.locationState.group) {
NewPrice = (<span className='order-newprice'>¥{props.groupPrice}</span>)
}
const Info = (
<div className="order-info">
<p
className='order-title'
style={{
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'
}}
onClick={() => props.toDetail(course_id)}
>
{course_title}
</p>
<p className='order-content' style={{
WebkitBoxOrient: 'vertical',
WebkitLineClamp: '2',
wordBreak: 'break-all',
overflow: 'hidden',
textOverflow: 'ellipsis',
display: '-webkit-box'
}}>{simpledescription}</p>
<p className='order-des'>
{NewPrice}
<span className={'price-des'}>(预付定金)</span>
</p>
</div>
)
return (
<OrderItem
{...item}
src={image_name}
id={course_id}
key={index}
info={Info}
isaist={props.isaist}
toDetail={props.toDetail}
>
{
(props.locationState && (props.locationState.type || props.locationState.simple)) ? (
<div className="order-prefer">
<List key={index}>
<Item
arrow="horizontal"
onClick={() => {
}}
>
<Link to={{
pathname: `/coupons`,
search: `?id=${course_id}`,
state: {
from: '/order'
}
}}>
<Flex justify='between'>
<span
style={{
color: '#333',
fontSize: '15px'
}}
>优惠券</span>
<span
style={{
fontSize: '14px',
color: '#999999'
}}
>
{!coupon_desc ? (coupon_num === 0 ? '无' : `${coupon_num}张可用`) : (coupon_desc)}
</span>
</Flex>
</Link>
</Item>
</List>
</div>
) : null
}
</OrderItem>
)
})
}
</div>
)
}
class Order extends Component {
constructor(props) {
super(props)
this.state = {
groupPrice: '',
total: 0.00, // 需要支付总金额
discount: 0.00, //
useBalance: false,
orderList: [],
info: false,
offset: 0,
depositPrice: 0,
course_id: getParam('oid'),
user_account: '',
finalStartTime: '',
}
}
// 提交订单
submitOrder = () => {
http.post(`${API["base-api"]}/m/deposit/create`, {
plat_form: 5,
source: getParam('source'), //来源 1-详情页 2-活动页,
course_id: this.state.course_id,
is_deduction: this.state.useBalance ? 1 : 0
}).then(res => {
const {data} = res
if (data.errno == 200) {
if (data.data['pay_jump']) {
this.props.history.replace(`/expand/callback?order_id=${data.data['order_id']}`)
} else {
this.props.history.replace({
pathname: '/deposit-pay-order',
search: `?oid=${data.data['order_id']}`
})
}
} else {
Toast.info(data.msg)
}
})
}
showInfo = () => {
this.setState((prevState) => ({
info: !prevState.info
}))
}
componentDidMount() {
http.post(`${API["base-api"]}/m/deposit/preorder`, {
course_id: this.state.course_id
})
.then(res => {
const {data} = res
if (data.errno == 200) {
this.setState({
orderList: [data.data.course],
depositPrice: data.data.course['sale_price'],
user_account: data.data['user_account'],
finalStartTime: data.data['final_start_time']
})
} else {
Toast.info(data.msg)
}
})
};
toCourseDetail = (id) => {
const {history} = this.props
history.push(`/detail?id=${id}`)
}
useBalance = () => {
let {user_account, depositPrice} = this.state
if (parseFloat(user_account) === 0) {
return
}
let offset = parseFloat(user_account) - parseFloat(depositPrice)
offset = offset > 0 ? depositPrice : user_account
this.setState(prevState => ({useBalance: !prevState.useBalance, offset}))
}
updateUserAccount = () => {
}
render() {
const {
orderList,
discount,
groupPrice,
depositPrice,
user_account,
useBalance,
info,
offset,
finalStartTime
} = this.state
return (
<div className="order-wrapper">
<Flex>
<Flex.Item>
<HeaderBar title='课程报名' arrow={true}/>
<div className="order-list">
<OrderList
list={orderList}
courseId={getParam('id')}
locationState={this.props.location.state}
groupPrice={groupPrice}
toDetail={this.toCourseDetail}
/>
</div>
<div className="order-balance">
<List>
<Item
className="order-prefer-text"
>
<Flex justify='between'>
<Flex align='center'>
<span>余额抵扣</span>
<span className="order-balanceprice"> (余额: <i
className="order-money">{`${user_account}元`}</i>)</span>
<i className="iconfont iconiconfront-22 question-mark"
onClick={this.showInfo}></i>
</Flex>
<Flex>
{
useBalance ? (
<>
<span style={{
color: '#FF2121',
fontSize: '15px',
marginRight: "6px"
}}>{`-¥${offset}`}</span>
<i className={`iconfont icondanseshixintubiao-5 balance-used`}
onClick={this.useBalance}></i>
</>
) : (
<i className='circle-icon' onClick={this.useBalance}></i>
)
}
</Flex>
</Flex>
</Item>
</List>
</div>
<ul className={'deposit-limit-time'}>
<li>· {finalStartTime}开始支付尾款</li>
<li>· 代金券只能在支付尾款时使用</li>
</ul>
<div className="order-bar">
<div className="order-course">
<span className="order-course-text">{`${orderList.length}门课程`}</span>
</div>
<div className="order-bar-text">
<div className="order-amount">
<span className="order-amount-title">合计:</span>
<span className="order-amount-price">{`¥${depositPrice}`}</span>
</div>
<div className="order-preprice">
<span className="order-preprice-title">已优惠:</span>
<span className="order-preprice-price">{${discount}`}</span>
</div>
</div>
<button type="button" className="order-button has-info">
<span className="order-button-text" onClick={this.submitOrder}>确定订单</span>
</button>
</div>
</Flex.Item>
</Flex>
{
info ? (
<div style={{
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
zIndex: '99'
}}>
<div style={{
padding: '20px',
backgroundColor: '#FFF',
width: '300px',
height: '170px',
margin: '0 auto',
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)'
}}>
<Flex direction='column' justify='between' align='center' style={{height: '100%'}}>
<p style={{fontSize: '16px', color: '#333333'}}>余额抵扣说明</p>
<p style={{
lineHeight: '20px',
fontSize: '13px',
color: '#666666'
}}>分销课程或者参与七月在线的相关活动,可获得资金奖励。账户资金可直接提现,也可抵扣课程费用。</p>
<div onClick={this.showInfo} style={{
width: '260px',
height: '30px',
lineHeight: '30px',
textAlign: 'center',
borderRadius: '3px',
border: '1px solid #0099FF',
color: '#0099FF',
fontSize: '15px'
}}>知道了
</div>
</Flex>
</div>
</div>
) : null
}
</div>
)
}
}
export default Order
.order-wrapper {
width: 100%;
height: 100vh;
margin-bottom: 50px;
background-color: $bg_f5f5f5;
.order-tab {
color: $black;
background: $bg_f7f9fc;
}
.order-information {
display: flex;
width: 100%;
overflow: hidden;
padding: 29px 15px;
color: $color_555;
background-color: $bg_fff;
position: relative;
}
.order-information::before {
content: '';
left: 0;
right: 0;
bottom: 0;
height: 2px;
position: absolute;
background: -webkit-repeating-linear-gradient(135deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background: repeating-linear-gradient(-45deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background-size: 80px;
}
.order-information2 {
height: 80px;
background-color: #FFF;
margin-top: 8px;
position: relative;
.user-icon {
font-size: 28px;
flex-basis: 40px;
}
.order-cell {
height: 50px;
font-size: 13px;
color: $color_333;
line-height: 20px;
flex: 1 1 auto;
.name {
margin-bottom: 10px;
}
}
}
.order-information2::before {
content: '';
left: 0;
right: 0;
bottom: 0;
height: 2px;
position: absolute;
background: -webkit-repeating-linear-gradient(135deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background: repeating-linear-gradient(-45deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background-size: 80px;
}
.order-addsize {
font-size: 22px !important;
margin-bottom: 0px;
height: 22px;
color: $active;
line-height: 22px;
}
.order-next {
line-height: 22px;
margin-bottom: 0px;
}
.order-list {
margin-top: 8px;
background-color: #F5F5F5;
.public-content {
padding: 10px 15px;
}
}
.order-infotext {
flex: 1;
height: 22px;
line-height: 22px;
margin-left: 10px;
font-size: $font_14;
color: $color_555;
}
.order-info {
color: $color_666;
font-size: $font_14;
min-width: 160px;
flex: 1 1 auto;
display: flex;
flex-direction: column;
justify-content: space-around;
.order-title {
color: $color_333;
font-size: $font_16;
}
.order-content {
color: $color_666;
font-size: $font_14;
line-height: 18px;
}
.order-newprice {
color: $redprice;
font-size: $font_16;
margin-right: 8px;
}
.price-des{
color: #999;
font-size: 11px;
}
}
.order-bar {
width: 100%;
position: fixed;
bottom: 0;
z-index: 2;
height: 50px;
display: flex;
font-size: 14px;
align-items: center;
background-color: $bg_fff;
}
.order-course {
margin-left: 20px;
.order-course-text {
font-size: $font_16;
color: $color_333;
}
}
.order-bar-text {
flex: 1;
text-align: right;
color: #323233;
padding-right: 20px;
.order-amount {
font-size: $font_14;
color: $color_333;
.order-amount-price {
color: $redprice;
}
}
.order-preprice {
font-size: $font_12;
color: $color_555;
}
}
.order-button {
width: 110px;
height: 50px;
display: inline-block;
padding: 0;
background-color: $bg_ff9898;
color: $white;
line-height: 48px;
font-size: 16px;
border-radius: 0px;
text-align: center;
box-sizing: border-box;
-webkit-appearance: none;
-webkit-text-size-adjust: 100%;
border: 1px solid transparent;
}
.has-info {
background-color: #FF3131;
}
.v-list-item {
margin-top: 8px;
padding: 10px 15px 0 15px;
.content {
border-bottom: none;
}
}
.order-prefer {
.am-list-body{
&::after{
display: none;
}
}
.am-list-content {
font-size: 15px !important;
}
.am-list-line {
padding: 0 15px;
}
}
.am-list-item .am-list-line .am-list-content {
color: $color_333;
}
.order-list {
.am-list-item {
padding-left: 0 !important;
}
}
.deposit-limit-time{
background: #fff;
padding: 11px 15px;
border-top: 1px solid #E5E5E5;
border-bottom: 1px solid #E5E5E5;
font-size: 13px;
color: #666;
line-height: 1.7;
}
.order-balance {
line-height: 44px;
background: #fff;
margin: 8px 0;
.am-list-item {
padding-left: 0 !important;
}
.am-list-line {
padding: 0 15px;
}
.am-list-content {
color: $color_333;
font-size: $font_16;
.iconiconfront-22 {
font-size: 18px;
margin-left: 15px;
}
}
.order-balanceprice {
color: $color_666;
font-size: $font_12;
.order-money {
color: #ff2121;
font-size: $font_12 !important;
font-weight: normal;
font-style: inherit;
vertical-align: middle;
margin: 0;
}
}
.iconiconfront-22.question-mark {
font-size: 24px;
margin-left: 15px;
}
.am-list-body {
&::before, &::after {
display: none;
}
}
.balance-used {
font-size: 24px;
color: #0099FF;
}
.circle-icon {
width: 20px;
height: 20px;
border: 1px solid #BFBFBF;
border-radius: 50%;
margin-right: 2px;
}
}
}
import React, { Component } from 'react'
import { Flex, WingBlank, WhiteSpace, List, Radio, Toast, Checkbox } from 'antd-mobile'
import { http, getParam, is_weixin, browser } from '@/utils'
import { OrderItem, HeaderBar } from '@common/index'
import { Link } from 'react-router-dom'
import './index.scss'
import { VList } from '@/common'
import { WithFullSize } from '@/HOCs'
import classnames from 'classnames'
const RadioItem = Radio.RadioItem
let mockData = []
if (browser.isWeixin) {
mockData = [
{value: 1, label: '微信支付', icon: 'iconweixinzhifu'}
]
} else {
mockData = [
{value: 1, label: '微信支付', icon: 'iconweixinzhifu'},
{value: 0, label: '支付宝', icon: 'iconalipay'},
]
}
class PayOrder extends Component {
constructor(props) {
super(props)
this.state = {
pay_amount: 0,
payType: 1,
stageNumber: 0,
checkPeriod: false,
singleMoney: 0,
periodNumber: 0,
orderId: getParam('oid'),
huabei: false,
fenqiList: [
{value: 'zhifubao', qishu: '3', lilv: '2.30%', everyMoney: 300, feiyong: 2.3},
{value: 'weixin', qishu: '6', lilv: '4.50%', everyMoney: 150, feiyong: 4.5},
{value: 'huabei', qishu: '9', lilv: '7.50%', everyMoney: 100, feiyong: 7.5},
],
categoryList: [],
agree: false
}
}
onChange = (value) => {
this.setState({
payType: value,
checkPeriod: false,
})
if (value === 2) {
this.setState({
huabei: true,
})
}
}
// 确定购买
pay = () => {
const {payType, orderId} = this.state
if(!this.state.agree){
return
}
if (payType === 0) {
this.alipayPay(orderId)
} else if (payType === 1) {
this.weixinPay(orderId)
}
}
// 微信支付
weixinPay = (orderId) => {
// 微信内部-支付
if (is_weixin()) {
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
} else {
// 微信外部-支付
http.get(`${API['base-api']}/pay/wxpay/wap_charge/oid/${orderId}`).then((res) => {
if (res.data.errno === 0) {
window.location.href = res.data.data.url + "&redirect_url=" + encodeURIComponent(window.location.href + "&weixinpay=1").toLowerCase()
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
// 微信内部支付
isweixinPay = () => {
let _this = this
let weixin_code = getParam('code')
if (weixin_code) {
if (getParam('oid') === undefined) {
return
} else {
http.get(`${API['base-api']}/pay/wxpay/pub_charge/oid/${getParam('oid')}/code/${weixin_code}`).then((res) => {
if (res.data.errno === 0) {
let data = res.data.data
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: data.appId, //公众号名称,由商户传入
timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数
nonceStr: data.nonceStr, //随机串
package: data.package,
signType: data.signType, //微信签名方式:
paySign: data.paySign //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
Toast.info('支付成功', 2)
_this.intervalPayStatus = setInterval(function () {
http.get(`${API['base-api']}/m/orderState/oid/${getParam('oid')}`).then(res => {
if (res.data.errno === 401) {
clearInterval(_this.intervalPayStatus)
_this.intervalPayStatus = null
_this.props.history.replace(`/expand/callback?order_id=${getParam('oid')}`)
}
})
}, 1000)
} else {
alert('支付失败')
}
}
)
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady)
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady)
}
} else {
onBridgeReady()
}
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
}
// 支付完成之后获取状态
payCallback = () => {
const _this = this
// 支付回调
// 定时器轮训获取订单状态
_this.intervalPayStatus = setInterval(function () {
http.get(`${API['base-api']}/m/orderState/oid/${getParam('oid')}`).then(res => {
if (res.data.errno === 401) {
clearInterval(_this.intervalPayStatus)
_this.intervalPayStatus = null
window.location.href = '/expand/callback?order_id=' + getParam('oid')
}
})
}, 1000)
}
onBridgeReady1 = (data) => {
let _this = this
data = data || _this.BridgeData
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
"appId": "wx23dac6775ac82877", //公众号名称,由商户传入
"timeStamp": data.timeStamp, //时间戳,自1970年以来的秒数
"nonceStr": data.nonceStr, //随机串
"package": data.package,
"signType": data.signType, //微信签名方式:
"paySign": data.paySign //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
Toast.info('支付成功', 2)
_this.payCallback()
} else {
alert('支付失败')
}
}
)
}
// 支付宝支付
alipayPay = (orderId) => {
http.get(`${API['base-api']}/pay/alipay/wap_charge_new/oid/${orderId}`).then((res) => {
if (res.data.errno === 0) {
this.payCallback()
window.location = res.data.data.url
} else {
Toast.info(res.data.msg, 2)
}
})
}
componentDidMount() {
if (getParam('weixinpay')) {
this.payCallback()
}
if (browser.isWeixin) {
this.isweixinPay(getParam('oid'))
}
http.post(`${API["base-api"]}/m/deposit/detail`, {
order_id: this.state.orderId
}).then(res => {
const {data} = res
if (data.errno == 200) {
this.setState({
categoryList: [data.data.course_info],
salePrice: data.data.course_info.sale_price
})
} else {
Toast.info(data.msg)
}
})
}
changeAgreement = () => {
this.setState((prevState) => ({agree: !prevState.agree}))
}
render() {
const {
orderId,
salePrice,
payType,
checkPeriod,
singleMoney,
periodNumber,
categoryList,
agree
} = this.state
return (
<div className='pay-order'>
<HeaderBar title='确认支付' arrow={true}></HeaderBar>
<WhiteSpace size='sm'></WhiteSpace>
<div className='order-number'>
<WingBlank>
<Flex justify='between' align='center' style={{height: '44px'}}>
<span>订单号</span>
<span className='number'>{orderId}</span>
</Flex>
</WingBlank>
</div>
<WhiteSpace size='md'></WhiteSpace>
{
categoryList.map((item, index) => {
const Info = (
<div className="order-info">
<p className='order-title text-overflow-one'>
<Link to={`/detail?id=${item.course_id}`}>{item.course_title}</Link>
</p>
<p className='order-content text-overflow-2'>{item.simpledescription}</p>
<p className='order-des'>
<span className='order-newprice'>¥{item.sale_price}</span>
<span className={'price-des'}>(预付定金)</span>
</p>
</div>
)
return (
<VList key={index} img={item.image_name}
id={item.course_id}
info={Info}></VList>
)
})
}
<WhiteSpace size='md'></WhiteSpace>
<div className='order-number'>
<WingBlank>
<Flex justify='between' align='center' style={{height: '44px'}}>
<span>支付金额</span>
<span className='money'>{`¥${salePrice}`}</span>
</Flex>
</WingBlank>
</div>
<WhiteSpace size='md'></WhiteSpace>
<List renderHeader={() => '支付方式'} className='pay-type-list'>
{mockData.map(i => (
<RadioItem
thumb={<i className={`iconfont ${i.icon} ${payType === i.value ? 'checked' : ''}`}></i>}
key={i.value}
checked={payType === i.value}
onChange={() => this.onChange(i.value)}>
{
i.value === 2 ? (
<Flex direction='column' align='start' style={{width: '100%', marginTop: '6px'}}>
<Flex direction='row' justify='between'
style={{width: '100%', paddingRight: '30px'}}>
<span style={{color: '#555555', fontSize: '14px'}}>{i.label}</span>
{
checkPeriod ? (
<span style={{
color: '#333333',
fontSize: '12px'
}}>{`${singleMoney}元 × ${periodNumber}期`}</span>
) : null
}
</Flex>
<Flex justify='start'>
<span style={{color: '#999999', fontSize: '12px'}}>支付上限受限于您的花呗额度</span>
</Flex>
</Flex>
) : (i.label)
}
</RadioItem>
))}
</List>
<Flex>
<Flex.Item className={'agreement'}>
<Checkbox.AgreeItem onChange={this.changeAgreement}>
我已同意定金不退
</Checkbox.AgreeItem>
</Flex.Item>
</Flex>
{/*<div className='pay-tip'>请在15分钟内完成支付,否则届时系统将关闭该订单。</div>*/}
<div className={classnames(['pay-button', !agree && 'invalid'])} onClick={this.pay}>确认支付</div>
</div>
)
}
}
export default WithFullSize(PayOrder)
.pay-order {
width: 100%;
height: calc(100% - 44px);
background-color: #f5f5f5;
.order-number {
background-color: #fff;
span {
font-size: 15px;
color: #333333;
}
.number {
font-size: 12px;
color: #666666;
}
.money {
color: #ff3131;
}
}
.pay-type-list {
.am-list-body {
&::after {
display: none;
}
}
.am-list-header {
color: #333333;
font-size: 15px;
background-color: #fff;
}
.iconalipay {
font-size: 22px;
color: #01aaef;
}
.iconweixinzhifu {
font-size: 22px;
color: #3baf34;
}
.iconhuabei {
font-size: 22px;
color: #01aaef;
}
.am-radio-inner {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #c1c1c1;
}
.am-radio-inner:after {
display: block;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
.agreement {
margin-top: 8px;
background: #fff;
.am-checkbox-agree{
.am-checkbox {
left: unset;
right: 6px;
}
.am-checkbox-agree-label{
margin-left: 3px;
}
}
}
.pay-tip {
width: 100%;
height: 30px;
line-height: 30px;
text-align: center;
font-size: 12px;
color: #ff3131;
background-color: #fff4ce;
}
.pay-button {
position: fixed;
bottom: 0;
width: 100%;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
font-size: 18px;
background-color: #18b4ed;
z-index: 9;
&.invalid{
background: #BBB;
}
}
.check-staging {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, $alpha: 0.6);
z-index: 19;
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
border-radius: 6px;
background-color: #FFF;
padding-bottom: 10px;
.check-title {
color: #333333;
font-size: 16px;
text-align: center;
width: 100%;
height: 44px;
line-height: 44px;
border-bottom: 1px solid #DDDDDD;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
}
.am-list-item .am-list-line .am-list-extra {
flex-basis: 16%;
}
.am-radio-inner {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #BFBFBF;
background-color: #fff;
}
.am-radio-inner:after {
display: block;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border: 1px solid #FFF;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
.order-info {
position: relative;
flex: 1;
.order-title {
font-size: 16px;
color: $color_333;
}
.order-content {
font-size: 14px;
color: $color_666;
margin-top: 14px;
line-height: 18px;
}
.order-des {
height: 24px;
line-height: 33px;
position: absolute;
bottom: 0;
.order-newprice {
font-size: 16px;
color: $redprice;
}
.order-price {
font-size: 12px;
color: $color_999;
margin-left: 15px;
text-decoration: line-through;
}
}
}
.v-list-item {
padding: 10px 15px;
background-color: #fff;
.content {
border: none;
padding-bottom: 0;
.cover {
flex: inherit;
width: 42.2%;
img {
width: 100%;
height: 100%;
}
.course-status {
background-color: rgba(224, 46, 36, 0.6);
}
}
.price-des {
color: #999;
font-size: 11px;
}
}
.info {
width: 52.3%;
position: relative;
display: block;
.title {
font-size: 16px;
color: $color_333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 16px;
line-height: 16px;
}
.contact {
font-size: 14px;
color: $color_666;
margin-top: 14px;
}
.des {
position: absolute;
bottom: 0;
.course-price {
.price {
color: $red;
font-size: 12px;
}
.new {
color: $red;
font-size: 16px;
}
.old {
color: $color_999;
font-size: 12px;
display: inline-block;
margin-left: 15px;
text-decoration: line-through;
}
}
.isbuy {
display: inline-block;
width: 61px;
height: 18px;
background-color: $bg_active;
border-radius: 9px;
color: $white;
font-size: 12px;
text-align: center;
line-height: 18px;
}
}
}
}
}
import React, { Component } from 'react'
import { Checkbox, Flex, List, Radio, Toast, WhiteSpace, WingBlank } from 'antd-mobile'
import { browser, getParam, http, is_weixin } from '@/utils'
import { HeaderBar } from '@common/index'
import VlistBase from '@/common/v-list-base'
import './index.scss'
import { WithFullSize } from '@/HOCs'
import { Link } from "react-router-dom"
import app from "@/utils/app"
const RadioItem = Radio.RadioItem
const Item = Flex.Item
function OrderList({courses, toggleSelectedCourse}) {
return (
<Flex wrap={'wrap'}>
{courses.length && courses.map(course => {
const {image_name: img, course_id, coupon_desc, coupon_num} = course
const info = (
<div className="info">
<div className="title">{course.course_title}</div>
<div className="des">
<div className={'deposit-discount'}>
定金折扣:<span className={'price'}>-¥{course.deduction_amount}</span>
</div>
{
course.coupon_amount != 0 &&
<div className={'coupon-amount'}>
使用优惠券:<span className={'price'}>-¥{course.coupon_amount}</span>
</div>
}
</div>
<div className="prices">
<span className={'sale-price price'}>¥{course.sale_price}</span>
<span className={'former-price'}>¥{course.price1}</span>
</div>
</div>
)
return (
<React.Fragment key={course.course_id}>
<Item className={'order-item'}>
<Flex className="select-bar" justify={'between'}>
<Item>
<Checkbox defaultChecked onChange={() => {
toggleSelectedCourse(course)
}}/>
</Item>
<Item className={'final-payment-hint'}>
待付尾款
</Item>
</Flex>
<VlistBase img={img}
handleClick={() => {
}}
info={info}
/>
</Item>
<div className="order-prefer">
<List key={course_id}>
<List.Item
arrow="horizontal"
onClick={() => {
}}
>
<Link to={{
pathname: `/coupons`,
search: `?id=${course_id}`,
state: {
from: '/order'
}
}}>
<Flex justify='between'>
<span
style={{
color: '#333',
fontSize: '15px'
}}
>优惠券</span>
<span
style={{
fontSize: '14px',
color: '#999999'
}}
>
{!coupon_desc ? (coupon_num === 0 ? '无' : `${coupon_num}张可用`) : (coupon_desc)}
</span>
</Flex>
</Link>
</List.Item>
</List>
</div>
</React.Fragment>
)
})}
</Flex>
)
}
let mockData = []
if (browser.isWeixin) {
mockData = [
{value: 1, label: '微信支付', icon: 'iconweixinzhifu'}
]
} else {
mockData = [
{value: 1, label: '微信支付', icon: 'iconweixinzhifu'},
{value: 0, label: '支付宝', icon: 'iconalipay'},
]
}
class FinalDepositOrder extends Component {
constructor(props) {
super(props)
this.state = {
pay_amount: 0,
payType: 1,
stageNumber: 0,
orderId: getParam('oid'),
categoryList: [],
selectedCourses: [],
salePrice: '',
user_account: '',
useBalance: false,
info: false,
order_id: '',
moneyOffRules: [],
finalEndTime: '',
offset: 0,
appliedMoneyOffRule: {}
}
}
onChange = (value) => {
this.setState({
payType: value,
checkPeriod: false,
})
if (value === 2) {
this.setState({
huabei: true,
})
}
}
// 确定购买
pay = () => {
const {payType, order_id} = this.state
if (payType === 0) {
this.alipayPay(order_id)
} else if (payType === 1) {
this.weixinPay(order_id)
}
}
//提交
submit = () => {
this.createOrder().then(res => {
if (res.data.errno == 200) {
this.setState({
order_id: res.data.data.order_id
}, () => {
if (res.data.data.pay_jump === 1) {
this.props.history.push('/purchased')
} else {
this.pay()
}
})
} else {
Toast.info(res.data.msg)
}
})
}
//创建订单
createOrder = () => {
const {selectedCourses, salePrice, useBalance, user_account, appliedMoneyOffRule} = this.state
return http.post(`${API["base-api"]}/m/deposit/final/create`, {
course_ids: selectedCourses.map(item => item.course_id),
cut_amount: appliedMoneyOffRule.cut_amount || 0,
pay_amount: salePrice,
is_deduction: useBalance ? 1 : 0,
deduction_amount: useBalance ? this.getBalanceOffset() : 0,
plat_form: 5,
source: getParam('source')
})
}
// 微信支付
weixinPay = (orderId) => {
// 微信内部-支付
if (is_weixin()) {
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
} else {
// 微信外部-支付
http.get(`${API['base-api']}/pay/wxpay/wap_charge/oid/${orderId}`).then((res) => {
if (res.data.errno === 0) {
window.location.href = res.data.data.url + "&redirect_url=" + encodeURIComponent(window.location.href + "&weixinpay=1").toLowerCase()
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
// 微信内部支付
isweixinPay = () => {
let _this = this
let weixin_code = getParam('code')
if (weixin_code) {
if (getParam('oid') === undefined) {
return
} else {
http.get(`${API['base-api']}/pay/wxpay/pub_charge/oid/${getParam('oid')}/code/${weixin_code}`).then((res) => {
if (res.data.errno === 0) {
let data = res.data.data
function onBridgeReady() {
WeixinJSBridge.invoke(
'getBrandWCPayRequest', {
appId: data.appId, //公众号名称,由商户传入
timeStamp: data.timeStamp, //时间戳,自1970年以来的秒数
nonceStr: data.nonceStr, //随机串
package: data.package,
signType: data.signType, //微信签名方式:
paySign: data.paySign //微信签名
},
function (res) {
if (res.err_msg == "get_brand_wcpay_request:ok") {
Toast.info('支付成功', 2)
_this.intervalPayStatus = setInterval(function () {
http.get(`${API['base-api']}/m/orderState/oid/${getParam('oid')}`).then(res => {
if (res.data.errno === 401) {
clearInterval(_this.intervalPayStatus)
_this.intervalPayStatus = null
_this.props.history.replace(`/expand/callback?order_id=${getParam('oid')}`)
}
})
}, 1000)
} else {
alert('支付失败')
}
}
)
}
if (typeof WeixinJSBridge == "undefined") {
if (document.addEventListener) {
document.addEventListener('WeixinJSBridgeReady', onBridgeReady, false)
} else if (document.attachEvent) {
document.attachEvent('WeixinJSBridgeReady', onBridgeReady)
document.attachEvent('onWeixinJSBridgeReady', onBridgeReady)
}
} else {
onBridgeReady()
}
} else {
Toast.info(res.data.msg, 2)
}
})
}
}
}
// 支付完成之后获取状态
payCallback = () => {
const _this = this
// 支付回调
// 定时器轮训获取订单状态
_this.intervalPayStatus = setInterval(function () {
http.get(`${API['base-api']}/m/orderState/oid/${getParam('oid')}`).then(res => {
if (res.data.errno === 401) {
clearInterval(_this.intervalPayStatus)
_this.intervalPayStatus = null
window.location.href = '/expand/callback?order_id=' + getParam('oid')
}
})
}, 1000)
}
// 支付宝支付
alipayPay = (orderId) => {
http.get(`${API['base-api']}/pay/alipay/wap_charge_new/oid/${orderId}`).then((res) => {
if (res.data.errno === 0) {
this.payCallback()
window.location = res.data.data.url
} else {
Toast.info(res.data.msg, 2)
}
})
}
componentDidMount() {
if (getParam('weixinpay')) {
this.payCallback()
}
if (browser.isWeixin) {
this.isweixinPay(getParam('oid'))
}
http.get(`${API["base-api"]}/m/deposit/final/preorder`)
.then(res => {
const {data} = res
if (data.errno == 200) {
this.setState({
categoryList: [...data.data.courses],
salePrice: this.getTotalPrice({
courses: [...data.data.courses],
moneyOffRules: data.data['full_rule']
}),
selectedCourses: [...data.data.courses],
user_account: data.data.user_account,
moneyOffRules: data.data['full_rule'],
finalEndTime: data.data['final_end_time']
})
} else {
Toast.info(data.msg)
}
})
}
// 展示余额抵扣规则
showInfo = () => {
this.setState((prevState) => ({
info: !prevState.info
}))
}
toggleSelectedCourse = course => {
this.setState(prevState => {
const {selectedCourses} = prevState
let index = prevState.selectedCourses.findIndex(item => item.course_id == course.course_id)
if (index == -1) {
selectedCourses.push(course)
} else {
selectedCourses.splice(index, 1)
}
let totalPrice = this.getTotalPrice(selectedCourses)
return {selectedCourses, salePrice: totalPrice, offset: this.getBalanceOffset(totalPrice)}
})
}
//获取支付价格
getTotalPrice = (
{
courses = this.state.selectedCourses,
useBalance = this.state.useBalance,
moneyOffRules = this.state.moneyOffRules
} = {}
) => {
let totalPrice = this.getOriginTotalPrice({courses})
totalPrice = this.moneyOff(totalPrice, moneyOffRules)
if (useBalance) {
totalPrice -= parseFloat(this.state.user_account)
}
return totalPrice < 0 ? 0 : totalPrice.toFixed(2)
}
//满减计算
moneyOff = (totalPrice, moneyOffRules = this.state.moneyOffRules) => {
let rules = moneyOffRules.sort((a, b) => b.full_amount - a.full_amount)
let result = parseFloat(totalPrice)
for (let i = 0; i < rules.length; i++) {
let rule = rules[i]
if (result >= rule.full_amount) {
this.setState({
appliedMoneyOffRule: rule
})
return result - parseFloat(rule.cut_amount)
}
}
return result
}
//使用余额
useBalance = () => {
this.setState(prevState => {
const useBalance = !prevState.useBalance
let totalPrice = this.getTotalPrice({useBalance})
return {
useBalance,
salePrice: totalPrice,
offset: this.getBalanceOffset(totalPrice)
}
})
}
getOriginTotalPrice = ({courses = this.state.selectedCourses} = {}) => {
return courses.reduce((accu, item) => {
return accu + parseFloat(item['sale_price'])
}, 0)
}
getBalanceOffset = () => {
let originalTotalPrice = this.getOriginTotalPrice()
let currentPrice = this.moneyOff(originalTotalPrice)
let offset = parseFloat(this.state.user_account) - parseFloat(currentPrice)
offset = offset >= 0 ? currentPrice : this.state.user_account
return offset
}
render() {
const {
orderId,
salePrice,
payType,
categoryList,
user_account,
useBalance,
info,
finalEndTime,
offset,
appliedMoneyOffRule
} = this.state
return (
<div className='deposit-pay-order'>
<HeaderBar title='课程报名' arrow={true}></HeaderBar>
<WhiteSpace size='sm' />
{/*<div className='order-number'>
<WingBlank>
<Flex justify='between' align='center' style={{height: '44px'}}>
<span>订单号</span>
<span className='number'>{orderId}</span>
</Flex>
</WingBlank>
</div>*/}
<WhiteSpace size='md' />
<div className={'order-list'}>
<OrderList
courses={categoryList}
toggleSelectedCourse={this.toggleSelectedCourse}
/>
</div>
<div className="order-balance">
<List>
<Item className="order-prefer-text">
<Flex justify='between'>
<Flex align='center'>
<span>余额抵扣</span>
<span className="order-balanceprice">
(余额:
<i className="order-money">{`${user_account}元`}</i>
)
</span>
<i className="iconfont iconiconfront-22 question-mark" onClick={this.showInfo}></i>
</Flex>
<Flex>
{
useBalance ? (
<>
<span style={{
color: '#FF2121',
fontSize: '15px',
marginRight: "6px"
}}>{`-¥${offset}`}</span>
<i
className={`iconfont icondanseshixintubiao-5 balance-used`}
onClick={this.useBalance}
/>
</>
) : (
<i className='circle-icon' onClick={this.useBalance}></i>
)
}
</Flex>
</Flex>
</Item>
</List>
</div>
<WhiteSpace size='md'></WhiteSpace>
<div className='order-number'>
<WingBlank>
<Flex justify='between' align='center' style={{height: '44px'}}>
<span>支付金额</span>
<span className='money'>{`¥${salePrice}`}</span>
</Flex>
</WingBlank>
</div>
<WhiteSpace/>
{
appliedMoneyOffRule.full_amount &&
<div className="money-off">
<WingBlank>
<Flex justify='end' align='center' style={{height: '44px'}}>
<span>{appliedMoneyOffRule.full_amount}{appliedMoneyOffRule.cut_amount}</span>
<span className='money'>{`-¥${appliedMoneyOffRule.cut_amount}`}</span>
</Flex>
</WingBlank>
</div>
}
<WhiteSpace size='md'></WhiteSpace>
<List renderHeader={() => '支付方式'} className='pay-type-list'>
{mockData.map(i => (
<RadioItem
thumb={<i className={`iconfont ${i.icon} ${payType === i.value ? 'checked' : ''}`}></i>}
key={i.value}
checked={payType === i.value}
onChange={() => this.onChange(i.value)}>
{i.label}
</RadioItem>
))}
</List>
<div className='pay-tip'>{`${finalEndTime}结束支付尾款`}</div>
<div className='pay-button' onClick={this.submit}>确认支付</div>
{
info ? (
<div style={{
position: 'fixed',
top: 0,
left: 0,
width: '100%',
height: '100%',
backgroundColor: 'rgba(0, 0, 0, 0.8)',
zIndex: '99'
}}>
<div style={{
padding: '20px',
backgroundColor: '#FFF',
width: '300px',
height: '170px',
margin: '0 auto',
position: 'absolute',
left: '50%',
top: '50%',
transform: 'translate(-50%, -50%)'
}}>
<Flex direction='column' justify='between' align='center' style={{height: '100%'}}>
<p style={{fontSize: '16px', color: '#333333'}}>余额抵扣说明</p>
<p style={{
lineHeight: '20px',
fontSize: '13px',
color: '#666666'
}}>分销课程或者参与七月在线的相关活动,可获得资金奖励。账户资金可直接提现,也可抵扣课程费用。</p>
<div onClick={this.showInfo} style={{
width: '260px',
height: '30px',
lineHeight: '30px',
textAlign: 'center',
borderRadius: '3px',
border: '1px solid #0099FF',
color: '#0099FF',
fontSize: '15px'
}}>知道了
</div>
</Flex>
</div>
</div>
) : null
}
</div>
)
}
}
export default WithFullSize(FinalDepositOrder)
.deposit-pay-order {
width: 100%;
background-color: #f5f5f5;
box-sizing: content-box;
padding-bottom: 44px;
.order-number {
background-color: #fff;
span {
font-size: 15px;
color: #333333;
}
.number {
font-size: 12px;
color: #666666;
}
.money {
color: #ff3131;
}
}
.money-off{
font-size: 14px;
background: #fff;
color: #999;
.money{
color: #FF3131;
}
}
.pay-type-list {
.am-list-body {
&::after {
display: none;
}
}
.am-list-header {
color: #333333;
font-size: 15px;
background-color: #fff;
}
.iconalipay {
font-size: 22px;
color: #01aaef;
}
.iconweixinzhifu {
font-size: 22px;
color: #3baf34;
}
.iconhuabei {
font-size: 22px;
color: #01aaef;
}
.am-radio-inner {
width: 20px;
height: 20px;
border-radius: 50%;
background-color: #c1c1c1;
}
.am-radio-inner:after {
display: block;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
/*.agreement {
margin-top: 8px;
background: #fff;
.am-checkbox-agree{
.am-checkbox {
left: unset;
right: 6px;
}
.am-checkbox-agree-label{
margin-left: 3px;
}
}
}*/
.price {
color: #FF3131;
margin-right: 10px;
font-size: 12px;
&.sale-price {
font-size: 15px;
}
}
.former-price {
text-decoration: line-through;
color: #999;
}
.pay-tip {
width: 100%;
padding: 21px;
text-align: center;
font-size: 12px;
color: #ff3131;
}
.pay-button {
position: fixed;
bottom: 0;
width: 100%;
height: 44px;
line-height: 44px;
text-align: center;
color: #fff;
font-size: 18px;
background-color: #18b4ed;
z-index: 9;
}
.check-staging {
position: fixed;
width: 100%;
height: 100%;
top: 0;
left: 0;
background-color: rgba(0, 0, 0, $alpha: 0.6);
z-index: 19;
.container {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
width: 300px;
border-radius: 6px;
background-color: #FFF;
padding-bottom: 10px;
.check-title {
color: #333333;
font-size: 16px;
text-align: center;
width: 100%;
height: 44px;
line-height: 44px;
border-bottom: 1px solid #DDDDDD;
border-top-left-radius: 6px;
border-top-right-radius: 6px;
}
}
.am-list-item .am-list-line .am-list-extra {
flex-basis: 16%;
}
.am-radio-inner {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid #BFBFBF;
background-color: #fff;
}
.am-radio-inner:after {
display: block;
border-color: #fff;
top: 0;
right: 6px;
}
.am-radio.am-radio-checked .am-radio-inner {
background-color: #009aff;
border: 1px solid #FFF;
border-radius: 50%;
width: 20px;
height: 20px;
}
.am-radio.am-radio-checked .am-radio-inner:after {
display: block;
}
}
.select-bar {
background: #fff;
padding: 11px 15px;
border-bottom: 1px solid #E5E5E5;
.am-flexbox-item {
flex: 0 1 auto;
}
.final-payment-hint {
padding: 4px 6px 5px;
background: $bg-active;
border-radius: 3px;
color: #fff;
}
}
.order-item {
}
.v-list-base-item {
padding: 10px 15px;
background-color: #fff;
.content {
border: none;
padding-bottom: 0;
.cover {
flex: inherit;
width: 42.2%;
img {
width: 100%;
height: 100%;
}
.course-status {
background-color: rgba(224, 46, 36, 0.6);
}
}
.price-des {
color: #999;
font-size: 11px;
}
}
.info {
width: 52.3%;
position: relative;
.title {
font-size: 15px;
color: $color_333;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 16px;
line-height: 16px;
margin-bottom: 16px;
}
.contact {
font-size: 14px;
color: $color_666;
margin-top: 14px;
}
.des {
color: #999;
.course-price {
.price {
color: $red;
font-size: 12px;
}
.new {
color: $red;
font-size: 16px;
}
.old {
color: $color_999;
font-size: 12px;
display: inline-block;
margin-left: 15px;
text-decoration: line-through;
}
}
.isbuy {
display: inline-block;
width: 61px;
height: 18px;
background-color: $bg_active;
border-radius: 9px;
color: $white;
font-size: 12px;
text-align: center;
line-height: 18px;
}
}
& .prices:last-child {
position: absolute;
bottom: 0;
}
}
}
//order.scss
.order-balance {
height: 44px;
line-height: 44px;
padding: 0 15px;
background: #fff;
.am-list-item {
padding-left: 0 !important;
}
.am-list-line {
padding: 0 15px;
}
.am-list-content {
color: $color_333;
font-size: $font_16;
.iconiconfront-22 {
font-size: 18px;
margin-left: 15px;
}
}
.order-balanceprice {
color: $color_666;
font-size: $font_12;
.order-money {
color: #ff2121;
font-size: $font_12 !important;
font-weight: normal;
font-style: inherit;
vertical-align: middle;
margin: 0;
}
}
.iconiconfront-22.question-mark {
font-size: 24px;
margin-left: 15px;
}
.am-list-body {
&::before, &::after {
display: none;
}
}
.balance-used {
font-size: 24px;
color: #0099FF;
}
.circle-icon {
width: 20px;
height: 20px;
border: 1px solid #BFBFBF;
border-radius: 50%;
margin-right: 2px;
}
}
.order-prefer {
width: 100%;
margin-bottom: 6px;
.am-list-body {
&::after {
display: none;
}
}
.am-list-content {
font-size: 15px !important;
}
}
.order-list{
.am-flexbox-item{
margin-left: 0;
}
}
/*.order-tab {
color: $black;
background: $bg_f7f9fc;
}
.order-information {
display: flex;
width: 100%;
overflow: hidden;
padding: 29px 15px;
color: $color_555;
background-color: $bg_fff;
position: relative;
}
.order-information::before {
content: '';
left: 0;
right: 0;
bottom: 0;
height: 2px;
position: absolute;
background: -webkit-repeating-linear-gradient(135deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background: repeating-linear-gradient(-45deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background-size: 80px;
}
.order-information2 {
height: 80px;
background-color: #FFF;
margin-top: 8px;
position: relative;
.user-icon {
font-size: 28px;
flex-basis: 40px;
}
.order-cell {
height: 50px;
font-size: 13px;
color: $color_333;
line-height: 20px;
flex: 1 1 auto;
.name {
margin-bottom: 10px;
}
}
}
.order-information2::before {
content: '';
left: 0;
right: 0;
bottom: 0;
height: 2px;
position: absolute;
background: -webkit-repeating-linear-gradient(135deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background: repeating-linear-gradient(-45deg, #ff6c6c 0, #ff6c6c 20%, transparent 0, transparent 25%, #1989fa 0, #1989fa 45%, transparent 0, transparent 50%);
background-size: 80px;
}
.order-addsize {
font-size: 22px !important;
margin-bottom: 0px;
height: 22px;
color: $active;
line-height: 22px;
}
.order-next {
line-height: 22px;
margin-bottom: 0px;
}
.order-list {
margin-top: 8px;
background-color: #F5F5F5;
.public-content {
padding: 10px 15px;
}
}
.order-infotext {
flex: 1;
height: 22px;
line-height: 22px;
margin-left: 10px;
font-size: $font_14;
color: $color_555;
}
.order-info {
color: $color_666;
font-size: $font_14;
min-width: 160px;
flex: 1 1 auto;
display: flex;
flex-direction: column;
justify-content: space-around;
.order-title {
color: $color_333;
font-size: $font_16;
}
.order-content {
color: $color_666;
font-size: $font_14;
line-height: 18px;
}
.order-newprice {
color: $redprice;
font-size: $font_16;
margin-right: 15px;
}
.order-price {
color: $color_999;
font-size: $font_12;
text-decoration: line-through;
}
}
.order-bar {
width: 100%;
position: fixed;
bottom: 0;
z-index: 2;
height: 50px;
display: flex;
font-size: 14px;
align-items: center;
background-color: $bg_fff;
}
.order-course {
margin-left: 20px;
.order-course-text {
font-size: $font_16;
color: $color_333;
}
}
.order-bar-text {
flex: 1;
text-align: right;
color: #323233;
padding-right: 20px;
.order-amount {
font-size: $font_14;
color: $color_333;
.order-amount-price {
color: $redprice;
}
}
.order-preprice {
font-size: $font_12;
color: $color_555;
}
}
.order-button {
width: 110px;
height: 50px;
display: inline-block;
padding: 0;
background-color: $bg_ff9898;
color: $white;
line-height: 48px;
font-size: 16px;
border-radius: 0px;
text-align: center;
box-sizing: border-box;
-webkit-appearance: none;
-webkit-text-size-adjust: 100%;
border: 1px solid transparent;
}
.has-info {
background-color: #FF3131;
}
.am-list-item .am-list-line .am-list-content {
color: $color_333;
}
.order-list {
.am-list-item {
padding-left: 0 !important;
}
}
*/
}
...@@ -120,6 +120,8 @@ class Order extends Component { ...@@ -120,6 +120,8 @@ class Order extends Component {
orderList: [], orderList: [],
info: false, info: false,
offset: 0, offset: 0,
full_amount: 0, // 满金额
cut_amount: 0, // 减金额
}; };
} }
// 提交订单 // 提交订单
...@@ -133,6 +135,7 @@ class Order extends Component { ...@@ -133,6 +135,7 @@ class Order extends Component {
Toast.info('请完善报名信息!'); Toast.info('请完善报名信息!');
} }
const { location: { state ={} } } = this.props; const { location: { state ={} } } = this.props;
if(state.group === 1) { if(state.group === 1) {
let params = state.pdd_order_id? { let params = state.pdd_order_id? {
course_id: getParam("id"), course_id: getParam("id"),
...@@ -143,8 +146,7 @@ class Order extends Component { ...@@ -143,8 +146,7 @@ class Order extends Component {
ischeck: this.state.useBalance, ischeck: this.state.useBalance,
} }
http.post(`${API['base-api']}/pdd/m`, params).then(res => { http.post(`${API['base-api']}/pdd/m`, params).then(res => {
console.log(res); if(Number(res.data.errno) === 200) {
if(res.data.errno === 200) {
sessionStorage.removeItem('orderUseCacheObj'); sessionStorage.removeItem('orderUseCacheObj');
if (res.data.data.pay_jump === 1) { if (res.data.data.pay_jump === 1) {
this.props.history.push(`/togroup?id=${res.data.data.oid}`); this.props.history.push(`/togroup?id=${res.data.data.oid}`);
...@@ -152,7 +154,10 @@ class Order extends Component { ...@@ -152,7 +154,10 @@ class Order extends Component {
} }
this.props.history.push(`/payorder?oid=${res.data.data.oid}`, {group: 1}); this.props.history.push(`/payorder?oid=${res.data.data.oid}`, {group: 1});
}else { }else if(Number(res.data.errno) === 0){
Toast.info(res.data.data.msg, 2);
return;
} else {
Toast.info(res.data.msg, 2); Toast.info(res.data.msg, 2);
return; return;
} }
...@@ -267,6 +272,12 @@ class Order extends Component { ...@@ -267,6 +272,12 @@ class Order extends Component {
discount, discount,
}); });
}; };
fullRules = (data) => {
this.setState({
full_amount: data.full_amount,
cut_amount: data.cut_amount,
});
};
// 公共方法 本地存储 // 公共方法 本地存储
publicLocalStorage = () => { publicLocalStorage = () => {
if(this.props.history.action === 'PUSH') { if(this.props.history.action === 'PUSH') {
...@@ -300,8 +311,11 @@ class Order extends Component { ...@@ -300,8 +311,11 @@ class Order extends Component {
// 普通课程立即报名 不带 type = 1 // 普通课程立即报名 不带 type = 1
http.get(`${API['base-api']}/m/order/preorder`).then(res => { http.get(`${API['base-api']}/m/order/preorder`).then(res => {
if(res.data.errno === 200) { if(res.data.errno === 200) {
console.log(res.data.data);
this.publicGetData(res.data.data); this.publicGetData(res.data.data);
this.publicLocalStorage(); this.publicLocalStorage();
this.fullRules(res.data.data);
}else{ }else{
Toast.info(res.data.msg, 2); Toast.info(res.data.msg, 2);
} }
...@@ -407,7 +421,9 @@ class Order extends Component { ...@@ -407,7 +421,9 @@ class Order extends Component {
useBalance, useBalance,
info, info,
offset, offset,
groupPrice groupPrice,
full_amount,
cut_amount,
} = this.state; } = this.state;
return ( return (
...@@ -495,6 +511,20 @@ class Order extends Component { ...@@ -495,6 +511,20 @@ class Order extends Component {
</Item> </Item>
</List> </List>
</div> </div>
{
(full_amount > 0 && cut_amount > 0) ? (
<>
<div className="full__rules">
<WingBlank>
<div className="money__off">
<span>{full_amount}{cut_amount}</span>
<span className='money'>{`-¥${cut_amount}`}</span>
</div>
</WingBlank>
</div>
</>
) : (null)
}
<div className="order-bar"> <div className="order-bar">
<div className="order-course"> <div className="order-course">
<span className="order-course-text">{`${orderList.length}门课程`}</span> <span className="order-course-text">{`${orderList.length}门课程`}</span>
......
...@@ -265,7 +265,8 @@ ...@@ -265,7 +265,8 @@
.order-balance { .order-balance {
height: 44px; height: 44px;
line-height: 44px; line-height: 44px;
margin: 8px 0 50px 0; margin: 8px 0 8px 0;
display: flow-root;
.am-list-item { .am-list-item {
padding-left: 0 !important; padding-left: 0 !important;
...@@ -282,4 +283,23 @@ ...@@ -282,4 +283,23 @@
} }
} }
} }
.full__rules {
width: 100%;
height: 50px;
margin-top: 16px;
background: #FFF;
font-size: 14px;
background: #fff;
color: #999;
.money__off {
height: 50px;
display: flex;
justify-content: space-between;
align-items: center;
}
.money{
color: #FF3131;
}
}
} }
\ No newline at end of file
...@@ -112,6 +112,15 @@ export default class PayOrder extends Component { ...@@ -112,6 +112,15 @@ export default class PayOrder extends Component {
// 微信内部-支付 // 微信内部-支付
if (is_weixin()) { if (is_weixin()) {
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"; window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
// if(window.location.href.indexOf('aa=bb') === -1){
// localStorage.setItem('a', '第一次');
// window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(window.location.href + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
// }
// if(window.location.href.indexOf('aa=bb') > 0) {
// localStorage.setItem('a', '多次');
// let newHref = window.location.href.slice(0, window.location.href.indexOf('aa=bb')-1);
// window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx23dac6775ac82877&redirect_uri=" + encodeURIComponent(newHref + "&aa=bb").toLowerCase() + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect";
// }
} else { } else {
// 微信外部-支付 // 微信外部-支付
http.get(`${API['base-api']}/pay/wxpay/wap_charge/oid/${orderId}`).then((res) => { http.get(`${API['base-api']}/pay/wxpay/wap_charge/oid/${orderId}`).then((res) => {
......
import React, { Component } from 'react'; import React, { Component } from 'react'
import './binding-tel.scss' import './binding-tel.scss'
import { withFormik, Field, Form } from "formik"; import { withFormik, Field, Form } from "formik"
import { http, getParam } from "@/utils"; import { http, getParam } from "@/utils"
import { compose } from "redux"; import { compose } from "redux"
import { connect } from "react-redux"; import { connect } from "react-redux"
import { setCurrentUser } from "@/store/userAction"; import { setCurrentUser } from "@/store/userAction"
import Captcha from '@/common/Captcha' import Captcha from '@/common/Captcha'
import { HeaderBar } from '@/common' import { HeaderBar } from '@/common'
...@@ -13,8 +13,8 @@ import { HeaderBar } from '@/common' ...@@ -13,8 +13,8 @@ import { HeaderBar } from '@/common'
import ClearableInput from '../common/clearableInputWithCountryCodes' import ClearableInput from '../common/clearableInputWithCountryCodes'
import Button from '../common/Button' import Button from '../common/Button'
import VeriCodeInput from '../common/veriCodeInput' import VeriCodeInput from '../common/veriCodeInput'
import { Toast } from "antd-mobile"; import { Toast } from "antd-mobile"
import { isEmpty } from "lodash"; import { isEmpty } from "lodash"
class BindingTel extends Component { class BindingTel extends Component {
...@@ -95,7 +95,7 @@ class BindingTel extends Component { ...@@ -95,7 +95,7 @@ class BindingTel extends Component {
</Form> </Form>
</div> </div>
</> </>
); )
} }
} }
...@@ -123,22 +123,23 @@ const formikConfig = { ...@@ -123,22 +123,23 @@ const formikConfig = {
phone_num: values.tel, phone_num: values.tel,
phone_code: values.veriCode, phone_code: values.veriCode,
mkey: getParam('mkey'), mkey: getParam('mkey'),
area_code: '00'+props.country.num, area_code: '00' + props.country.num,
plat: 5 plat: 5
}).then(res => { }).then(res => {
const data = res.data const data = res.data
if (data.errno == 200) { if (data.errno == 200) {
if (data.data['is_set_pwd']) { if (data.data['is_set_pwd']) {
props.setCurrentUser({ const {history} = props
history.replace(`/passport/set-password`, {
user: {
hasError: false, hasError: false,
data: { data: {
uid: data.data.uid uid: data.data.uid
}, },
msg: data.data.msg, msg: data.data.msg,
stage: 'binding' stage: 'binding'
}
}) })
props.history.replace(`/passport/set-password`)
} else { } else {
location.assign(data.data['jump_url']) location.assign(data.data['jump_url'])
} }
...@@ -156,4 +157,4 @@ export default compose( ...@@ -156,4 +157,4 @@ export default compose(
{setCurrentUser} {setCurrentUser}
), ),
withFormik(formikConfig), withFormik(formikConfig),
)(BindingTel); )(BindingTel)
\ No newline at end of file
...@@ -23,6 +23,7 @@ class Passport extends Component { ...@@ -23,6 +23,7 @@ class Passport extends Component {
redirectURL = '/' redirectURL = '/'
count = 1 count = 1
blackList = new Set(['/passport/binding-tel', '/passport/set-password'])
constructor(props) { constructor(props) {
super(props) super(props)
...@@ -85,7 +86,7 @@ class Passport extends Component { ...@@ -85,7 +86,7 @@ class Passport extends Component {
routeWhenUserLoggedIn = () => { routeWhenUserLoggedIn = () => {
let {hasError} = this.props.user let {hasError} = this.props.user
if (!hasError) { if (!hasError && !this.blackList.has(this.props.location.pathname)) {
const redirectURI = getParam('redirect') const redirectURI = getParam('redirect')
redirectURI ? (window.location.href = redirectURI) : this.props.history.go(-this.count) redirectURI ? (window.location.href = redirectURI) : this.props.history.go(-this.count)
} }
...@@ -108,7 +109,9 @@ class Passport extends Component { ...@@ -108,7 +109,9 @@ class Passport extends Component {
<Route path={match.url + '/account-login'} component={AccountLogin}/> <Route path={match.url + '/account-login'} component={AccountLogin}/>
<Route path={match.url + '/forgot-password'} component={ForgotPassword}/> <Route path={match.url + '/forgot-password'} component={ForgotPassword}/>
<Route path={match.url + '/forgot-password-email'} component={ForgotPasswordEmail}/> <Route path={match.url + '/forgot-password-email'} component={ForgotPasswordEmail}/>
<Route path={match.url + '/set-password'} component={SetPassword}/> <Route path={match.url + '/set-password'} render={props => {
return <SetPassword {...props} count={this.count}/>
}}/>
<Route path={match.url + '/binding-tel'} component={BindingTel}/> <Route path={match.url + '/binding-tel'} component={BindingTel}/>
</Switch> </Switch>
</div> </div>
......
import React, { Component } from 'react'; import React, { Component } from 'react'
import './set-password.scss' import './set-password.scss'
import { withFormik, Form, Field } from "formik"; import { withFormik, Form, Field } from "formik"
import PasswordInput from '../common/passwordInput' import PasswordInput from '../common/passwordInput'
import Button from '../common/Button' import Button from '../common/Button'
import classnames from 'classnames' import classnames from 'classnames'
import { compose } from 'redux' import { compose } from 'redux'
import { HeaderBar } from "@/common"; import { HeaderBar } from "@/common"
import { http, api } from "@/utils"; import { http } from "@/utils"
import { Toast } from "antd-mobile"; import { Toast } from "antd-mobile"
import { encrypt } from "@/components/passport/encryption"; import { encrypt } from "@/components/passport/encryption"
import { Link } from "react-router-dom"; import { Link } from "react-router-dom"
import { isEmpty } from "lodash"; import { isEmpty } from "lodash"
import { connect } from "react-redux"; import { connect } from "react-redux"
import { setCurrentUser } from '@/store/userAction'
class SetPassword extends Component { class SetPassword extends Component {
render() { render() {
...@@ -56,7 +56,7 @@ class SetPassword extends Component { ...@@ -56,7 +56,7 @@ class SetPassword extends Component {
</div> </div>
</div> </div>
</> </>
); )
} }
} }
...@@ -71,7 +71,7 @@ const formikConfig = { ...@@ -71,7 +71,7 @@ const formikConfig = {
let from = props.location.state && props.location.state.from || {pathname: '/'} let from = props.location.state && props.location.state.from || {pathname: '/'}
if (from.pathname.includes('forgot-password')) { if (from.pathname.includes('forgot-password')) {
forgotPasswordReset(values, props); forgotPasswordReset(values, props)
} else { } else {
bindMobileSetPassword(values, props) bindMobileSetPassword(values, props)
} }
...@@ -80,7 +80,7 @@ const formikConfig = { ...@@ -80,7 +80,7 @@ const formikConfig = {
validateOnChange: false, validateOnChange: false,
validate: values => { validate: values => {
let errors = {} let errors = {}
const re = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/; const re = /^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{6,16}$/
if (!re.test(values.password)) { if (!re.test(values.password)) {
errors.password = '密码需要包含6-16位字母及数字' errors.password = '密码需要包含6-16位字母及数字'
Toast.info(errors.password, 2, null, false) Toast.info(errors.password, 2, null, false)
...@@ -122,10 +122,17 @@ function bindMobileSetPassword(values, props) { ...@@ -122,10 +122,17 @@ function bindMobileSetPassword(values, props) {
}) })
.then(res => { .then(res => {
if (res.data.errno == 200) { if (res.data.errno == 200) {
const {location, history} = props
Toast.info('密码设置成功') Toast.info('密码设置成功')
let from = props.location.state && props.location.state.from || {pathname: '/'} let from = location.state && location.state.from || {pathname: '/'}
let local_redirect_url = JSON.parse(window.localStorage.getItem('binding_redirect'))
setTimeout(function () { setTimeout(function () {
props.history.replace(from.pathname) if (local_redirect_url) {
const {pathname, search, hash} = local_redirect_url
history.replace(pathname + search + hash)
} else {
history.replace(from.pathname)
}
}, 1000) }, 1000)
} else { } else {
Toast.info(res.data.msg, 2, null, false) Toast.info(res.data.msg, 2, null, false)
...@@ -136,7 +143,7 @@ function bindMobileSetPassword(values, props) { ...@@ -136,7 +143,7 @@ function bindMobileSetPassword(values, props) {
export default compose( export default compose(
connect( connect(
state => ({user: state.user}), state => ({user: state.user}),
null {setCurrentUser}
), ),
withFormik(formikConfig) withFormik(formikConfig)
)(SetPassword); )(SetPassword)
\ No newline at end of file
...@@ -43,7 +43,7 @@ class Preferential extends Component { ...@@ -43,7 +43,7 @@ class Preferential extends Component {
http.get(`${API.home}/m/home/bargainZone`).then((res) => { http.get(`${API.home}/m/home/bargainZone`).then((res) => {
if (res.data.code === 200) { if (res.data.code === 200) {
this.setState({ this.setState({
dataList: res.data.data, dataList: JSON.stringify(res.data.data) == '{}' ? []:res.data.data,
isLoading: false, isLoading: false,
}) })
} else { } else {
...@@ -83,7 +83,7 @@ class Preferential extends Component { ...@@ -83,7 +83,7 @@ class Preferential extends Component {
} }
toCourseDetail = (id) => { toCourseDetail = (id) => {
const { dispatch, history } = this.props; const {dispatch, history} = this.props;
// dispatch(getCourses(id, () => { // dispatch(getCourses(id, () => {
history.push(`/detail?id=${id}`) history.push(`/detail?id=${id}`)
// })); // }));
...@@ -95,11 +95,11 @@ class Preferential extends Component { ...@@ -95,11 +95,11 @@ class Preferential extends Component {
{title: '砍价专区'}, {title: '砍价专区'},
{title: '一键拼团'} {title: '一键拼团'}
] ]
const { user ={} } = this.props; const {user = {}} = this.props;
let isLogin = user.data && user.data.uid? true : false; let isLogin = user.data && user.data.uid ? true : false;
return ( return (
<div className='preferential'> <div className='preferential'>
<HeaderSearch isLogin={isLogin} /> <HeaderSearch isLogin={isLogin}/>
<Loading isLoading={this.state.isLoading}> <Loading isLoading={this.state.isLoading}>
<div className='class-content'> <div className='class-content'>
<WhiteSpace/> <WhiteSpace/>
...@@ -116,11 +116,14 @@ class Preferential extends Component { ...@@ -116,11 +116,14 @@ class Preferential extends Component {
> >
</Tabs> </Tabs>
<div className='tabs'> <div className='tabs'>
{
this.state.dataList.length>0?
<ul> <ul>
{this.state.dataList.map((item, index) => { {this.state.dataList.map((item, index) => {
const Info = ( const Info = (
<div className="info"> <div className="info">
<p className='title' onClick={() => this.toCourseDetail(item.course_id)}> <p className='title'
onClick={() => this.toCourseDetail(item.course_id)}>
{/* <Link to={`/detail?id=${item.course_id}`}> */} {/* <Link to={`/detail?id=${item.course_id}`}> */}
{item.course_title} {item.course_title}
{/* </Link> */} {/* </Link> */}
...@@ -167,7 +170,8 @@ class Preferential extends Component { ...@@ -167,7 +170,8 @@ class Preferential extends Component {
/> />
) )
})} })}
</ul> </ul>:<div className={'notdata'}>砍价的课程已被设置为双十一活动课程,参加双十一活动购买课程优惠更多哦!</div>
}
</div> </div>
<WhiteSpace/> <WhiteSpace/>
......
...@@ -148,5 +148,14 @@ ...@@ -148,5 +148,14 @@
} }
} }
.notdata{
width: 100%;
padding: 0 35px;
text-align: center;
margin-top: 100px;
color: #666;
font-size: 14px;
}
} }
...@@ -109,6 +109,7 @@ class Search extends PureComponent { ...@@ -109,6 +109,7 @@ class Search extends PureComponent {
}) })
: <div style={{textAlign: 'center', padding: '20px'}}>暂无热门</div> : <div style={{textAlign: 'center', padding: '20px'}}>暂无热门</div>
} }
</div> </div>
</div> </div>
</div> </div>
......
...@@ -18,6 +18,7 @@ import Single from "@/components/detail/single"; ...@@ -18,6 +18,7 @@ import Single from "@/components/detail/single";
import SingleSuccess from "../detail/single/singleSuccess"; import SingleSuccess from "../detail/single/singleSuccess";
import './CustomPlayButton' import './CustomPlayButton'
let alert = Modal.alert let alert = Modal.alert
function ProgressShareModal(props) { function ProgressShareModal(props) {
...@@ -606,6 +607,7 @@ class Video extends Component { ...@@ -606,6 +607,7 @@ class Video extends Component {
activeIndex: index activeIndex: index
}, },
() => { () => {
if (this.hasAuth(this.state.activeIndex)) { if (this.hasAuth(this.state.activeIndex)) {
this.setPlayerSrc(this.state.videoList[index]['play_url']) this.setPlayerSrc(this.state.videoList[index]['play_url'])
this.sendLastRecord() this.sendLastRecord()
...@@ -708,7 +710,10 @@ class Video extends Component { ...@@ -708,7 +710,10 @@ class Video extends Component {
} }
playVideo = () => { playVideo = () => {
this.player.ready(() => {
this.player.play() this.player.play()
})
} }
......
import loadable from '@loadable/component' import loadable from '@loadable/component'
import Index from '@/components/Index'; import Index from '@/components/Index'
import My from '@/components/my'; import My from '@/components/my'
import Passport from '@/components/passport'; import Passport from '@/components/passport'
import Scholarship from '@/components/scholarship'; import Scholarship from '@/components/scholarship'
const Coupons = loadable(() => import(/* webpackChunkName: 'coupons'*/ '@/components/coupons')) const Coupons = loadable(() => import(/* webpackChunkName: 'coupons'*/ '@/components/coupons'))
const Study = loadable(() => import(/* webpackChunkName: 'study'*/'@/components/study')) const Study = loadable(() => import(/* webpackChunkName: 'study'*/'@/components/study'))
...@@ -31,6 +31,10 @@ const CampTest = loadable(() => import(/* webpackChunkName: 'Classify'*/'@/compo ...@@ -31,6 +31,10 @@ const CampTest = loadable(() => import(/* webpackChunkName: 'Classify'*/'@/compo
const CampResolve = loadable(() => import(/* webpackChunkName: 'Classify'*/'@/components/video/camp/campResolve')) const CampResolve = loadable(() => import(/* webpackChunkName: 'Classify'*/'@/components/video/camp/campResolve'))
const ShareCourse = loadable(() => import(/* webpackChunkName: 'ShareCourse'*/'@/components/ShareCourse/index')) const ShareCourse = loadable(() => import(/* webpackChunkName: 'ShareCourse'*/'@/components/ShareCourse/index'))
const Country = loadable(() => import(/* webpackChunkName: 'Country' */'@/components/country/index')) 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'))
export default [ export default [
{ {
path: '/', path: '/',
...@@ -168,5 +172,54 @@ export default [ ...@@ -168,5 +172,54 @@ export default [
{ {
path: '/aist-share', path: '/aist-share',
component: loadable(() => import(/* webpackChunkName: 'aist-share'*/'@/components/share-page/aist-share')) component: loadable(() => import(/* webpackChunkName: 'aist-share'*/'@/components/share-page/aist-share'))
},
{
path: '/blessingRank',
component: loadable(() => import(/* webpackChunkName: 'blessing-rank' */'@/components/blessingRank/index'))
},
{
path: '/blessingPreheat',
component: loadable(() => import(/* webpackChunkName: 'blessing-preheat' */'@/components/blessingPreheat/index'))
},
{
path: '/prize-winner-list',
component: loadable(() => import(/* webpackChunkName: 'prize-winner-list' */'@/components/activity/prize-winner-list'))
},
//定金订单页面
{
path: '/deposit-order',
component: loadable(() => import(/* webpackChunkName: 'deposit-order' */ '@components/order/deposit/deposit-order'))
},
//定金支付页面
{
path: '/deposit-pay-order',
component: loadable(() => import(/* webpackChunkName: 'deposit-pay-order' */ '@components/order/deposit/deposit-pay-order'))
},
//尾款支付页面
{
path: '/final-deposit-order',
component: loadable(() => import(/* webpackChunkName: 'deposit-pay-order' */ '@components/order/deposit/final-order'))
},
// 定金支付之后
{
path: '/expand/callback',
component: ExpandCallback
},
// 定金-邀请好友助力
{
path: '/expand/index',
component: ExpandShare
},
{
path: '/toAppDemo',
component: loadable(() => import(/* webpackChunkName: 'aist-share'*/'@/components/blessingPreheat/toAppDemo'))
},
{
path: '/activity',
component: Activity,
},
{
path: '/invite',
component: Invite,
} }
] ]
...@@ -83,7 +83,9 @@ const browser = (function () { ...@@ -83,7 +83,9 @@ const browser = (function () {
isWeixin: /MicroMessenger/i.test(ua), isWeixin: /MicroMessenger/i.test(ua),
isAndroid: /Android/i.test(ua), isAndroid: /Android/i.test(ua),
isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua), isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua),
isIPad: /iPad/i.test(ua) isIPad: /iPad/i.test(ua),
isAndroidApp: /Android/i.test(ua) && getParam('version'),
isIOSApp: /iPhone/i.test(ua) && getParam('version')
} }
})() })()
......
...@@ -6807,21 +6807,11 @@ lodash._reinterpolate@~3.0.0: ...@@ -6807,21 +6807,11 @@ lodash._reinterpolate@~3.0.0:
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=
lodash.assign@^4.2.0:
version "4.2.0"
resolved "https://registry.yarnpkg.com/lodash.assign/-/lodash.assign-4.2.0.tgz#0d99f3ccd7a6d261d19bdaeb9245005d285808e7"
integrity sha1-DZnzzNem0mHRm9rrkkUAXShYCOc=
lodash.camelcase@^4.3.0: lodash.camelcase@^4.3.0:
version "4.3.0" version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY= integrity sha1-soqmKIorn8ZRA1x3EfZathkDMaY=
lodash.clonedeep@^4.3.2:
version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef"
integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=
lodash.debounce@^4.0.0: lodash.debounce@^4.0.0:
version "4.0.8" version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
...@@ -6851,11 +6841,6 @@ lodash.memoize@^4.1.2: ...@@ -6851,11 +6841,6 @@ lodash.memoize@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4=
lodash.mergewith@^4.6.0:
version "4.6.1"
resolved "https://registry.yarnpkg.com/lodash.mergewith/-/lodash.mergewith-4.6.1.tgz#639057e726c3afbdb3e7d42741caa8d6e4335927"
integrity sha512-eWw5r+PYICtEBgrBE5hhlT6aAa75f411bgDz/ZL2KZqYV03USvucsxcHUIlGTDTECs1eunpI7HOV7U+WLDvNdQ==
lodash.sortby@^4.7.0: lodash.sortby@^4.7.0:
version "4.7.0" version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
...@@ -7354,11 +7339,16 @@ mux.js@5.1.3: ...@@ -7354,11 +7339,16 @@ mux.js@5.1.3:
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.1.3.tgz#1a59b8979a6780be5bcb63983c7e883c90cd615b" resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.1.3.tgz#1a59b8979a6780be5bcb63983c7e883c90cd615b"
integrity sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg== integrity sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg==
nan@^2.10.0, nan@^2.12.1: nan@^2.12.1:
version "2.13.2" version "2.13.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7" resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw== integrity sha512-TghvYc72wlMGMVMluVo9WRJc0mB8KxxF/gZ4YYFy7V2ZQX9l7rgbPg7vjS9mt6U5HXODVFVI2bOduCzwOMv/lw==
nan@^2.13.2:
version "2.14.0"
resolved "https://registry.npm.taobao.org/nan/download/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c"
integrity sha1-eBj3IgJ7JFmobwKV1DTR/CM2xSw=
nanomatch@^1.2.9: nanomatch@^1.2.9:
version "1.2.13" version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
...@@ -7525,10 +7515,10 @@ node-releases@^1.1.25: ...@@ -7525,10 +7515,10 @@ node-releases@^1.1.25:
dependencies: dependencies:
semver "^5.3.0" semver "^5.3.0"
node-sass@^4.11.0: node-sass@^4.13.0:
version "4.11.0" version "4.13.0"
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a" resolved "https://registry.npm.taobao.org/node-sass/download/node-sass-4.13.0.tgz?cache=0&sync_timestamp=1571899964908&other_urls=https%3A%2F%2Fregistry.npm.taobao.org%2Fnode-sass%2Fdownload%2Fnode-sass-4.13.0.tgz#b647288babdd6a1cb726de4545516b31f90da066"
integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA== integrity sha1-tkcoi6vdahy3Jt5FRVFrMfkNoGY=
dependencies: dependencies:
async-foreach "^0.1.3" async-foreach "^0.1.3"
chalk "^1.1.1" chalk "^1.1.1"
...@@ -7537,12 +7527,10 @@ node-sass@^4.11.0: ...@@ -7537,12 +7527,10 @@ node-sass@^4.11.0:
get-stdin "^4.0.1" get-stdin "^4.0.1"
glob "^7.0.3" glob "^7.0.3"
in-publish "^2.0.0" in-publish "^2.0.0"
lodash.assign "^4.2.0" lodash "^4.17.15"
lodash.clonedeep "^4.3.2"
lodash.mergewith "^4.6.0"
meow "^3.7.0" meow "^3.7.0"
mkdirp "^0.5.1" mkdirp "^0.5.1"
nan "^2.10.0" nan "^2.13.2"
node-gyp "^3.8.0" node-gyp "^3.8.0"
npmlog "^4.0.0" npmlog "^4.0.0"
request "^2.88.0" request "^2.88.0"
......
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