Commit 2fdcc747 by xuzhenghua

lujing

parents d2ea7aaf 6915df36
......@@ -1650,15 +1650,15 @@
}
},
"@videojs/http-streaming": {
"version": "1.10.3",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.3.tgz",
"integrity": "sha512-fxXtwVrQBdhOFh6GymPAPCb4utCI01Zs5fdyZgtR6FSsaz/zGmnzfNS5GvNjBi/hZviMsbNPFaOTTFMMNLNA3A==",
"version": "1.10.6",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-1.10.6.tgz",
"integrity": "sha512-uPBuunHnxWeFRYxRX0j6h1IIWv3+QKvSkZGmW9TvqxWBqeNGSrQymR6tm1nVjQ2HhMVxVphQTUhUTTPDVWqmQg==",
"requires": {
"aes-decrypter": "3.0.0",
"global": "^4.3.0",
"m3u8-parser": "4.3.0",
"m3u8-parser": "4.4.0",
"mpd-parser": "0.8.1",
"mux.js": "5.1.3",
"mux.js": "5.2.1",
"url-toolkit": "^2.1.3",
"video.js": "^6.8.0 || ^7.0.0"
}
......@@ -9225,21 +9225,11 @@
"resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
"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": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz",
"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": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz",
......@@ -9270,11 +9260,6 @@
"resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz",
"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": {
"version": "4.7.0",
"resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz",
......@@ -9348,9 +9333,9 @@
}
},
"m3u8-parser": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.3.0.tgz",
"integrity": "sha512-bVbjuBMoVIgFL1vpXVIxjeaoB5TPDJRb0m5qiTdM738SGqv/LAmsnVVPlKjM4fulm/rr1XZsKM+owHm+zvqxYA==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/m3u8-parser/-/m3u8-parser-4.4.0.tgz",
"integrity": "sha512-iH2AygTFILtato+XAgnoPYzLHM4R3DjATj7Ozbk7EHdB2XoLF2oyOUguM7Kc4UVHbQHHL/QPaw98r7PbWzG0gg==",
"requires": {
"global": "^4.3.2"
}
......@@ -9860,9 +9845,9 @@
"integrity": "sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s="
},
"mux.js": {
"version": "5.1.3",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.1.3.tgz",
"integrity": "sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg=="
"version": "5.2.1",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.2.1.tgz",
"integrity": "sha512-1t2payD3Y8izfZRq7tfUQlhL2fKzjeLr9v1/2qNCTkEQnd9Abtn1JgzsBgGZubEXh6lM5L8B0iLGoWQiukjtbQ=="
},
"nan": {
"version": "2.13.2",
......@@ -10025,9 +10010,9 @@
}
},
"node-sass": {
"version": "4.11.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.11.0.tgz",
"integrity": "sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==",
"version": "4.13.0",
"resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.0.tgz",
"integrity": "sha512-W1XBrvoJ1dy7VsvTAS5q1V45lREbTlZQqFbiHb3R3OTTCma0XBtuG6xZ6Z4506nR4lmHPTqVRwxT6KgtWC97CA==",
"requires": {
"async-foreach": "^0.1.3",
"chalk": "^1.1.1",
......@@ -10036,12 +10021,10 @@
"get-stdin": "^4.0.1",
"glob": "^7.0.3",
"in-publish": "^2.0.0",
"lodash.assign": "^4.2.0",
"lodash.clonedeep": "^4.3.2",
"lodash.mergewith": "^4.6.0",
"lodash": "^4.17.15",
"meow": "^3.7.0",
"mkdirp": "^0.5.1",
"nan": "^2.10.0",
"nan": "^2.13.2",
"node-gyp": "^3.8.0",
"npmlog": "^4.0.0",
"request": "^2.88.0",
......@@ -14587,11 +14570,6 @@
"resolved": "https://registry.npmjs.org/tslib/-/tslib-1.9.3.tgz",
"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": {
"version": "0.0.0",
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
......@@ -14982,25 +14960,24 @@
}
},
"video.js": {
"version": "7.6.0",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.0.tgz",
"integrity": "sha512-A0HSKzAmcYkd1xyExqUlM6n8bkghcX54iCvW08bPvvl3UHt8d8zijuylfIWu8vo1Z8fYyk9HPOFs1i3Cldr/cw==",
"version": "7.6.5",
"resolved": "https://registry.npmjs.org/video.js/-/video.js-7.6.5.tgz",
"integrity": "sha512-r0kC9SNJhXz9th/wwbRaLVOIZTvXkF+rhFq9/FWU+e+EJClwClRCgP8STGmfrPHDXrfWiJwH9YY21JZK61vGGQ==",
"requires": {
"@babel/runtime": "^7.4.5",
"@videojs/http-streaming": "1.10.3",
"@videojs/http-streaming": "1.10.6",
"global": "4.3.2",
"keycode": "^2.2.0",
"safe-json-parse": "4.0.0",
"tsml": "1.0.1",
"videojs-font": "3.2.0",
"videojs-vtt.js": "^0.14.1",
"xhr": "2.4.0"
},
"dependencies": {
"@babel/runtime": {
"version": "7.5.5",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.5.5.tgz",
"integrity": "sha512-28QvEGyQyNkB0/m2B4FU7IEZGK2NUrcMtT6BZEFALTguLk+AUT6ofsHtPk5QyjAdUkpMJ+/Em+quwz4HOt30AQ==",
"version": "7.6.3",
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.6.3.tgz",
"integrity": "sha512-kq6anf9JGjW8Nt5rYfEuGRaEAaH1mkv3Bbu6rYvLOpPh/RusSJXuKPEAoZ7L7gybZkchE8+NV5g9vKF4AGAtsA==",
"requires": {
"regenerator-runtime": "^0.13.2"
}
......
......@@ -46,13 +46,14 @@
"less-loader": "^4.1.0",
"lodash": "^4.17.15",
"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",
"pnp-webpack-plugin": "1.2.1",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.5.0",
"postcss-safe-parser": "4.0.1",
"prop-types": "^15.7.2",
"qrcode": "^1.3.3",
"qs": "^6.7.0",
"react": "^16.8.6",
......@@ -79,7 +80,7 @@
"swiper": "^4.5.0",
"terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2",
"video.js": "^7.6.0",
"video.js": "^7.6.5",
"web-launch-app": "^2.1.9",
"webpack": "4.28.3",
"webpack-dev-server": "3.1.14",
......
......@@ -5,5 +5,6 @@ var API = {
'passport-api': 'http://passport-test.julyedu.com',
'base-api': 'http://api-test.julyedu.com',
'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 {
if (cookie.get('uid') && this.props.user.hasError) {
this.getUser()
}
if(location.pathname==='/passport'){
window.localStorage.setItem('binding_redirect', JSON.stringify(this.previousLocation))
}
const {pathname, state} = location
if (pathname.startsWith('/passport')) {
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;
}
}
}
......@@ -5,8 +5,9 @@ export { default as OrderItem } from './OrderList'
export { default as HeaderBar } from './HeaderBar'
export { default as CallApp } from './CallApp'
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 RenderTabBar } from './renderTabBar'
export { default as Popup } from './closable-popup'
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 {
Toast.info('领取成功,你可前往七月在线官网/APP进行查看', 2);
localStorage.setItem('lingqu', 1);
}
}
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: 'https://m.julyedu.com/blessingPreheat',
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: 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: 30px;
font-size: 11px;
color: #fff;
text-align: center;
line-height: 30px;
&.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 { http, SendMessageToApp } from "@/utils";
import { Link } from 'react-router-dom';
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="course-popup__item"
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: 24px;
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__name {
width: 200px;
font-size: 12px;
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;
border: 1px solid rgba(255, 246, 4, 1);
border-radius: 0 0 6px 6px;
}
.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 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;
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.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>
</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;
height: 250px;
background: rgba(255, 255, 255, 1);
border-radius: 5px;
padding: 18px 24px 0 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;
height: 102px;
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;
}
}
}
.close__button {
width: 32px;
height: 32px;
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: 32px;
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 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;
}
}
}
\ No newline at end of file
import React, {Component} from 'react'
import {SendMessageToApp} from '@/utils'
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 {
......@@ -29,6 +32,7 @@ class ToAppDemo extends Component {
userInfoList: result
})
if (this.state.userInfoList.length !== 0) {
this.props.startFetchUser()
this.appLogin()
}
}
......@@ -43,6 +47,34 @@ class ToAppDemo extends Component {
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',
})
}
......@@ -76,10 +108,10 @@ class ToAppDemo extends Component {
QQshare = () => {
// 内容需要和产品确认
let data = {
title: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 标题
desc: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 描述
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/shareimg.png', // 图片地址
link: 'https://m.julyedu.com/blessingPreheat' // url
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)
}
......@@ -87,10 +119,10 @@ class ToAppDemo extends Component {
WXshare = () => {
// 内容需要和产品确认
let data = {
title: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 标题
desc: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 描述
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/shareimg.png', // 图片地址
link: 'https://m.julyedu.com/blessingPreheat' // url
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)
}
......@@ -98,10 +130,10 @@ class ToAppDemo extends Component {
// 邀请好友注册
toShare = () => {
let data = {
title: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 标题
desc: '11.11-11.13 AI充电节,预热来袭!重磅好课1折秒,超10万元奖品来就送-七月在线', // 描述
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/shareimg.png', // 图片地址
link: 'https://m.julyedu.com/blessingPreheat' // url
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)
}
......@@ -109,6 +141,7 @@ class ToAppDemo extends Component {
render() {
return (
<div>
<Button type={'primary'} onClick={() => this.testShare()}>测试分享</Button><WhiteSpace/>
<p>登录</p>
<Button type={'primary'} onClick={() => this.toLogin()}>App登录</Button><WhiteSpace/>
<p>去课程详情页</p>
......@@ -132,4 +165,10 @@ class ToAppDemo extends Component {
}
}
export default ToAppDemo
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
......@@ -3,7 +3,9 @@ import './coupon.scss'
import classnames from 'classnames'
import { http } from "@/utils"
import showAlert from '@common/deposit/end-expansion-alert'
import {Toast} from 'antd-mobile'
import { Toast } from 'antd-mobile'
import { withRouter } from "react-router-dom"
class Coupon extends PureComponent {
......@@ -12,9 +14,18 @@ class Coupon extends PureComponent {
EXPAND = 4 //膨胀全
pick = () => {
let {useCoupon, invalid} = this.props
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)
}
}
......@@ -38,8 +49,8 @@ class Coupon extends PureComponent {
.then(res => {
const {data} = res
if (data.code == 200) {
this.props.endExpansion(id)
}else {
this.props.endExpansion(id, data.data.coupon_id)
} else {
Toast.info(data.msg)
}
})
......@@ -209,4 +220,4 @@ function BaseCoupon(
)
}
export default Coupon
export default withRouter(Coupon)
......@@ -6,7 +6,6 @@ import Coupon from '../Coupon'
import { http, getParam } from '@/utils'
import { WithFullSize } from '@/HOCs'
import { Toast } from 'antd-mobile'
import { isEmpty } from 'lodash'
import { connect } from 'react-redux'
@connect()
......@@ -110,19 +109,13 @@ class UseCoupon extends PureComponent {
getMyCoupons = () => {
Promise.all([
http.get(`${API.home}/m/coupon/all`),
http.get(`${API.home}/m/coupon/expansion`)
http.get(`${API.home}/m/coupon/expansion`),
http.get(`${API.home}/m/coupon/all`)
]).then((coupons) => {
let myCoupons = []
const [allCoupons, expansionCoupons] = coupons
const [expansionCoupons, allCoupons] = coupons
const {data: all} = allCoupons
const {data: expansion} = expansionCoupons
if (all.code == 200) {
Array.isArray(all.data) && (myCoupons = myCoupons.concat(all.data))
} else {
Toast.info(all.msg)
}
if (expansion.code == 200) {
Array.isArray(expansion.data)
&& (expansion.data = expansion.data.map(item => (item.ctype = 4, item)))
......@@ -130,6 +123,11 @@ class UseCoupon extends PureComponent {
} else {
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
......@@ -139,25 +137,13 @@ class UseCoupon extends PureComponent {
getAllCoupons = () => {
Promise.all([
http.post(`${API.home}/m/coupon/select`, {course_id: this.state.courseId}),
http.get(`${API.home}/m/coupon/expansion`)
http.get(`${API.home}/m/coupon/expansion`),
http.post(`${API.home}/m/coupon/select`, {course_id: this.state.courseId})
]).then((coupons) => {
const [selectCoupons, expansionCoupons] = coupons
const [expansionCoupons, selectCoupons] = coupons
const {data: select} = selectCoupons
const {data: expansion} = expansionCoupons
if (select.code === 200) {
const inuse_coupon = select.data['inuse_coupon']
this.setState({
valid_coupons: inuse_coupon
? [...inuse_coupon, ...select.data.valid_coupons]
: select.data.valid_coupons,
invalid_coupons: select.data.invalid_coupons,
selectedCouponId: inuse_coupon.length ? inuse_coupon[0].id : 0
})
} else {
Toast.info(data.msg)
}
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)))
......@@ -167,8 +153,20 @@ class UseCoupon extends PureComponent {
} 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({
valid_coupons: PzCoupon.concat(PzCoupon2),
invalid_coupons: select.data.invalid_coupons,
selectedCouponId: inuse_coupon.length ? inuse_coupon[0].id : 0
})
} else {
Toast.info(data.msg)
}
})
}
......@@ -278,11 +276,12 @@ class UseCoupon extends PureComponent {
})
}
endExpansion = id => {
endExpansion = (id, validId) => {
this.setState({
couponList: this.state.couponList.map(item => {
valid_coupons: this.state.valid_coupons.map(item => {
if (item.id === id) {
delete item.start_amount
item.id = validId
}
return item
})
......@@ -353,6 +352,7 @@ function Content({coupons, ...rest}) {
{
coupons.map(item => {
return (
item.id &&
<Coupon
key={item.id}
{...item}
......
......@@ -23,7 +23,7 @@ class Deposit extends Component {
<div className="expand-bgimg">
<img
className="four-year"
src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/4year.png"
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>
......
......@@ -13,7 +13,7 @@
width: 100%;
height: 70px;
background-size: cover;
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/detail-expand-bg.png");
background-image: url("https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/detail-expand-bg.png");
.four-year {
width: 104px;
......
......@@ -21,6 +21,7 @@ class ToGroup extends Component {
number: 0, // 差几人成团
isBuy: false,
modal: false,
pddOrderId:''
}
}
......@@ -57,22 +58,26 @@ class ToGroup extends Component {
person_num: res.data.data.person_num,
course_list: res.data.data.course_list,
number: res.data.data.number,
pddOrderId: res.data.data.pdd_order_id,
countdown: '',
isBuy: res.data.data.is_buy
});
if (res.data.data.is_success === 0) {
let date = res.data.data.end_time * 1000,
day = 0,
hours = 0,
minutes = 0,
seconds = 0;
setInterval(() => {
date -= 1000
hours = `${parseInt(date / (60 * 60 * 1000))}`.padStart(2, 0);
minutes = `${parseInt((date - hours * 3600000) / 60000)}`.padStart(2, 0);
seconds = `${parseInt((date - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0);
day = `${parseInt(date / (3600000 * 24))}`.padStart(2, 0);
hours = `${parseInt((date- day * 3600000 * 24)/3600000)}`.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({
countdown: `${hours}:${minutes}:${seconds}`
// countdown: `${day}:${hours}:${minutes}:${seconds}`
countdown: `${day}${hours}${minutes}分`
});
}, 1000)
}
......@@ -98,7 +103,8 @@ class ToGroup extends Component {
history.push(
`/order?id=${data.course_id}`,
{
group: 1
group: 1,
pdd_order_id:this.state.pddOrderId
}
)
} else {
......
......@@ -48,7 +48,9 @@ class Detail extends Component {
nowPrice: 0,
laterPrice: 0,
isPdd: 0, // 是否是拼团课程 控制首次单集购买后的 全集购买 接口: 拼团课程走拼团接口,否则直接走购买接口
isRedPacket: true
isRedPacket: true,
countDownTime: '20s',
}
}
......@@ -73,6 +75,51 @@ class Detail extends Component {
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)
}
// 判断时候未红包课程
......@@ -298,16 +345,19 @@ class Detail extends Component {
if (course_info.group_status === 3 || course_info.group_status === 4) {
let endTime = course_info.pdd_group_info.groupon_member.end_time;
let date = endTime * 1000,
day = 0,
hours = 0,
minutes = 0,
seconds = 0;
setInterval(() => {
date -= 1000
hours = `${parseInt(date / (60 * 60 * 1000))}`.padStart(2, 0);
minutes = `${parseInt((date - hours * 3600000) / 60000)}`.padStart(2, 0);
seconds = `${parseInt((date - hours * 3600000 - minutes * 60000) / 1000)}`.padStart(2, 0);
day = `${parseInt(date / (3600000 * 24))}`.padStart(2, 0);
hours = `${parseInt((date- day * 3600000 * 24)/3600000)}`.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({
countdown: `${hours}:${minutes}:${seconds}`
// countdown: `${day}:${hours}:${minutes}:${seconds}`
countdown: `${day}${hours}${minutes}分`
});
}, 1000)
}
......@@ -443,7 +493,7 @@ class Detail extends Component {
}
render() {
const {course: {course_info = {}}, barInfo, singleBox, singleType, isRedPacket} = this.state;
const {course: {course_info = {}}, barInfo, singleBox, singleType, isRedPacket, countDownTime} = this.state;
let courseInfo = '',
service = '',
......@@ -468,8 +518,17 @@ class Detail extends Component {
if (getParam('dist_code')) {
href = '/'
}
let isCent = course_info.pdd_group_info && course_info.pdd_group_info.price != '0.01';
return (
<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'>
<HeaderBar
title='课程详情'
......@@ -641,17 +700,19 @@ class Detail extends Component {
* 拼团
* is_aist: 是否AI特训营
* group_status: 团状态,3:课程有小团 用户没参加小团;4:用户参加了小团
* 拼团价格为1分钱时,不允许参团
*/
}
{
!course_info.is_aist && (course_info.group_status === 3 || course_info.group_status === 4) &&
<Group
courseInfo={course_info}
history={this.props.history}
countdown={countdown}
invitedFriends={this.invitedFriends}
/>
}
{/*双十一期间不需要显示 不要删除*/}
{/*{*/}
{/*isCent && !course_info.is_aist && (course_info.group_status === 3 || course_info.group_status === 4) &&*/}
{/*<Group*/}
{/*courseInfo={course_info}*/}
{/*history={this.props.history}*/}
{/*countdown={countdown}*/}
{/*invitedFriends={this.invitedFriends}*/}
{/*/>*/}
{/*}*/}
{/*
* 砍价
......
......@@ -231,3 +231,26 @@
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 @@
}
.dec {
margin-top: 15px;
a{
word-break:break-all;
}
}
}
......
import React, {Component} from 'react'
import './share.scss'
import {http, getParam, browser, wxShare} from '@/utils'
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";
......@@ -21,14 +21,15 @@ class ExpandShare extends Component {
componentDidMount() {
this.getListorData()
this.getCourseList()
if(is_weixin()) {
wxShare({
title: '七月在线4岁啦,80元红包等你来拿!',
desc: '重磅好课1元购,大奖、红包轰趴7天7夜',
title: 'AI充电节,预热来袭!80元红包送给你,手要快!',
desc: '积福气享1折秒课,超10万元奖品来就送--七月在线',
link: window.location.href,
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/717/shareimg.png',
imgUrl: 'https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_1111/m/dj-share-img.png',
})
}
}
// 获取膨胀券相关
getListorData = () => {
......@@ -225,7 +226,7 @@ class ExpandShare extends Component {
return (
<div className="expand-box">
<div className="banner">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/active19_717/m/zl-banner.png" alt=""/>
<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">
......
......@@ -193,7 +193,7 @@ function PayInfo(props) {
</p>
<p>
<span className='payable'>已优惠:</span>
<span className='price'>¥{props.item.deposit_cut}</span>
<span className='price'>¥{props.item.discount}</span>
</p>
</div>
......
......@@ -176,10 +176,10 @@ class FinalDepositOrder extends Component {
//创建订单
createOrder = () => {
const {selectedCourses, salePrice, useBalance, user_account} = this.state
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: 0,
cut_amount: appliedMoneyOffRule.cut_amount || 0,
pay_amount: salePrice,
is_deduction: useBalance ? 1 : 0,
deduction_amount: useBalance ? this.getBalanceOffset() : 0,
......@@ -400,8 +400,9 @@ class FinalDepositOrder extends Component {
getBalanceOffset = () => {
let originalTotalPrice = this.getOriginTotalPrice()
let offset = parseFloat(this.state.user_account) - parseFloat(originalTotalPrice)
offset = offset >= 0 ? originalTotalPrice : this.state.user_account
let currentPrice = this.moneyOff(originalTotalPrice)
let offset = parseFloat(this.state.user_account) - parseFloat(currentPrice)
offset = offset >= 0 ? currentPrice : this.state.user_account
return offset
}
......@@ -421,7 +422,7 @@ class FinalDepositOrder extends Component {
return (
<div className='deposit-pay-order'>
<HeaderBar title='课程报名' arrow={true}></HeaderBar>
<WhiteSpace size='sm'></WhiteSpace>
<WhiteSpace size='sm' />
{/*<div className='order-number'>
<WingBlank>
<Flex justify='between' align='center' style={{height: '44px'}}>
......@@ -430,25 +431,26 @@ class FinalDepositOrder extends Component {
</Flex>
</WingBlank>
</div>*/}
<WhiteSpace size='md'></WhiteSpace>
<WhiteSpace size='md' />
<div className={'order-list'}>
<OrderList courses={categoryList}
<OrderList
courses={categoryList}
toggleSelectedCourse={this.toggleSelectedCourse}
/>
</div>
<div className="order-balance">
<List>
<Item
className="order-prefer-text"
>
<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>
<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>
......@@ -460,8 +462,10 @@ class FinalDepositOrder extends Component {
fontSize: '15px',
marginRight: "6px"
}}>{`-¥${offset}`}</span>
<i className={`iconfont icondanseshixintubiao-5 balance-used`}
onClick={this.useBalance}></i>
<i
className={`iconfont icondanseshixintubiao-5 balance-used`}
onClick={this.useBalance}
/>
</>
) : (
<i className='circle-icon' onClick={this.useBalance}></i>
......
......@@ -135,6 +135,7 @@ class Order extends Component {
Toast.info('请完善报名信息!');
}
const { location: { state ={} } } = this.props;
if(state.group === 1) {
let params = state.pdd_order_id? {
course_id: getParam("id"),
......@@ -145,8 +146,7 @@ class Order extends Component {
ischeck: this.state.useBalance,
}
http.post(`${API['base-api']}/pdd/m`, params).then(res => {
console.log(res);
if(res.data.errno === 200) {
if(Number(res.data.errno) === 200) {
sessionStorage.removeItem('orderUseCacheObj');
if (res.data.data.pay_jump === 1) {
this.props.history.push(`/togroup?id=${res.data.data.oid}`);
......@@ -154,7 +154,10 @@ class Order extends Component {
}
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);
return;
}
......
......@@ -112,6 +112,15 @@ export default class PayOrder extends Component {
// 微信内部-支付
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";
// 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 {
// 微信外部-支付
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 { withFormik, Field, Form } from "formik";
import { http, getParam } from "@/utils";
import { compose } from "redux";
import { connect } from "react-redux";
import { setCurrentUser } from "@/store/userAction";
import { withFormik, Field, Form } from "formik"
import { http, getParam } from "@/utils"
import { compose } from "redux"
import { connect } from "react-redux"
import { setCurrentUser } from "@/store/userAction"
import Captcha from '@/common/Captcha'
import { HeaderBar } from '@/common'
......@@ -13,8 +13,8 @@ import { HeaderBar } from '@/common'
import ClearableInput from '../common/clearableInputWithCountryCodes'
import Button from '../common/Button'
import VeriCodeInput from '../common/veriCodeInput'
import { Toast } from "antd-mobile";
import { isEmpty } from "lodash";
import { Toast } from "antd-mobile"
import { isEmpty } from "lodash"
class BindingTel extends Component {
......@@ -95,7 +95,7 @@ class BindingTel extends Component {
</Form>
</div>
</>
);
)
}
}
......@@ -123,22 +123,23 @@ const formikConfig = {
phone_num: values.tel,
phone_code: values.veriCode,
mkey: getParam('mkey'),
area_code: '00'+props.country.num,
area_code: '00' + props.country.num,
plat: 5
}).then(res => {
const data = res.data
if (data.errno == 200) {
if (data.data['is_set_pwd']) {
props.setCurrentUser({
const {history} = props
history.replace(`/passport/set-password`, {
user: {
hasError: false,
data: {
uid: data.data.uid
},
msg: data.data.msg,
stage: 'binding'
}
})
props.history.replace(`/passport/set-password`)
} else {
location.assign(data.data['jump_url'])
}
......@@ -156,4 +157,4 @@ export default compose(
{setCurrentUser}
),
withFormik(formikConfig),
)(BindingTel);
\ No newline at end of file
)(BindingTel)
......@@ -23,6 +23,7 @@ class Passport extends Component {
redirectURL = '/'
count = 1
blackList = new Set(['/passport/binding-tel', '/passport/set-password'])
constructor(props) {
super(props)
......@@ -85,7 +86,7 @@ class Passport extends Component {
routeWhenUserLoggedIn = () => {
let {hasError} = this.props.user
if (!hasError) {
if (!hasError && !this.blackList.has(this.props.location.pathname)) {
const redirectURI = getParam('redirect')
redirectURI ? (window.location.href = redirectURI) : this.props.history.go(-this.count)
}
......@@ -108,7 +109,9 @@ class Passport extends Component {
<Route path={match.url + '/account-login'} component={AccountLogin}/>
<Route path={match.url + '/forgot-password'} component={ForgotPassword}/>
<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}/>
</Switch>
</div>
......
import React, { Component } from 'react';
import React, { Component } from 'react'
import './set-password.scss'
import { withFormik, Form, Field } from "formik";
import { withFormik, Form, Field } from "formik"
import PasswordInput from '../common/passwordInput'
import Button from '../common/Button'
import classnames from 'classnames'
import { compose } from 'redux'
import { HeaderBar } from "@/common";
import { http, api } from "@/utils";
import { Toast } from "antd-mobile";
import { encrypt } from "@/components/passport/encryption";
import { Link } from "react-router-dom";
import { isEmpty } from "lodash";
import { connect } from "react-redux";
import { HeaderBar } from "@/common"
import { http } from "@/utils"
import { Toast } from "antd-mobile"
import { encrypt } from "@/components/passport/encryption"
import { Link } from "react-router-dom"
import { isEmpty } from "lodash"
import { connect } from "react-redux"
import { setCurrentUser } from '@/store/userAction'
class SetPassword extends Component {
render() {
......@@ -56,7 +56,7 @@ class SetPassword extends Component {
</div>
</div>
</>
);
)
}
}
......@@ -71,7 +71,7 @@ const formikConfig = {
let from = props.location.state && props.location.state.from || {pathname: '/'}
if (from.pathname.includes('forgot-password')) {
forgotPasswordReset(values, props);
forgotPasswordReset(values, props)
} else {
bindMobileSetPassword(values, props)
}
......@@ -80,7 +80,7 @@ const formikConfig = {
validateOnChange: false,
validate: values => {
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)) {
errors.password = '密码需要包含6-16位字母及数字'
Toast.info(errors.password, 2, null, false)
......@@ -122,10 +122,17 @@ function bindMobileSetPassword(values, props) {
})
.then(res => {
if (res.data.errno == 200) {
const {location, history} = props
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 () {
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)
} else {
Toast.info(res.data.msg, 2, null, false)
......@@ -136,7 +143,7 @@ function bindMobileSetPassword(values, props) {
export default compose(
connect(
state => ({user: state.user}),
null
{setCurrentUser}
),
withFormik(formikConfig)
)(SetPassword);
\ No newline at end of file
)(SetPassword)
......@@ -18,6 +18,7 @@ import Single from "@/components/detail/single";
import SingleSuccess from "../detail/single/singleSuccess";
import './CustomPlayButton'
let alert = Modal.alert
function ProgressShareModal(props) {
......@@ -606,6 +607,7 @@ class Video extends Component {
activeIndex: index
},
() => {
if (this.hasAuth(this.state.activeIndex)) {
this.setPlayerSrc(this.state.videoList[index]['play_url'])
this.sendLastRecord()
......@@ -708,7 +710,10 @@ class Video extends Component {
}
playVideo = () => {
this.player.ready(() => {
this.player.play()
})
}
......
......@@ -33,6 +33,8 @@ const ShareCourse = loadable(() => import(/* webpackChunkName: 'ShareCourse'*/'@
const Country = loadable(() => import(/* webpackChunkName: 'Country' */'@/components/country/index'))
const ExpandCallback = loadable(() => import('@/components/expand/callback'))
const ExpandShare = loadable(() => import('@/components/expand/share'))
const Activity = loadable(() => import(/* webpackChunkName: 'Activity' */'@/components/activity/index'))
const Invite = loadable(() => import(/* webpackChunkName: 'Invite' */'@/components/activity/invite'))
export default [
{
path: '/',
......@@ -171,6 +173,18 @@ export default [
path: '/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',
......@@ -199,5 +213,13 @@ export default [
{
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 () {
isWeixin: /MicroMessenger/i.test(ua),
isAndroid: /Android/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:
resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d"
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:
version "4.3.0"
resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6"
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:
version "4.0.8"
resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af"
......@@ -6851,11 +6841,6 @@ lodash.memoize@^4.1.2:
resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe"
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:
version "4.7.0"
resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438"
......@@ -7354,11 +7339,16 @@ mux.js@5.1.3:
resolved "https://registry.yarnpkg.com/mux.js/-/mux.js-5.1.3.tgz#1a59b8979a6780be5bcb63983c7e883c90cd615b"
integrity sha512-FhDcysLvAkO9H8ftBJ2sK1O4Rmz0AWnMS+2uqP7WjrnaAyE/ox11GEiZkRzrWIdp8at9R9qBHDqdURY3/h/xTg==
nan@^2.10.0, nan@^2.12.1:
nan@^2.12.1:
version "2.13.2"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.13.2.tgz#f51dc7ae66ba7d5d55e1e6d4d8092e802c9aefe7"
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:
version "1.2.13"
resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119"
......@@ -7525,10 +7515,10 @@ node-releases@^1.1.25:
dependencies:
semver "^5.3.0"
node-sass@^4.11.0:
version "4.11.0"
resolved "https://registry.yarnpkg.com/node-sass/-/node-sass-4.11.0.tgz#183faec398e9cbe93ba43362e2768ca988a6369a"
integrity sha512-bHUdHTphgQJZaF1LASx0kAviPH7sGlcyNhWade4eVIpFp6tsn7SV8xNMTbsQFpEV9VXpnwTTnNYlfsZXgGgmkA==
node-sass@^4.13.0:
version "4.13.0"
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 sha1-tkcoi6vdahy3Jt5FRVFrMfkNoGY=
dependencies:
async-foreach "^0.1.3"
chalk "^1.1.1"
......@@ -7537,12 +7527,10 @@ node-sass@^4.11.0:
get-stdin "^4.0.1"
glob "^7.0.3"
in-publish "^2.0.0"
lodash.assign "^4.2.0"
lodash.clonedeep "^4.3.2"
lodash.mergewith "^4.6.0"
lodash "^4.17.15"
meow "^3.7.0"
mkdirp "^0.5.1"
nan "^2.10.0"
nan "^2.13.2"
node-gyp "^3.8.0"
npmlog "^4.0.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