Commit 17563eb1 by zhanghaozhe

Merge branch 'limit-free' into dev

# Conflicts:
#	src/components/video/index.js
parents 16d7e00c 8c943d62
No preview for this file type
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
No preview for this file type
No preview for this file type
No preview for this file type
.v-list-base-item { .v-list-base-item {
height: 130px; //height: 130px;
padding: 10px 10px 0; padding: 10px 10px 0;
position: relative; position: relative;
......
#chatBtn { #chatBtn {
bottom: 60px!important; bottom: 60px !important;
} }
.index-box { .index-box {
overflow: hidden; overflow: hidden;
background-color: $bg_fff; background-color: $bg_fff;
...@@ -283,6 +284,20 @@ ...@@ -283,6 +284,20 @@
font-size: 16px; font-size: 16px;
color: $color_333; color: $color_333;
display: inline-block; display: inline-block;
.hot {
display: inline-block;
width: 25px;
height: 14px;
margin-left: 5px;
transform: translateY(-5px);
background: rgba(255, 64, 0, 1);
border-radius: 7px 7px 7px 0;
color: #fff;
text-align: center;
line-height: 14px;
font-size: 12px;
}
} }
.more { .more {
...@@ -358,6 +373,11 @@ ...@@ -358,6 +373,11 @@
text-align: center; text-align: center;
line-height: 18px; line-height: 18px;
} }
.free{
color: $red;
font-size: 15px;
}
} }
/* /*
...@@ -511,7 +531,7 @@ ...@@ -511,7 +531,7 @@
text-align: center; text-align: center;
height: 47px; height: 47px;
button,a { button, a {
width: 60px; width: 60px;
height: 27px; height: 27px;
background-color: $bg_active; background-color: $bg_active;
...@@ -524,7 +544,8 @@ ...@@ -524,7 +544,8 @@
margin-left: -30px; margin-left: -30px;
bottom: 10px; bottom: 10px;
} }
a{
a {
width: 90px; width: 90px;
line-height: 27px; line-height: 27px;
margin-left: -45px; margin-left: -45px;
...@@ -740,9 +761,89 @@ ...@@ -740,9 +761,89 @@
// //.is-visible { // //.is-visible {
// // background-image: none; // // background-image: none;
// //} // //}
.limit-free {
padding: 0 15px;
color: #333;
h2 {
display: flex;
align-items: center;
margin: 15px 0;
font-size: 15px;
}
.hot {
display: inline-block;
width: 25px;
height: 14px;
margin-left: 5px;
background: rgba(255, 64, 0, 1);
border-radius: 7px 7px 7px 0;
color: #fff;
text-align: center;
line-height: 14px;
font-size: 12px;
}
ul {
display: flex;
flex-wrap: wrap;
li {
margin-right: 15px;
margin-top: 0;
margin-bottom: 20px;
}
& li:nth-child(2n) {
margin-right: 0;
}
}
.origin-price {
color: #999;
font-size: 12px;
text-decoration: line-through;
}
.bottom {
margin-top: 5px;
span{
margin-right: 5px;
}
span:nth-child(3){
margin-right: 0;
}
}
$red: #FF2121;
.bottom span:nth-child(1), .bottom button:nth-child(1) {
margin-right: 6px;
}
.current-price, .free {
color: $red;
font-size: 15px;
}
button {
width: 61px;
height: 18px;
background: rgba(0, 153, 255, 1);
border-radius: 9px;
text-align: center;
color: #fff;
font-size: 12px;
-webkit-appearance: none;
outline: 0;
border: 0;
}
}
} }
.index-box + .nav-bar + .year19-index{ .index-box + .nav-bar + .year19-index {
display: none; display: none;
} }
......
...@@ -112,6 +112,19 @@ html,body,#root { ...@@ -112,6 +112,19 @@ html,body,#root {
text-align: center; text-align: center;
line-height: 18px; line-height: 18px;
} }
.limit-free{
span:first-child{
color: #FF2121;
font-size: 15px;
margin-right: 10px;
}
span:last-child{
color: #999;
font-size: 11px;
text-decoration: line-through;
}
}
} }
} }
} }
......
...@@ -523,6 +523,19 @@ class BtnStatus extends Component { ...@@ -523,6 +523,19 @@ class BtnStatus extends Component {
</Overlay> </Overlay>
} }
{
//todo 联调
info.is_limit_free && info.limit_free_status == 0 && <div className='btns-box'>
<a className='consult consult-m' onClick={()=>this.qimoChatClick()}>
<i className='iconfont iconerji'></i>
<span>课程咨询</span>
</a>
<button className={'get-course btn'} onClick={() => {this.props.getCourse(info.course_id)}}>立即领取</button>
</div>
}
</div> </div>
) )
} }
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
background-color: $bg_fff; background-color: $bg_fff;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
box-shadow:0px 0px 5px 0px rgba(0, 0, 0, 0.1); box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
z-index: 3; z-index: 3;
.consult { .consult {
...@@ -84,18 +84,26 @@ ...@@ -84,18 +84,26 @@
font-size: 12px; font-size: 12px;
} }
} }
.sign-up-now { .sign-up-now {
width: 50%; width: 50%;
color: #fff; color: #fff;
font-size: 16px; font-size: 16px;
background: linear-gradient(270deg,rgba(255,64,0,1) 0%,rgba(253,119,0,1) 100%); background: linear-gradient(270deg, rgba(255, 64, 0, 1) 0%, rgba(253, 119, 0, 1) 100%);
} }
.learn-now { .learn-now {
background-color: #0099FF; background-color: #0099FF;
font-size: 16px; font-size: 16px;
color: #FFF; color: #FFF;
} }
.get-course {
width: 280px;
height: 44px;
background: linear-gradient(90deg, rgba(253, 119, 0, 1) 0%, rgba(255, 64, 0, 1) 100%);
}
.btn-m { .btn-m {
width: 50%; width: 50%;
} }
......
...@@ -82,6 +82,22 @@ ...@@ -82,6 +82,22 @@
} }
} }
.limit-free{
span:first-child{
color: #FF2121;
font-size: 15px;
margin-right: 10px;
}
.origin-price{
font-size: 11px;
color: #999;
text-decoration: line-through;
}
}
.time-limit{
color: #FF2121;
}
.isbuy { .isbuy {
display: inline-block; display: inline-block;
width: 66px; width: 66px;
...@@ -253,4 +269,50 @@ ...@@ -253,4 +269,50 @@
bottom: 4px; bottom: 4px;
left: 8px; left: 8px;
} }
}
.get-course-popup {
top: 210px !important;
padding-bottom: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
.title {
text-align: center;
margin-bottom: 30px;
img {
width: 30px;
height: 30px;
}
div {
font-size: 14px;
color: #525C65;
}
}
.btns {
border-top: 1px solid #DDD;
display: flex;
height: 40px;
button {
-webkit-appearance: none;
width: 50%;
border: none;
outline: none;
color: #333;
background: #fff;
border-radius: 0 0 5px 5px;
}
& button:first-child {
border-right: 1px solid #DDD;
}
& button:last-child {
color: #09f;
}
}
} }
\ No newline at end of file
import React, { Component } from 'react'
import { http } from "@/utils"
import './index.scss'
import { HeaderBar } from "@common/index"
import { WhiteSpace, Toast } from "antd-mobile";
import VList from '@/common/v-list-base'
import { Popup } from "@common/index"
import WithFullSize from "@/HOCs/WithFullSize"
import { connect } from "react-redux";
import { Link } from "react-router-dom";
function showToast(msg) {
Toast.info(msg, 2, null, false)
}
class LimitFree extends Component {
nav
state = {
tab: {},
courses: [],
navItemStyle: {},
tabActiveIndex: 0
}
componentDidMount() {
const {user, history} = this.props
if (user.hasError) {
history.push('/passport')
}
this.getData()
}
getData = () => {
Promise.all([http.get(`${API.home}/sys/category`), http.get(`${API.home}/sys/course`)])
.then(res => {
const [tab, courses] = res
const {data: tabData, code: tabCode, msg: tabMsg} = tab.data
const {data: coursesData, code: coursesCode, msg: coursesMsg} = courses.data
if (tabCode == 200) {
this.setState({
tab: tabData
})
} else {
showToast(tabMsg)
}
if (coursesCode === 200) {
this.setState({
courses: coursesData
})
} else {
showToast(coursesMsg)
}
})
}
handleClick = id => {
this.props.history.push(`/detail?id=${id}`)
}
changeTab = (e, index) => {
const {tabActiveIndex} = this.state
if (tabActiveIndex !== index) {
this.setState({
tabActiveIndex: index
}
)
}
}
getCourse = id => {
http.post(`${API.home}/sys/limitFree/receive`, {
course_id: id
})
.then(res => {
const {code, msg} = res.data
if (code === 200) {
const instance = Popup({
className: 'get-course-popup',
closable: false,
clickMaskClose: false,
title: <div>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/time_limited_free/M/check.png" alt=""/>
<div>课程有效期7天,快去学习吧~</div>
</div>,
content: <div className={'btns'}>
<button onClick={() => {
instance.close()
this.getData()
}}>知道了
</button>
<button onClick={this.toPlay.bind(this, id)}>立即学习</button>
</div>
})
} else {
showToast(msg)
}
})
}
toPlay = id => {
this.props.history.push(`/play/video?id=${id}`)
}
formatTime = seconds => ({
d: Math.floor(seconds / 60 / 60 / 24).toString().padStart(2, '0'),
h: Math.floor(seconds / 60 / 60 % 24).toString().padStart(2, '0'),
m: Math.floor(seconds / 60 % 60).toString().padStart(2, '0')
})
render() {
const {tab, courses, navItemStyle, tabActiveIndex} = this.state
return (
<div className='limit-free'>
<HeaderBar arrow={true} title={'限时免费'}></HeaderBar>
<div className="banner">
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/time_limited_free/M/banner.png" alt=""/>
</div>
<nav>
<div className="prev-cover"></div>
<ul ref={el => this.nav = el}>
{
tab && !!Object.keys(tab).length && Object.keys(tab).map((item, index) => {
return (
<li key={index} className={index === tabActiveIndex ? 'active' : ''} style={navItemStyle}
onClick={e => this.changeTab(e, index)}>
<a href={`#category${item}`} target={'_self'}>{tab[item]}</a>
</li>
)
})
}
</ul>
<div className="next-cover"></div>
</nav>
<WhiteSpace/>
<div className="course-list">
<ul>
{
tab && !!Object.keys(tab).length && Object.keys(tab).map(key => {
return (
<li key={key} className={'category'}>
<h2 id={`category${key}`}>
<img src="https://julyedu-cdn.oss-cn-beijing.aliyuncs.com/time_limited_free/M/category-icon.png"
alt=""/>
<span>{tab[key]}</span>
</h2>
<ul className={'courses'}>
{
courses && courses.length && courses.map((item, index) => {
if (item.category_id != key) {
return null
}
/*
* course_status:
* 0未领取 1已领取未过期 2 已领取已过期 3 正常已购买
* */
let des, bottom
switch (item.course_status) {
case 0:
des = <div className={'learner'}>
<i className='iconfont iconRectangleCopy4'/>
<span>{item.play_times}人学习</span>
</div>
bottom = <div className={'bottom'}>
<span className={'red'}>限时免费</span>
<span className={'origin-price'}>¥{item.price0}</span>
<button onClick={this.getCourse.bind(this, item.course_id)}>免费领取</button>
</div>
break
case 1:
const {d, h, m} = this.formatTime(item.course_expire)
des = <div className={'remain-time'}>
<i className={'iconfont iconiconfront-21'}/>
<span>{d}{h}{m}分后过期</span>
</div>
bottom = <div className={'bottom'}>
<span className={'red'}>限时免费</span>
<span className={'origin-price'}>¥{item.price0}</span>
<StudyButton id={item.course_id}/>
</div>
break
case 2:
des = <div className={'remain-time'}>
<i className={'iconfont iconiconfront-21'}/>
<span>{item.play_times}人学习</span>
</div>
bottom = <div className={'bottom'}>
<span className={'red'}>¥{item.price1}</span>
<span className={'origin-price'}>¥{item.price0}</span>
<Link to={`/detail?id=${item.course_id}`}>立即购买</Link>
</div>
break
case 3:
des = <div className={'purchased'}>
<i className='iconfont iconRectangleCopy4'/>
<span>{item.play_times}人学习</span>
</div>
bottom = <div className="bottom">
<span>已购买</span>
<StudyButton id={item.course_id}/>
</div>
}
const info = (
<div className='info'>
<div className='title'>{item.course_title}</div>
{des}
{bottom}
</div>
)
return (
<VList img={item.image_name}
handleClick={this.handleClick}
id={item.course_id}
info={info}
key={index}
/>
)
})
}
</ul>
</li>
)
})
}
</ul>
</div>
<div className="no-more">
-没有更多了-
</div>
</div>
);
}
}
function StudyButton({id}) {
return <Link to={`/play/video?id=${id}`}>立即学习</Link>
}
export default connect(
state => ({user: state.user}),
null
)
(WithFullSize(LimitFree))
\ No newline at end of file
.limit-free {
background: #F9F9FB;
min-height: 100%;
.banner {
font-size: 0;
img {
width: 100%;
}
}
nav {
position: sticky;
top: 0;
left: 0;
display: flex;
align-items: center;
height: 39px;
background: #fff;
overflow: hidden;
z-index: 999;
.prev-cover, .next-cover {
position: absolute;
top: 0;
width: 44px;
height: 39px;
pointer-events: none;
}
.prev-cover {
left: 0;
background: linear-gradient(90deg, rgba(255, 255, 255, 1), rgba(255, 255, 255, 0));
}
.next-cover {
right: 0;
background: linear-gradient(90deg, rgba(255, 255, 255, 0), rgba(255, 255, 255, 1));
}
ul {
width: 100%;
height: 100%;
padding: 0 18px;
display: flex;
align-items: center;
overflow-x: auto;
&::-webkit-scrollbar {
display: none;
}
}
li {
width: 20%;
text-align: center;
height: 100%;
line-height: 39px;
flex-shrink: 0;
&.active {
color: #09f;
border-bottom: 1px solid #09f;
}
}
}
.course-list {
border-top: 1px solid transparent;
}
.category {
padding: 12px 12px 0;
background: #fff;
margin-bottom: 8px;
}
h2 {
scroll-margin-top: 45px;
}
.courses li:nth-last-child(1) {
margin-bottom: 0;
& div {
border-bottom: none;
}
}
.v-list-base-item {
padding: 0;
margin-bottom: 18px;
}
h2 {
display: flex;
align-items: center;
margin: 18px 0;
img {
width: 12px;
height: 12px;
margin-right: 6px;
}
span {
font-size: 16px;
color: #333;
}
}
.iconfont {
font-size: 12px;
margin-right: 4px;
}
.info {
display: flex;
flex-wrap: wrap;
align-items: flex-start;
font-size: 12px;
color: #999;
.red {
color: #FF2121;
font-size: 15px;
margin-right: 10px;
}
.origin-price {
color: #999;
font-size: 12px;
text-decoration: line-through;
}
button, a {
width: 68px;
height: 24px;
float: right;
border-radius: 3px;
background: #09f;
border: none;
font-size: 13px;
color: #fff;
line-height: 24px;
text-align: center;
}
button {
-webkit-appearance: none;
outline: 0;
}
.bottom {
width: 100%;
height: 24px;
align-self: flex-end;
font-size: 0;
line-height: 24px;
span {
font-size: 12px;
}
}
}
.no-more {
width: 375px;
height: 82px;
line-height: 82px;
background: #F7F9FC;
font-size: 14px;
color: #AAA;
text-align: center;
}
}
.get-course-popup {
top: 210px !important;
padding-bottom: 0 !important;
padding-left: 0 !important;
padding-right: 0 !important;
.title {
text-align: center;
margin-bottom: 30px;
img {
width: 30px;
height: 30px;
}
div {
font-size: 14px;
color: #525C65;
}
}
.btns {
border-top: 1px solid #DDD;
display: flex;
height: 40px;
button {
-webkit-appearance: none;
width: 50%;
border: none;
outline: none;
color: #333;
background: #fff;
border-radius: 0 0 5px 5px;
}
& button:first-child {
border-right: 1px solid #DDD;
}
& button:last-child {
color: #09f;
}
}
}
\ No newline at end of file
import React, {Component} from 'react'; import React, { Component } from 'react';
import './index.scss'; import './index.scss';
import {HeaderBar, VList} from '../../common' import { HeaderBar, VList } from '../../common'
import { http } from "@/utils"; import { http, dateCountDown } from "@/utils";
import {Link} from 'react-router-dom' import { Link } from 'react-router-dom'
import {Toast} from 'antd-mobile' import { Toast } from 'antd-mobile'
import {connect} from "react-redux" import { connect } from "react-redux"
import {getCourses} from './../detail/actions';
import Loading from '@/common/Loading' import Loading from '@/common/Loading'
class Purchased extends Component { class Purchased extends Component {
constructor(props) { constructor(props) {
super(props) super(props)
this.state = { this.state = {
data: [], data: [],
isLoading: true isLoading: true
}
} }
}
componentDidMount() { componentDidMount() {
this.getList() this.getList()
} this.limitFreeCountDown()
}
// 获取订单 // 获取订单
getList = () => { getList = () => {
http.get(`${API.home}/m/my/courses`,).then((res) => { http.get(`${API.home}/m/my/courses`,).then((res) => {
if (res.data.code === 200) { if (res.data.code === 200) {
this.setState({ this.setState({
data: res.data.data, data: res.data.data,
isLoading: false isLoading: false
})
} else {
Toast.info(res.data.msg, 2);
}
}) })
} } else {
Toast.info(res.data.msg, 2);
}
})
}
toCourseDetail = (id) => { toCourseDetail = (id) => {
const { dispatch, history } = this.props; const {dispatch, history} = this.props;
// dispatch(getCourses(id, () => { // dispatch(getCourses(id, () => {
history.push(`/detail?id=${id}`) history.push(`/detail?id=${id}`)
// })); // }));
} }
limitFreeCountDown = timestamp => {
//todo 联调
const later = new Date(timestamp)
const earlier = Date.now()
return dateCountDown(later, earlier)
}
render() { render() {
const {user} = this.props const {user} = this.props
const uid = user && user.data && user.data.uid const uid = user && user.data && user.data.uid
return ( return (
<div className='purchased-box'> <div className='purchased-box'>
<HeaderBar arrow={true} title='已购课程' cart={false} toHref='/my' /> <HeaderBar arrow={true} title='已购课程' cart={false} toHref='/my'/>
<Loading isLoading={this.state.isLoading}> <Loading isLoading={this.state.isLoading}>
{ {
this.state.data && this.state.data.length > 0 ? this.state.data && this.state.data.length > 0 ?
<div className="purchased-body"> <div className="purchased-body">
<div className='tip'>加群请备注您的学号:{uid}</div> <div className='tip'>加群请备注您的学号:{uid}</div>
{ {
this.state.data.map((item, index) => { this.state.data.map((item, index) => {
const Info = ( const Info = (
<div className="info"> <div className="info">
<p className='title' onClick={() => this.toCourseDetail(item.course_id)}> <p className='title' onClick={() => this.toCourseDetail(item.course_id)}>
{/* <Link to={`/detail?id=${item.course_id}`}> */} {item.course_title}
{item.course_title} </p>
{/* </Link> */} <p className='contact text-overflow-2'>{item.simpledescription}</p>
</p>
<p className='contact text-overflow-2'>{item.simpledescription}</p>
{ {
item.is_aist && item.is_aist &&
<div className='des'>助教微信:{item.assist_weixin}</div> <div className='des'>助教微信:{item.assist_weixin}</div>
} }
{ {
!item.is_aist && item.contact_type == 1 && item.course_qq && !item.is_aist && item.contact_type == 1 && item.course_qq &&
<div className='des'>QQ群:{item.course_qq}</div> <div className='des'>QQ群:{item.course_qq}</div>
} }
{ {
!item.is_aist && item.contact_type == 2 && item.course_qq && !item.is_aist && item.contact_type == 2 && item.course_qq &&
<div className='des'>班主任微信:{item.course_qq}</div> <div className='des'>班主任微信:{item.course_qq}</div>
} }
</div> </div>
) )
const status = ( const status = (
item.is_aist && <span className='status'>返现</span> // item.is_aist && <span className='status'>返现</span>
) <span className='limit-free-status'>{'*'}{'*'}{'*'}分后过期</span>
const courseExpire = ( )
item.course_expire && item.course_expire!='' && const courseExpire = (
<span className='course-expire'>{item.course_expire}</span> item.course_expire && item.course_expire != '' &&
) <span className='course-expire'>{item.course_expire}</span>
return ( )
<VList return (
key={index} <VList
img={item.image_name} key={index}
id={item.course_id} img={item.image_name}
info={Info} id={item.course_id}
status={status} info={Info}
courseExpire={courseExpire} status={status}
toDetail={this.toCourseDetail} courseExpire={courseExpire}
/> toDetail={this.toCourseDetail}
) />
}) )
} })
</div> }
: <div className="cart-tip"> </div>
<p className='cart-mess'>您还没有课程哦,快去逛逛吧~</p> : <div className="cart-tip">
<Link to='/classify'>去逛逛</Link> <p className='cart-mess'>您还没有课程哦,快去逛逛吧~</p>
</div> <Link to='/classify'>去逛逛</Link>
} </div>
</Loading> }
</Loading>
</div> </div>
) )
} }
} }
export default connect( export default connect(
state => ({user: state.user}), state => ({user: state.user}),
null null
)(Purchased) )(Purchased)
html, body, #root { html, body, #root {
height: 100%!important; height: 100% !important;
} }
.purchased-box {
width: 100%;
height: 100%;
//background-color: $bg_f5f5f5;
.purchased-box {
width: 100%;
height: 100%;
//background-color: $bg_f5f5f5;
.tip {
width: 100%;
height: 30px;
line-height: 30px;
font-size: 12px;
color: $color_333;
text-align: center;
background-color: $bg_FFF4CE;
margin-bottom: 10px;
}
.purchased-body { .tip {
background-color: $bg_fff; width: 100%;
height: 30px;
line-height: 30px;
font-size: 12px;
color: $color_333;
text-align: center;
background-color: $bg_FFF4CE;
margin-bottom: 10px;
}
.purchased-body {
background-color: $bg_fff;
}
.v-list-item {
background-color: #fff;
.content {
padding-bottom: 10px;
border-bottom: 1px solid #e7eaf1;
.cover {
flex: inherit;
width: 42.2%;
img {
width: 100%;
}
}
} }
.v-list-item { .info {
background-color: #fff; width: 52.3%;
position: relative;
.content { display: block;
padding-bottom: 10px;
border-bottom: 1px solid #e7eaf1;
.cover {
flex: inherit;
width: 42.2%;
img { .title {
width: 100%; font-size: 16px;
} color: $color_333;
} overflow: hidden;
} text-overflow: ellipsis;
white-space: nowrap;
height: 16px;
line-height: 16px;
}
.contact {
font-size: 14px;
color: $color_666;
margin-top: 14px;
}
.info { .des {
width: 52.3%; position: absolute;
position: relative; bottom: 5px;
display: block; color: $active;
font-size: 14px;
.title { height: 14px;
font-size: 16px; line-height: 14px;
color: $color_333; }
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 16px;
line-height: 16px;
}
.contact {
font-size: 14px;
color: $color_666;
margin-top: 14px;
}
.des {
position: absolute;
bottom: 5px;
color: $active;
font-size: 14px;
height: 14px;
line-height: 14px;
}
}
} }
}
.cart-tip { .cart-tip {
color: #555; color: #555;
margin-top: 140px; margin-top: 140px;
text-align: center; text-align: center;
.iconfridge {
font-size: 21px;
}
.cart-mess {
font-size: 12px;
color: $color_666;
}
a { .iconfridge {
display: inline-block; font-size: 21px;
width: 130px;
height: 30px;
border: 1px solid $bg_active;
border-radius: 15px;
font-size: 16px;
margin-top: 30px;
color: $active;
text-align: center;
line-height: 28px;
}
} }
.status { .cart-mess {
position: absolute; font-size: 12px;
top: 0; color: $color_666;
right: 0;
padding: 2px 6px;
border-radius: 11px 0 0 11px;
font-size: 14px;
color: #fff;
background: linear-gradient(to bottom, #FF4000, #FD7700);
} }
.course-expire{
display: inline-block; a {
text-align: center; display: inline-block;
position: absolute; width: 130px;
bottom: 10px; height: 30px;
left: 0; border: 1px solid $bg_active;
width:92px; border-radius: 15px;
height:20px; font-size: 16px;
line-height: 21px; margin-top: 30px;
background-color: #FF3A3A; color: $active;
border-radius:0 10px 10px 0; text-align: center;
color: #fff; line-height: 28px;
font-size: 12px;
} }
}
.status {
position: absolute;
top: 0;
right: 0;
padding: 2px 6px;
border-radius: 11px 0 0 11px;
font-size: 14px;
color: #fff;
background: linear-gradient(to bottom, #FF4000, #FD7700);
}
.limit-free-status {
position: absolute;
right: 0;
top: 8px;
width: 112px;
height: 20px;
background: #FF0000;
border-radius: 10px 0 0 10px;
line-height: 20px;
color: #fff;
text-align: center;
font-size: 11px;
}
.course-expire {
display: inline-block;
text-align: center;
position: absolute;
bottom: 10px;
left: 0;
width: 92px;
height: 20px;
line-height: 21px;
background-color: #FF3A3A;
border-radius: 0 10px 10px 0;
color: #fff;
font-size: 12px;
}
} }
\ No newline at end of file
...@@ -299,4 +299,10 @@ export default [ ...@@ -299,4 +299,10 @@ export default [
exact: true, exact: true,
component: loadable(() => import('@/components/college/courseList')) component: loadable(() => import('@/components/college/courseList'))
}, },
//限时免费落地页
{
path:'/free',
exact: true,
component: loadable(() => import(/*limit-free*/'@/components/limit-free'))
}
] ]
import jsCookie from "js-cookie"; import jsCookie from "js-cookie";
import {
differenceInDays,
differenceInHours,
differenceInMinutes,
differenceInSeconds
} from 'date-fns'
export const getParam = (key, str) => { export const getParam = (key, str) => {
const _s = str ? str : location.href; const _s = str ? str : location.href;
const re = new RegExp(`(?:\\?|#|&)(${key})=([^=&#\\?]+)`, 'ig'); const re = new RegExp(`(?:\\?|#|&)(${key})=([^=&#\\?]+)`, 'ig');
let found; let found;
return (found = re.exec(_s)) ? found[2] : null; return (found = re.exec(_s)) ? found[2] : null;
} }
const html = content => ({__html: htmlDecode(content)}) const html = content => ({
__html: htmlDecode(content)
})
const htmlDecode = content => { const htmlDecode = content => {
let e = document.createElement('div'); let e = document.createElement('div');
e.innerHTML = content; e.innerHTML = content;
return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue; return e.childNodes.length === 0 ? "" : e.childNodes[0].nodeValue;
} }
//加载网易易盾辅助函数 //加载网易易盾辅助函数
function getTimestamp(msec) { function getTimestamp(msec) {
msec = !msec && msec !== 0 ? msec : 1 msec = !msec && msec !== 0 ? msec : 1
return parseInt((new Date()).valueOf() / msec, 10) return parseInt((new Date()).valueOf() / msec, 10)
} }
function loadScript(src, cb) { function loadScript(src, cb) {
var head = document.head || document.getElementsByTagName('head')[0] var head = document.head || document.getElementsByTagName('head')[0]
var script = document.createElement('script') var script = document.createElement('script')
cb = cb || function () { cb = cb || function () {
} }
script.type = 'text/javascript' script.type = 'text/javascript'
script.src = src script.src = src
if (!('onload' in script)) { if (!('onload' in script)) {
script.onreadystatechange = function () { script.onreadystatechange = function () {
if (this.readyState !== 'complete' && this.readyState !== 'loaded') return if (this.readyState !== 'complete' && this.readyState !== 'loaded') return
this.onreadystatechange = null this.onreadystatechange = null
cb(script) cb(script)
}
} }
}
script.onload = function () { script.onload = function () {
this.onload = null this.onload = null
cb(script) cb(script)
} }
head.appendChild(script) head.appendChild(script)
} }
function initCaptcha(cb) { function initCaptcha(cb) {
if (window.initNECaptcha) { if (window.initNECaptcha) {
cb() cb()
} else { } else {
const url = '//cstaticdun.126.net/load.min.js' + '?t=' + getTimestamp(1 * 60 * 1000) const url = '//cstaticdun.126.net/load.min.js' + '?t=' + getTimestamp(1 * 60 * 1000)
loadScript(url, cb) loadScript(url, cb)
} }
} }
export const is_weixin = () => { export const is_weixin = () => {
var ua = window.navigator.userAgent.toLowerCase(); var ua = window.navigator.userAgent.toLowerCase();
if (ua.match(/MicroMessenger/i) == 'micromessenger') { if (ua.match(/MicroMessenger/i) == 'micromessenger') {
return true; return true;
} }
return false; return false;
} }
function validateTel(tel) { function validateTel(tel) {
return /^1[3-9](\d{9})$/.test(tel) return /^1[3-9](\d{9})$/.test(tel)
} }
function validateEmail(email) { function validateEmail(email) {
var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/; var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase()); return re.test(String(email).toLowerCase());
} }
const browser = (function () { const browser = (function () {
const ua = navigator.userAgent const ua = navigator.userAgent
return { return {
isWeixin: /MicroMessenger/i.test(ua), isWeixin: /MicroMessenger/i.test(ua),
isAndroid: /Android/i.test(ua), isAndroid: /Android/i.test(ua),
isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua), isIOS: /\(i[^;]+;( U;)? CPU.+Mac OS X/i.test(ua),
isIPad: /iPad/i.test(ua), isIPad: /iPad/i.test(ua),
isAndroidApp: /Android/i.test(ua) && getParam('version'), isAndroidApp: /Android/i.test(ua) && getParam('version'),
isIOSApp: /iPhone/i.test(ua) && getParam('version') isIOSApp: /iPhone/i.test(ua) && getParam('version')
} }
})() })()
const isLogin = (function () { const isLogin = (function () {
return jsCookie.get('uid') && jsCookie.get('token') return jsCookie.get('uid') && jsCookie.get('token')
})() })()
const dateCountDown = (later, earlier) => {
const d = differenceInDays(later, earlier)
const h = differenceInHours(later, earlier) % 24
const m = differenceInMinutes(later, earlier) % 60
const s = differenceInSeconds(later, earlier) % 60
return {
d,
h,
m,
s
}
}
export {default as http} from './http'
export {default as wxShare} from './wechat/share' export {
export {html, initCaptcha, validateTel, validateEmail, browser, isLogin} default as http
export {default as SendMessageToApp} from './app' }
from './http'
export {
default as wxShare
}
from './wechat/share'
export {
html,
initCaptcha,
validateTel,
validateEmail,
browser,
isLogin,
dateCountDown
}
export {
default as SendMessageToApp
}
from './app'
\ No newline at end of file
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