Commit 4334c1c1 by zhanghaozhe

Merge branch 'video'

# Conflicts:
#	src/common/Course/index.js
#	src/utils/index.js
parents 2150b3ce cecbef8b
...@@ -4,7 +4,7 @@ import {Link} from 'react-router-dom' ...@@ -4,7 +4,7 @@ import {Link} from 'react-router-dom'
const VList = (props) => { const VList = (props) => {
return ( return (
<li className='v-list-item' onClick={e=>props.handleClick(props.id)}> <li className='v-list-item' onClick={e => props.handleClick(props.id)}>
<div className="content"> <div className="content">
<div className="cover"> <div className="cover">
{props.status} {props.status}
......
.bargain { .bargain-func {
padding: 8px; padding: 8px;
border-top: 8px solid $bg_f5f5f5; border-top: 8px solid $bg_f5f5f5;
......
...@@ -14,7 +14,7 @@ class Bargain extends Component { ...@@ -14,7 +14,7 @@ class Bargain extends Component {
render() { render() {
return ( return (
<div className={'bargain'}> <div className={'bargain-func'}>
<BargainIntro <BargainIntro
onClick={this.toggleCover} onClick={this.toggleCover}
/> />
......
...@@ -7,13 +7,12 @@ import { Link } from 'react-router-dom' ...@@ -7,13 +7,12 @@ import { Link } from 'react-router-dom'
class Search extends PureComponent { class Search extends PureComponent {
constructor(props) {
super(props); state = {
this.state = { searchHistory: JSON.parse(localStorage.getItem('searchHistory')) || [],
history: JSON.parse(localStorage.getItem('history')) || [], hot_words: [],
hot_words: [], searchList: [],
searchList: [] value: ''
}
} }
async componentDidMount() { async componentDidMount() {
...@@ -25,26 +24,54 @@ class Search extends PureComponent { ...@@ -25,26 +24,54 @@ class Search extends PureComponent {
} }
} }
search = text => { clearHistory = () => {
localStorage.setItem('searchHistory', null)
this.setState({
searchHistory: []
})
}
handleChange = value => {
this.setState({value})
}
handleSearch = () => {
this.state.value && this.props.history.push(`/search-result?word=${encodeURIComponent(this.state.value)}`)
}
storeHistory = keyword => {
localStorage.setItem('searchHistory', JSON.stringify([...this.state.searchHistory, keyword]))
} }
render() { render() {
let querystring = this.props.location.query ? this.props.location.query.s : ''; const {searchHistory} = this.state
return ( return (
<div className="search-page"> <div className="search-page">
<SearchHead value={querystring} returnbtn={true}/> <SearchHead
searchHistory={this.state.searchHistory}
value={this.state.value}
handleChange={this.handleChange}
handleSearch={this.handleSearch}
/>
<div className="search-main"> <div className="search-main">
<div className="search-land search-history"> <div className="search-land">
<label> <div className='search-history'>
<span>最近搜索</span> <span>最近搜索</span>
<i className="iconfont iconiconfront-56"/> <i className="iconfont iconiconfront-56" onClick={this.clearHistory}/>
</label> </div>
<div className="search-tag"> <div className="search-tag">
{ {
this.state.history.length > 0 ? searchHistory.length > 0 ?
this.state.history.map((v, i) => { searchHistory.map((v, i) => {
return (<Tag key={i}>{v}</Tag>) return (
<Link
key={i}
to={`/search-result?word=${encodeURIComponent(v)}`}
>
<Tag>{v}</Tag>
</Link>
)
}) })
: <div style={{textAlign: 'center', padding: '20px'}}>暂无历史</div> : <div style={{textAlign: 'center', padding: '20px'}}>暂无历史</div>
} }
...@@ -59,7 +86,10 @@ class Search extends PureComponent { ...@@ -59,7 +86,10 @@ class Search extends PureComponent {
this.state['hot_words'].length > 0 ? this.state['hot_words'].length > 0 ?
this.state['hot_words'].map((v, i) => { this.state['hot_words'].map((v, i) => {
return ( return (
<Link key={i} to={`/search-result?word=${v}`}> <Link key={i}
to={`/search-result?word=${encodeURIComponent(v)}`}
onClick={this.storeHistory.bind(this, v)}
>
<Tag>{v}</Tag> <Tag>{v}</Tag>
</Link> </Link>
) )
......
.search-page{ .search-page {
.search-main{ .search-main {
background-color: #fff; background-color: #fff;
padding:10px; padding: 10px;
.search-land{
label{ .search-land {
margin-bottom:10px; .search-history {
margin-bottom: 10px;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
span{
font-size:16px; span {
font-size: 16px;
} }
img{
width:16px; img {
height:16px; width: 16px;
height: 16px;
display: block; display: block;
} }
} }
.search-tag{
.search-tag {
overflow: hidden; overflow: hidden;
} }
} }
.search-hot{
margin-top:10px; .search-hot {
margin-top: 10px;
} }
ul,li{
ul, li {
list-style: none; list-style: none;
padding:0; padding: 0;
margin:0; margin: 0;
} }
.list{
padding:10px 0; .list {
border-bottom:1px solid #eee; padding: 10px 0;
border-bottom: 1px solid #eee;
} }
.list:last-child{
border-bottom:0; .list:last-child {
border-bottom: 0;
} }
} }
.searct-lists{
padding:0 10px; .searct-lists {
padding: 0 10px;
} }
} }
\ No newline at end of file
import React, { Component } from "react";
import './recommendation.scss'
import { Course } from "@/common";
import { api, http } from "@/utils";
import { Toast } from 'antd-mobile'
import {withRouter} from 'react-router-dom'
class Recommendation extends Component {
state = {
courses: []
}
componentDidMount() {
http.get(`${api['search-api']}/search_hot_word`)
.then(res => {
if (res.data.errno === 0) {
this.setState({
courses: res.data.data.info.courses
})
} else {
Toast.info(res.data.msg)
}
})
}
handleClick = (id) => {
this.props.history.push(`/detail?id=${id}`)
}
render() {
const {courses} = this.state
return (
<div className="recommendation">
<div className="title">推荐课程</div>
<div className="courses">
{
courses.length > 0 &&
courses.map((item, index) => {
const Bottom = (
<div className='bottom'>
<span className='price'>{item['price1']}</span>
<span className='old-price'>{item['price0']}</span>
</div>
)
return (
<Course
key={item['course_id']}
id={item['course_id']}
img={item['image_name']}
title={item['course_title']}
bottom={Bottom}
handleClick={this.handleClick}
/>
)
})
}
</div>
</div>
)
}
}
export default withRouter(Recommendation)
.search-result {
.recommendation {
padding: 0 15px;
.title {
width: 100%;
font-size: 15px;
padding: 20px 0 5px;
text-align: center;
}
.courses {
display: flex;
flex-flow: wrap;
justify-content: space-between;
}
.bottom{
margin-top: 12px;
}
.price {
color: #FF2121;
font-size: 15px;
margin-right: 15px;
}
.old-price {
color: $color_999;
font-size: 11px;
text-decoration: line-through;
}
}
}
...@@ -3,7 +3,7 @@ import SearchHeader from './searchHead' ...@@ -3,7 +3,7 @@ import SearchHeader from './searchHead'
import VList from '@/common/VList' import VList from '@/common/VList'
import { http, api, getParam } from '@/utils' import { http, api, getParam } from '@/utils'
import './search-result.scss' import './search-result.scss'
import Recommendation from './recommendation'
const Bottom = ({item}) => { const Bottom = ({item}) => {
return ( return (
...@@ -17,55 +17,100 @@ const Bottom = ({item}) => { ...@@ -17,55 +17,100 @@ const Bottom = ({item}) => {
class SearchResult extends PureComponent { class SearchResult extends PureComponent {
state = { state = {
courseList: [] courseList: [],
value: '',
searchHistory: JSON.parse(localStorage.getItem('searchHistory')) || []
} }
componentDidMount() { componentDidMount() {
http.get(`${api['search-api']}/search/${encodeURIComponent(getParam('word'))}?type=course&page=1`) this.getCourses(getParam('word'))
}
getCourses = (word) => {
http.get(`${api['search-api']}/search/${word}?type=course&page=1`)
.then(res => { .then(res => {
const data = res.data const data = res.data
if (data.errno === 0) { if (data.errno === 0) {
this.setState({ this.setState({
courseList: data.data.info.search_data.course courseList: data.data.info['search_data'].course
}); });
} }
}) })
} }
handleClick = id => {
this.props.history.push(`/detail?id=${id}`)
}
handleSearch = () => {
this.state.value && this.getCourses(this.state.value)
}
handleChange = value => {
this.setState({value})
}
render() { render() {
const {courseList} = this.state const {courseList} = this.state
return ( return (
<div className='search-result'> <div className='search-result'>
<SearchHeader/> <SearchHeader
<ul> handleSearch={this.handleSearch}
{ value={this.state.value}
handleChange={this.handleChange}
courseList && courseList.length > 0 ? searchHistory={this.state.searchHistory}
courseList.map(item => { />
const Info = ( {
<div className="info">
<p className='title'>{item.course_title}</p> courseList && courseList.length > 0 ?
<p className='des'>{item.simpledescription}</p> <ul>
<Bottom {
item={item} courseList.map(item => {
const Info = (
<div className="info">
<p className='title'>{item.course_title}</p>
<p className='des'>{item.simpledescription}</p>
<Bottom
item={item}
/>
</div>
)
const status = (
(item['bargain_num'] || item['groupon_num']) ?
<div
className='status'>
{
item['bargain_num'] === 0 ? `砍价减${item['groupon_num']}元` : `拼团减${item['bargain_num']}元`
}
</div>
: null
)
return (
<VList img={item.image_name}
handleClick={this.handleClick}
key={item.course_id}
info={Info}
id={item['course_id']}
status={status}
/> />
</div> )
) })
return ( }
<VList img={item.image_name} </ul>
handleClick={this.handleClick} : <div className="empty">
key={item.course_id} 抱歉!没有搜到相关内容
info={Info}/> </div>
)
}) : null }
} <Recommendation/>
</ul>
</div> </div>
); );
} }
} }
export default SearchResult; export default SearchResult;
\ No newline at end of file
...@@ -3,9 +3,23 @@ ...@@ -3,9 +3,23 @@
list-style: none; list-style: none;
} }
.v-list-item{
.content{
width: 100%;
}
}
.info { .info {
display: flex; display: flex;
flex-wrap: wrap; flex-wrap: wrap;
width: 50%;
.title{
overflow: hidden;
white-space: nowrap;
text-overflow: ellipsis;
}
.des { .des {
font-size: $font_14; font-size: $font_14;
...@@ -25,8 +39,30 @@ ...@@ -25,8 +39,30 @@
color: $color_999; color: $color_999;
font-size: $font_12; font-size: $font_12;
} }
.bottom{
.bottom {
align-self: flex-end; align-self: flex-end;
} }
} }
.empty {
font-size: 12px;
color: $color_666;
padding: 30px 0;
text-align: center;
background-color: $bg_ccc;
}
.status {
width: 100%;
position: absolute;
bottom: -2px;
left: 0;
height: 24px;
text-align: center;
line-height: 24px;
font-size: 13px;
color: $white;
background-color: rgba(224, 46, 36, 0.6);
}
} }
\ No newline at end of file
...@@ -5,53 +5,46 @@ import { withRouter } from 'react-router-dom' ...@@ -5,53 +5,46 @@ import { withRouter } from 'react-router-dom'
import './search_header.scss' import './search_header.scss'
class SearchHead extends PureComponent { class SearchHead extends PureComponent {
constructor(props) {
super(props);
this.state = {
visible: false,
selected: '',
val: this.props.value || ''
}
}
// 返回某个页面 returnPage = () => {
returnPage() {
this.props.history.go(-1) this.props.history.go(-1)
} }
//组件装载完毕
componentDidMount() { componentDidMount() {
this.refs.search.focus(); this.refs.search.focus();
} }
search = () => {
this.storeKeyword()
this.props.handleSearch()
}
storeKeyword = () => {
let {searchHistory = [], value} = this.props
value && localStorage.setItem('searchHistory', JSON.stringify([...searchHistory, value]))
}
render() { render() {
return ( return (
<div className="search-head"> <div className="search-head">
<div className="left" onClick={() => { <div className="left" onClick={this.returnPage}>
// 返回某个页面
this.returnPage()
}}>
<i className="iconfont iconiconfront-68"/> <i className="iconfont iconiconfront-68"/>
</div> </div>
<div className="center"> <div className="center">
<SearchBar <SearchBar
value={this.state.val} value={this.props.value}
showCancelButton showCancelButton
cancelText={" "} cancelText={" "}
ref="search" ref="search"
focus={true} focus={true}
onChange={this.props.handleChange}
onChange={(val) => {
this.setState({val})
this.props.search.changeVal(val)
}}
placeholder="搜索课程"/> placeholder="搜索课程"/>
</div> </div>
<div className="right right-btn"> <div className="right right-btn" onClick={this.search}>
<div className="submit-btn" <div className="submit-btn">搜索
>搜索
</div> </div>
</div> </div>
</div> </div>
......
...@@ -16,12 +16,13 @@ class DatumCatalog extends Component { ...@@ -16,12 +16,13 @@ class DatumCatalog extends Component {
} }
render() { render() {
const {datum} = this.props
return ( return (
<div className='datum-catalog'> <div className='datum-catalog'>
<p className='prompt'>课程资料请到PC端播放页下载</p> <p className='prompt'>课程资料请到PC端播放页下载</p>
<Accordion> <Accordion>
{ {
this.props.datum.map((item, index) => { datum && datum.length && datum.map((item, index) => {
return ( return (
<Accordion.Panel header={item.dir_name} key={index}> <Accordion.Panel header={item.dir_name} key={index}>
{ {
......
import React, { Component } from 'react'; import React, { Component } from 'react';
import HeaderBar from '@/common/HeaderBar' import HeaderBar from '@/common/HeaderBar'
import './video.scss' import './video.scss'
import { NavLink, Route } from 'react-router-dom'; import { NavLink, Route, Redirect, Switch } from 'react-router-dom';
import { http, api } from '@/utils' import { http, api, getParam } from '@/utils'
import Recommendation from './recommendation' import Recommendation from './recommendation'
import VideoCatalog from './video-catalog' import VideoCatalog from './video-catalog'
import DatumCatalog from './datum-catalog' import DatumCatalog from './datum-catalog'
import { Toast } from 'antd-mobile'; import { Toast } from 'antd-mobile';
import videojs from 'video.js' import videojs from 'video.js'
import 'video.js/dist/video-js.min.css' import 'video.js/dist/video-js.min.css'
// import 'video.scss' import { Modal } from "antd-mobile";
let alert = Modal.alert
class Video extends Component { class Video extends Component {
video; video
player
courseID
state = { state = {
title: '视频', title: '视频',
courseId: 140, courseId: null,
video_catalog: [], video_catalog: [],
datum: [] datum: [],
currentVideoSrc: '',
activeIndex: 0,
isAuth: true,
course: null,
salePrice: null
} }
componentDidMount() { componentDidMount() {
this.courseID = getParam('id')
this.setState({
courseId: this.courseID
})
this.getVideoCatalog()
this.getDatumCatalog()
}
initializePlayer = () => {
window.HELP_IMPROVE_VIDEOJS = false; window.HELP_IMPROVE_VIDEOJS = false;
videojs(this.video, { this.player = videojs(this.video, {
controls: true, controls: true,
autoplay: true,
preload: 'auto', preload: 'auto',
bigPlayButton: true, bigPlayButton: true,
textTrackDisplay: false, textTrackDisplay: false,
posterImage: false, posterImage: false,
errorDisplay: false, errorDisplay: false
}, function () { })
this.log.debug() this.player.enableTouchActivity()
}
componentWillUnmount() {
if (this.player) {
this.player.dispose()
}
}
handleClick = index => {
if (this.hasAuth()) {
this.setPlayerSrc(this.state.video_catalog[index]['play_url'])
this.playVideo()
}
this.setState({
activeIndex: index
}) })
this.getVideoCatalog()
this.getDatumCatalog()
} }
getVideoCatalog = () => { getVideoCatalog = () => {
http.get(`${api.home}/m/course/play/40`) http.get(`${api.home}/m/course/play/${this.courseID}`)
.then(res => { .then(res => {
const data = res.data const data = res.data
if (data.code === 200) { if (data.code === 200) {
this.setState({ this.setState(
video_catalog: data.data.lessons state => ({
}) video_catalog: data.data['lessons'],
currentVideoSrc: data.data['lessons'][state.activeIndex]['play_url'],
course: data.data.course,
courseId: data.data.course['course_id']
}),
() => {
if (this.lessonAvailable()) {
if (this.hasAuth(this.state.activeIndex)) {
this.initializePlayer()
this.playWithAuth()
} else {
this.getCoursePrice();
}
} else {
alert('暂无视频', '', [{
text: 'OK',
onPress: () => {
this.props.history.push('/')
}
}])
}
}
)
} else { } else {
Toast.info(data.msg) Toast.info(data.msg)
} }
}) })
} }
setPlayerSrc = src => {
this.player.src({
src,
type: 'application/x-mpegURL'
})
}
playVideo = () => {
this.player.play()
}
getDatumCatalog() { getDatumCatalog() {
http.get(`${api.home}/m/course/data/40`) http.get(`${api.home}/m/course/data/${this.courseID}`)
.then(res => { .then(res => {
const data = res.data const data = res.data
if (data.code === 200) { if (data.code === 200) {
...@@ -76,16 +141,84 @@ class Video extends Component { ...@@ -76,16 +141,84 @@ class Video extends Component {
}) })
} }
lessonAvailable = () => {
const {video_catalog, activeIndex} = this.state
return video_catalog[activeIndex]['video_size'] !== 0
}
getCoursePrice = () => {
http.get(`${api.home}/sys/course/price/${this.state.courseId}`)
.then(res => {
const {data} = res
if (data.code === 200) {
this.setState({
salePrice: data.data['sale_price']
})
}
})
}
playWithAuth = () => {
const {video_catalog, activeIndex} = this.state
if (this.hasAuth()) {
this.setPlayerSrc(video_catalog[activeIndex]['play_url'])
}
}
hasAuth = (index) => {
const {course, video_catalog, activeIndex} = this.state
let lesson = video_catalog[activeIndex]
if (!lesson['is_free']) {
if (course['is_audition']) {
this.setState({
isAuth: true
})
return true
} else {
if (lesson['video_auth']) {
this.setState({
isAuth: true
})
return true
}
this.setState({
isAuth: false
})
return false
}
}
this.setState({
isAuth: true
})
return true
}
render() { render() {
let {match} = this.props let {match} = this.props
const {video_catalog, activeIndex, isAuth, salePrice} = this.state
return ( return (
<div className='play'> <div className='play'>
<HeaderBar title={this.state.title}/> <HeaderBar title={this.state.title}/>
<div className="video"> <div className="video">
<video className={'video-js'} ref={el => this.video = el}> <video className={'video-js'} ref={el => this.video = el}>
<source src='/v2/ts/40/191/175d6e5a.m3u8' type='application/x-mpegURL'/> <source src={'/'} type='application/x-mpegURL'/>
</video> </video>
{
!isAuth && (
<div className="purchase-box">
<div className='hint'>您尚未购买该课时,请购买后学习。</div>
<div className='btns'>
<button type='button' className='purchase-class'>¥{salePrice} 购买课程</button>
<button type='button'
className='purchase-episode'>¥{video_catalog.length && video_catalog[activeIndex]['class_price']} 购买单集
</button>
</div>
</div>
)
}
</div> </div>
<div className='tab'> <div className='tab'>
<div> <div>
...@@ -101,15 +234,23 @@ class Video extends Component { ...@@ -101,15 +234,23 @@ class Video extends Component {
>资料</NavLink> >资料</NavLink>
</div> </div>
</div> </div>
{/*<Route path={`${match.path}/video`} render={props => { <Switch>
return <VideoCatalog videoCatalog={this.state.video_catalog} {...props}/> <Redirect exact from={'/play'} to={'/play/video'}/>
}}/> <Route path={`${match.path}/video`} render={props => {
<Route path={`${match.path}/datum`} render={props => { return <VideoCatalog
return <DatumCatalog {...props} datum={this.state.datum}/> activeIndex={this.state.activeIndex}
}}/> handleClick={this.handleClick}
videoCatalog={this.state.video_catalog}
{...props}/>
}}/>
<Route path={`${match.path}/datum`} render={props => {
return <DatumCatalog {...props} datum={this.state.datum}/>
}}/>
</Switch>
<Route render={props => { <Route render={props => {
return <Recommendation {...props} courseId={this.state.courseId}/> return this.state.courseId ? <Recommendation {...props} courseId={this.state.courseId}/>
}}/>*/} : null
}}/>
</div> </div>
); );
} }
......
import React, { Component } from 'react'; import React, { PureComponent } from 'react';
import './recommendation.scss' import './recommendation.scss'
import { http, api } from '@/utils' import { http, api } from '@/utils'
import { Toast } from "antd-mobile"; import { Toast } from "antd-mobile";
...@@ -17,12 +17,14 @@ const Bottom = ({item}) => { ...@@ -17,12 +17,14 @@ const Bottom = ({item}) => {
class Recommendation extends Component { class Recommendation extends PureComponent {
state = { state = {
num: 10, num: 10,
list: [] list: [],
courseId: null
} }
componentDidMount() { componentDidMount() {
http.get(`${api.home}/m/play/recommend_course/${this.props.courseId}?num=${this.state.num}`) http.get(`${api.home}/m/play/recommend_course/${this.props.courseId}?num=${this.state.num}`)
.then(res => { .then(res => {
...@@ -39,6 +41,7 @@ class Recommendation extends Component { ...@@ -39,6 +41,7 @@ class Recommendation extends Component {
}) })
} }
handleClick = id => { handleClick = id => {
console.log(id) console.log(id)
} }
......
...@@ -5,14 +5,21 @@ import classnames from 'classnames' ...@@ -5,14 +5,21 @@ import classnames from 'classnames'
class VideoCatalog extends Component { class VideoCatalog extends Component {
handleClick = (i) => {
this.props.handleClick(i)
}
render() { render() {
return ( return (
<div className='video-catalog'> <div className='video-catalog'>
<ul> <ul>
{ {
this.props.videoCatalog.map(item => { this.props.videoCatalog.map((item, index) => {
return ( return (
<li key={item.id}> <li key={item.id}
className={classnames({active: this.props.activeIndex === index})}
onClick={this.handleClick.bind(this, index)}
>
<span className="title">{item.name}</span> <span className="title">{item.name}</span>
<span className='duration'>{item.duration}</span> <span className='duration'>{item.duration}</span>
<i className={classnames(`iconfont`, <i className={classnames(`iconfont`,
......
...@@ -5,6 +5,66 @@ $tabHeight: 44px; ...@@ -5,6 +5,66 @@ $tabHeight: 44px;
width: 100%; width: 100%;
height: 215px; height: 215px;
background-color: $black; background-color: $black;
position: relative;
.video-js {
width: 100%;
height: 100%;
.vjs-big-play-button {
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.purchase-box {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
flex-flow: column;
justify-content: center;
align-items: center;
.hint {
font-size: $font_14;
color: $white;
margin-bottom: 20px;
}
@mixin button{
display: block;
-webkit-appearance: none;
outline: none;
border: none;
background-color: transparent;
border-radius: 5px;
line-height: 30px;
font-size: 13px;
padding: 0 9px;
}
.btns {
width: 100%;
padding: 0 60px;
display: flex;
justify-content: space-around;
}
.purchase-class{
@include button;
background-color: $white;
color: $color_FF4000;
}
.purchase-episode{
@include button;
background-color: $bg_FF4000;
color: $white;
}
}
video { video {
width: 100%; width: 100%;
...@@ -35,7 +95,10 @@ $tabHeight: 44px; ...@@ -35,7 +95,10 @@ $tabHeight: 44px;
.active { .active {
color: $active; color: $active;
border-bottom: 1px solid $active;
.iconiconfront-74 {
color: $color_555;
}
} }
} }
\ No newline at end of file
export { default as http } from './http' export { default as http } from './http'
export { default as api } from './api' export { default as api } from './api'
export { html, initCaptcha, validateTel, validateEmail } export { html, initCaptcha, validateTel, validateEmail,browser }
export const getParam = (key, str) => { export const getParam = (key, str) => {
...@@ -78,3 +78,13 @@ function validateEmail(email) { ...@@ -78,3 +78,13 @@ 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 ua = navigator.userAgent
return {
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)
}
})()
\ No newline at end of file
...@@ -14,7 +14,7 @@ const config = { ...@@ -14,7 +14,7 @@ const config = {
v2: { v2: {
development: '/v2', development: '/v2',
test: 'https://v2.julyedu.com', test: 'https://v2.julyedu.com',
production: 'https://search.julyedu.com', production: 'https://v2.julyedu.com',
proxy: { proxy: {
secure: false, secure: false,
} }
......
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