Commit b1a33eac by zhanghaozhe

Merge branch 'master' into coupons

parents 5847e286 9000a6bc
import React from 'react'
import './index.scss'
const HeaderBar = (props) => {
return (
<div className="detail-header">
<i className={'iconfont iconiconfront-68 return'}></i>
<span className='herder'>{props.title}</span>
<i className={'iconfont icongouwuche shopping-cart'}></i>
</div>
);
};
export default HeaderBar;
.detail-header {
height: 44px;
line-height: 44px;
padding: 0 15px;
background-color: $bg_f7f9fc;
display: flex;
justify-content: space-between;
.shopping-cart, .return {
font-size: 18px !important;
}
.herder {
font-size: 16px;
color: $color_202426;
}
}
\ No newline at end of file
import React, {Component} from 'react'
import {SearchBar} from 'antd-mobile'
import './index.scss'
class HeaderBar extends Component {
toSearch() {
window.location.href ='/search'
}
return() {
window.location.href ='/'
}
render() {
return (
<div className='preferential'>
<div className="search-nav">
<i className={'iconfont iconiconfront-68 return'} onClick={this.return.bind(this)}></i>
<SearchBar
placeholder="搜索课程"
cancelText={" "}
onFocus={this.toSearch.bind(this)}
showCancelButton={false}
/>
<i className={'iconfont icongouwuche shopping-cart'}></i>
</div>
</div>
)
}
}
export default HeaderBar
.search-nav {
height: 44px;
line-height: 44px;
padding: 0 15px;
background-color: $bg_f7f9fc;
display: flex;
justify-content: space-between;
.am-search {
width: 81%;
background-color: $bg_f7f9fc;
}
.am-search-input, .am-search-synthetic-ph, .am-search-value {
text-align: left;
padding-left: 15px;
height: 26px;
line-height: 26px;
}
.am-search-input {
background-color: $bg_EBEFF5;
border-radius: 13px;
}
.shopping-cart, .return {
font-size: 18px !important;
}
}
\ No newline at end of file
import React, { Component } from 'react'
import React, { PureComponent } from 'react'
import './tag.scss'
export default class Tag extends Component {
export default class Tag extends PureComponent {
render() {
return (
<span className="tag" {...this.props}>
......
import React from 'react'
const ToApp = (props) => {
return (
<div className={props.className} onClick={props.toApp}>APP打开</div>
);
};
export default ToApp;
......@@ -2,7 +2,6 @@ import React from 'react';
import './index.scss'
const VList = (props) => {
console.log(props)
return (
<li className='v-list-item' onClick={e=>props.handleClick(props.id)}>
<div className="content">
......
......@@ -2,3 +2,5 @@ export { default as VList } from './VList'
export { default as Course } from './Course' // 课程状态(试听 正在直播)+封面+标题+ 详情
export { default as Tag } from './CategoryTag'
export { default as OrderItem } from './OrderList'
export { default as HeaderBar } from './HeaderBar'
export { default as ToApp } from './ToApp'
src/components/Index/image/freeclass_icon.png

2.95 KB | W: | H:

src/components/Index/image/freeclass_icon.png

1.54 KB | W: | H:

src/components/Index/image/freeclass_icon.png
src/components/Index/image/freeclass_icon.png
src/components/Index/image/freeclass_icon.png
src/components/Index/image/freeclass_icon.png
  • 2-up
  • Swipe
  • Onion skin
src/components/Index/image/jingpin_icon.png

2.64 KB | W: | H:

src/components/Index/image/jingpin_icon.png

1.47 KB | W: | H:

src/components/Index/image/jingpin_icon.png
src/components/Index/image/jingpin_icon.png
src/components/Index/image/jingpin_icon.png
src/components/Index/image/jingpin_icon.png
  • 2-up
  • Swipe
  • Onion skin
src/components/Index/image/mryt_icon.png

2.74 KB | W: | H:

src/components/Index/image/mryt_icon.png

1.51 KB | W: | H:

src/components/Index/image/mryt_icon.png
src/components/Index/image/mryt_icon.png
src/components/Index/image/mryt_icon.png
src/components/Index/image/mryt_icon.png
  • 2-up
  • Swipe
  • Onion skin
src/components/Index/image/qynx_icon.png

2.63 KB | W: | H:

src/components/Index/image/qynx_icon.png

1.61 KB | W: | H:

src/components/Index/image/qynx_icon.png
src/components/Index/image/qynx_icon.png
src/components/Index/image/qynx_icon.png
src/components/Index/image/qynx_icon.png
  • 2-up
  • Swipe
  • Onion skin
src/components/Index/image/zjxj_icon.png

2.62 KB | W: | H:

src/components/Index/image/zjxj_icon.png

1.59 KB | W: | H:

src/components/Index/image/zjxj_icon.png
src/components/Index/image/zjxj_icon.png
src/components/Index/image/zjxj_icon.png
src/components/Index/image/zjxj_icon.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -5,7 +5,7 @@ import {WithTab} from '@/HOCs'
import Swiper from 'react-mobile-swiper'
import createStyle from './createStyle'
import LazyLoad from 'react-lazy-load'
import {api} from '@/utils'
import {http, api} from '@/utils'
import LiveRoom from './liveRoom'
......@@ -53,7 +53,7 @@ class Index extends Component {
componentDidMount() {
// 首页课程
api.get('/m/home').then((res) => {
http.get(`${api.home}/m/home`).then((res) => {
if (res.data.code === 200) {
this.setState({
banner: res.data.data.banner,
......
import React, {Component} from 'react';
import './index.scss';
import {api} from '@/utils'
import {http, api} from '@/utils'
class LiveRoom extends Component {
constructor(props) {
......@@ -16,18 +16,18 @@ class LiveRoom extends Component {
componentDidMount() {
// this.livePrepare(this.props.roomId,'',2,'')
// this.livePrepare(this.props.roomId,'',2,'')
}
// 直播间预约接口公共方法
livePrepare=(room_id,type,source,mobile)=>{
livePrepare = (room_id, type, source, mobile) => {
let data = {
room_id: room_id, // 直播间id
type: type, // 1-为微信服务通知预约 2-为手机号预约
source: source, // 1-为微信内置浏览器 2-为wap(微信外
mobile: mobile // 手机号 当type为2时,该参数为必填
};
api.post('/m/live/prepare',data).then((res) => {
http.post(`${api.home}/m/live/prepare`, data).then((res) => {
/* status 0表示预约成功
1表示预约失败
2表示未关注服务号
......@@ -35,12 +35,12 @@ class LiveRoom extends Component {
4表示手机号不能为空
*/
if (res.data.code === 200) {
if (res.data.data.status === 0){
alert(res.data.data.msg)
this.setState(status => ({
success: true,
toSubscribe: false
}));
if (res.data.data.status === 0) {
alert(res.data.data.msg)
this.setState(status => ({
success: true,
toSubscribe: false
}));
// if (type === 1){
// this.setState(status => ({
......@@ -52,11 +52,11 @@ class LiveRoom extends Component {
// success: true,
// toSubscribe: false
// }));
// }
// }
} else if (res.data.data.status === 1){
} else if (res.data.data.status === 1) {
alert(res.data.data.msg)
} else if (res.data.data.status === 2){
} else if (res.data.data.status === 2) {
alert(res.data.data.msg)
this.setState(status => ({
toSubscribe: true,
......@@ -64,13 +64,13 @@ class LiveRoom extends Component {
isfollow: true
}));
} else if (res.data.data.status === 3){
} else if (res.data.data.status === 3) {
alert(res.data.data.msg)
this.setState(status => ({
issubscribe: 1,
}));
} else if (res.data.data.status === 4){
} else if (res.data.data.status === 4) {
alert(res.data.data.msg)
} else {
alert(res.data.data.msg)
......@@ -84,25 +84,30 @@ class LiveRoom extends Component {
}
})
}
// 关闭弹窗
liveColse() {
this.props.colseBox(false);
}
// 点击预约
toSubscribe() {
this.props.colseBox(false);
this.livePrepare(this.props.roomId,'',2,'')
this.livePrepare(this.props.roomId, '', 2, '')
}
// 手机号预约
iphoneStep() {
this.setState(status => ({
step: 1
}));
}
// 服务号预约
serverStep() {
this.livePrepare(this.props.roomId,1,2,'')
this.livePrepare(this.props.roomId, 1, 2, '')
}
// 最后提交
submit() {
if (this.state.step === 1) {
......@@ -112,6 +117,7 @@ class LiveRoom extends Component {
this.livePrepare(this.props.roomId, 1, 1, '')
}
}
// 取消预约 关闭弹窗
subscribeColse() {
this.setState(status => ({
......
import React, {Component} from 'react';
import {VList} from '../../common';
import {Tabs, WhiteSpace, SearchBar} from 'antd-mobile';
import {Tabs, WhiteSpace} from 'antd-mobile';
import './courselist.scss';
import HeaderSearch from '../../common/HeaderSearch/index'
import {http, api, getParam} from "@/utils";
class Classify extends Component {
constructor(props) {
super(props)
this.handleClick = this.handleClick.bind(this)
this.ontabclick = this.ontabclick.bind(this)
this.state = {
ispull: false,
display: 'none',
arr: [{basics: []}, {advanced: []}],
allClass: [],
data: [],
activeTab: decodeURIComponent(getParam('name'))
}
}
handleClick() {
console.log(1);
componentDidMount() {
this.getTabs()
this.getList()
}
ontabclick(tab, index) {
console.log(tab, index)
this.setState(status => ({
data: status.dataList,
}));
// 获取tabs接口
getTabs = () => {
let data = 0
http.get(`${api.home}/m/course/classify/${data}`,)
.then((res) => {
const _this = this
if (res.data.code === 200) {
if (res.data.data.common.length > 0) {
let arr = ['basics', 'advanced']
let arr2 = [{basics: []}, {advanced: []}]
let arr3 = []
arr.forEach(function (item, index) {
arr2[item] = res.data.data.common[index]
res.data.data.common[index].list.forEach(function (item, index) {
arr3.push({'title': item.c_name, 'id': item.c_id})
})
})
_this.setState({
arr: arr2,
allClass: arr3
})
}
}
})
.catch(err => {
console.log(err)
})
}
pulldown() {
this.setState(status => ({
ispull: !status.ispull,
display: status.ispull ? 'none' : 'block'
}));
// 获取课程接口
getList = () => {
http.get(`${api.home}/m/course/list/${getParam('id')}`,).then((res) => {
if (res.data.code === 200) {
this.setState(status => ({
data: res.data.data,
}));
}
})
}
labelclick(name) {
console.log(name)
this.setState(status => ({
ispull: !status.ispull,
display: status.ispull ? 'none' : 'block'
}));
// 点击课程
handleClick = (courseId) => {
console.log(courseId)
}
toSearch() {
window.location.href = '/search'
// 点击横向滚动tab查询
ontabclick = (tab) => {
this.props.history.push(`/courselist?id=${tab.id}&name=${tab.title}`)
this.getList()
this.setState({
activeTab: decodeURIComponent(getParam('name'))
});
}
return() {
window.location.href = '/classify'
// 上下展示
pulldown = () => {
this.setState(status => ({
ispull: !status.ispull,
display: status.ispull ? 'none' : 'block'
}));
}
state = {
ispull: false,
display: 'none',
mockData: [
{
title: '三月面试求职三月面试求职三月面试求职',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒6',
time: '03月12日',
record: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒',
isbuy: 1,
price0: 100,
price1: 100
},
{
title: '三月面试求职三月面试求职三月面试求职',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒6',
time: '03月12日',
record: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒',
isbuy: 1,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
],
data: [
{
title: '三月面试求职三月面试求职三月面试求职',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒6',
time: '03月12日',
record: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒',
isbuy: 1,
price0: 100,
price1: 100
},
{
title: '三月面试求职三月面试求职三月面试求职',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒6',
time: '03月12日',
record: '学习到第2课2三月面试求职班三月面试求职班三月面试求职班分33秒',
isbuy: 1,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
{
title: '三月面试求职班',
imgUrl: 'https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg',
contact: 'QQ群:449141326',
time: '03月12日',
record: '学习到第2课2分33秒',
isbuy: 0,
price0: 100,
price1: 100
},
],
dataList: [
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': 'Spark大数据',
'teacher': 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': '机器学习',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': 'Linux',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': '数学',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 1,
'price0': 200,
'price1': 2000
}
]
// 弹窗里面tab点击查询
labelclick = (item) => {
this.props.history.push(`/courselist?id=${item.c_id}&name=${item.c_name}`)
this.getList()
this.setState(status => ({
ispull: !status.ispull,
display: status.ispull ? 'none' : 'block',
activeTab: decodeURIComponent(getParam('name'))
}))
}
render() {
const tabs = [
{title: '机器学习'},
{title: '数学'},
{title: 'Linux'},
{title: '深度学习'},
{title: '数据结构'},
{title: 'Linux'},
{title: '数据结构'},
{title: '数学'},
];
const bottom = (
<i className={'iconfont iconiconfront-69 pull-down'}></i>
)
......@@ -350,44 +106,36 @@ class Classify extends Component {
<i className={'iconfont iconiconfront-71 pull-down'}></i>
)
let page = this.state.allClass.findIndex((item) => item.title === this.state.activeTab)
return (
<div className='class-child'>
<div className="search-nav">
<i className={'iconfont iconiconfront-68 return'} onClick={this.return.bind(this)}></i>
<SearchBar
placeholder="搜索课程"
cancelText={" "}
onFocus={this.toSearch.bind(this)}
showCancelButton={false}
/>
<i className={'iconfont icongouwuche shopping-cart'}></i>
</div>
<HeaderSearch></HeaderSearch>
<div className='class-content'>
<WhiteSpace/>
<div onClick={this.pulldown.bind(this)}>
{this.state.ispull ? top : bottom}
</div>
<Tabs
tabs={tabs}
tabs={this.state.allClass}
animated={false}
onChange={(tab, index) => this.ontabclick(tab, index)}
onTabClick={(tab, index) => this.ontabclick(tab, index)}
page={page}
onChange={(tab) => this.ontabclick(tab)}
>
<div className='tabs'>
<ul>
{this.state.data.map((item, index) => {
{this.state.data && this.state.data.length > 0 && this.state.data.map((item, index) => {
const Info = (
<div className="info">
<p className='title'>{item.title}</p>
<p className='contact text-overflow-2'>{item.contact}</p>
<p className='title'>{item.course_title}</p>
<p className='contact text-overflow-2'>{item.desc}</p>
<div className='des'>
{item.isbuy === 0 && <p className="course-price">
{item.is_buy === 0 && <p className="course-price">
<span className="new">¥{item.price0}</span>
<span className="old">¥{item.price1}</span>
</p>
}
{item.isbuy === 1 &&
{item.is_buy === 1 &&
<a href="/#" className="isbuy">已购买</a>
}
</div>
......@@ -395,14 +143,17 @@ class Classify extends Component {
)
const status = (
<div>
{item.isbuy === 1 &&
<p className='course-status'>拼团减100</p>
{item.bargain_num === 0 && item.groupon_num !== 0 &&
<p className='course-status'>拼团减{item.groupon_num}</p>
}
{item.bargain_num !== 0 && item.groupon_num === 0 &&
<p className='course-status'>砍价减{item.bargain_num}</p>
}
</div>
)
return (
<VList handleClick={this.handleClick} key={index} status={status}
img={item.image_name} id={item.course_id}
info={Info}></VList>
)
})}
......@@ -412,10 +163,15 @@ class Classify extends Component {
<WhiteSpace/>
</div>
<div className='mbc-box' style={{display: this.state.display}}>
<div className="tabcontent">
<ClassCourse data={this.state.dataList} title={'基础入门'} onclick={this.labelclick.bind(this)}/>
<ClassCourse data={this.state.dataList} title={'进阶提高'} onclick={this.labelclick.bind(this)}/>
</div>
{
this.state.arr.basics &&
<div className="tabcontent">
<ClassCourse activeTab={this.state.activeTab} data={this.state.arr.basics.list}
title={this.state.arr.basics.name} labelclick={this.labelclick}/>
<ClassCourse activeTab={this.state.activeTab} data={this.state.arr.advanced.list}
title={this.state.arr.advanced.name} labelclick={this.labelclick}/>
</div>
}
</div>
</div>
......@@ -424,16 +180,16 @@ class Classify extends Component {
}
function ClassCourse({data, title, onclick}) {
function ClassCourse(props) {
return (
<div className="class-course">
<p className='course-items-title'>{title}</p>
<p className='course-items-title'>{props.title}</p>
<div className='items-box'>
{
data.map((item, index) => {
props.data && props.data.length > 0 && props.data.map((item, index) => {
return (
<span key={index} onClick={onclick}
className='item-label'>{item.title}</span>
<span className={props.activeTab === item.c_name ? 'active-label' : 'item-label'}
key={index} onClick={e => props.labelclick(item)}>{item.c_name}</span>
)
})
}
......
.class-child {
.search-nav {
height: 44px;
line-height: 44px;
padding: 0 15px;
background-color: $bg_f7f9fc;
display: flex;
justify-content: space-between;
.am-search {
width: 81%;
background-color: $bg_f7f9fc;
}
.am-search-input,.am-search-synthetic-ph,.am-search-value{
text-align: left;
padding-left: 15px;
height: 26px;
line-height: 26px;
}
.am-search-input {
background-color: $bg_EBEFF5;
border-radius: 13px;
}
.shopping-cart,.return {
font-size: 18px !important;
}
}
.class-content {
padding: 0 12px;
......@@ -111,6 +82,9 @@
display: flex;
margin-top: 10px;
margin-bottom: 50px;
ul {
width: 100%;
}
}
.pull-down {
......@@ -201,6 +175,18 @@
margin-top: 15px;
margin-bottom: -5px;
}
.active-label {
display: inline-block;
width: 30.5%;
height: 30px;
line-height: 30px;
text-align: center;
background-color: $bg_active;
border-radius: 15px;
margin-top: 15px;
margin-bottom: -5px;
color: $white;
}
}
}
......
import React, {Component} from 'react';
import {WithTab} from '@/HOCs'
import './index.scss';
import {http, api} from "@/utils";
import { Link } from 'react-router-dom'
class Classify extends Component {
state = {
dataList: [
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': 'Spark大数据',
'teacher': 'wwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': '机器学习',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': 'Linux',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 0,
'price0': 100,
'price1': 1000
},
{
'src': 'http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png',
'title': '数学',
'teacher': 'wwwwww',
'time': '2343234',
'isbuy': 1,
'price0': 200,
'price1': 2000
constructor(props) {
super(props)
this.state = {
camp: [],
employment: [],
basics: [],
advanced: [],
special: []
}
}
componentDidMount() {
let data = 1
http.get(`${api.home}/m/course/classify/${data}`,).then((res) => {
if (res.data.code === 200) {
if (res.data.data.common.length > 0) {
this.setState({
basics: res.data.data.common[0],
advanced: res.data.data.common[1],
})
}
if (res.data.data.special.length > 0) {
this.setState({
camp: res.data.data.special[0],
employment: res.data.data.special[1],
special: res.data.data.special[2],
})
}
}
]
})
}
render() {
return (
<div className='class-box'>
<div className="class-title">分类</div>
<ClassCourseBox data={this.state.dataList} title={'集训营'} type={1}/>
<ClassCourseBox data={this.state.dataList} title={'就业班'} type={1}/>
<ClassCourseBox data={this.state.dataList} title={'基础入门'} type={2}/>
<ClassCourseBox data={this.state.dataList} title={'进阶提高'} type={2}/>
<ClassCourseBox data={this.state.camp.list} title={this.state.camp.name} type={1} />
<ClassCourseBox data={this.state.employment.list} title={this.state.employment.name} type={1}/>
<ClassCourseBox data={this.state.basics.list} title={this.state.basics.name} type={2}/>
<ClassCourseBox data={this.state.advanced.list} title={this.state.advanced.name} type={2}/>
<div className="vip">
<a href="/#">
<img src="http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png" alt=""/>
</a>
{this.state.special.list && this.state.special.list.length > 0 && this.state.special.list.map((item, index) => {
return (
<a key={index} href='/detail'>
<img src={item.course_img} alt=""/>
</a>
)
})
}
</div>
</div>
)
......@@ -62,14 +64,12 @@ class Classify extends Component {
}
function ClassCourseA({data}) {
return(
return (
<div className='items-box'>
{
data.map((item,index)=>{
data && data.length > 0 && data.map((item, index) => {
return (
<a href="/courselist" key={index} className='item-banner'><img
src={item.src}
alt=""/></a>
<a href={`/detail?id=${item.course_id}`} key={index} className='item-banner'><img src={item.course_img} alt=""/></a>
)
})
}
......@@ -77,13 +77,15 @@ function ClassCourseA({data}) {
)
}
function ClassCourseB({data}) {
return(
function ClassCourseB(props) {
return (
<div className='items-box'>
{
data.map((item,index)=>{
props.data && props.data.length > 0 && props.data.map((item, index) => {
return (
<a href="/#" key={index} className='item-label'>{item.title}</a>
<Link to={`/courselist?id=${item.c_id}&name=${item.c_name}`} key={index} className='item-label'>
{item.c_name}
</Link>
)
})
}
......@@ -91,19 +93,21 @@ function ClassCourseB({data}) {
)
}
function ClassCourseBox({data,title,type}) {
return(
function ClassCourseBox(props) {
return (
<div className="class-course">
<p className='course-items-title'><img
src="http://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/home/5afe433d01.png"
alt=""/>{title}</p>
{ type === 1 &&
<ClassCourseA data={data}/>
<p className='course-items-title'>
<img src={require('./image/tips.png')} alt=""/>
{props.title}
</p>
{props.type === 1 &&
<ClassCourseA data={props.data}/>
}
{ type === 2 &&
<ClassCourseB data={data}/>
{props.type === 2 &&
<ClassCourseB data={props.data}/>
}
</div>
)
}
export default WithTab(Classify);
import React, {Component} from 'react'
import './index.scss'
class Audition extends Component {
constructor(props) {
super(props);
}
colse = () => {
this.props.boxHide(false);
}
render() {
return (
<div>
{
this.props.auditionBox &&
<div className='popup-box'>
<div className='content audition-box'>
<p className='audition-header'>当前页面不支持试听</p>
<p className='audition-dec'>请前往APP试听</p>
<div className='btn btn-18B4ED'>立即前往</div>
</div>
<i onClick={this.colse} className={'iconfont iconiconfront-2 close'}></i>
</div>
}
</div>
);
}
}
export default Audition;
.popup-box {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .6);
z-index: 1;
.content {
width: 300px;
position: relative;
background-color: $white;
padding-top: 20px;
border-radius: 3px;
}
.close {
color: #fff;
font-size: 22px;
position: relative;
left: 50%;
margin-left: -11px;
}
.btn {
position: absolute;
bottom: 24px;
left: 83px;
width: 135px;
height: 30px;
border-radius: 3px;
font-size: 16px;
color: $white;
text-align: center;
line-height: 30px;
}
.btn-18B4ED {
background-color: $bg_18B4ED;
}
.btn-FF4000 {
background-color: $bg_FF4000;
}
.header {
color: $active;
height: 24px;
line-height: 24px;
text-align: center;
i {
font-size: 24px;
}
span {
font-size: 18px;
margin-left: 10px;
vertical-align: text-bottom;
}
}
.audition-box {
height: 144px;
text-align: center;
margin: 212px auto 22px auto;
.audition-header {
font-size: 16px;
color: $color_333;
}
.audition-dec {
font-size: 14px;
color: $color_666;
margin-top: 10px;
}
}
}
import React, {Component} from 'react';
import {Tabs, WhiteSpace} from 'antd-mobile';
import './index.scss';
import React, {Component} from 'react'
import './index.scss'
import Bargain from './bargain'
import OutLine from './outline'
import {HeaderBar, ToApp} from '../../common'
import ShareRank from "./shareRank"
import Audition from "./audition"
import Single from "./single"
class Detail extends Component {
state = {
isbuy: 0,
isvip: 0,
isshow: false,
status: 0,
stage_info: [
{
"stage_name": "预习阶段 机器学习中的数学基础",
"lesson": [
{
"is_video": 0,
"name": "微积分",
"video_id": 1170,
"point": [
{
"name": "微积分的基本概念",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 2,
"name": "概率论",
"video_id": 1171,
"point": [
{
"name": "概率论简介",
"type": 1
}
],
"class_price": 22.99,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 3,
"name": "线性代数",
"video_id": 1172,
"point": [
{
"name": "线性代数基础",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 4,
"name": "凸优化",
"video_id": 1173,
"point": [
{
"name": "凸优化简介",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第一阶段 掌握基本模型 打开ML大门",
"lesson": [
{
"is_video": 5,
"name": "第1课 回归问题与应用",
"video_id": 1118,
"point": [
{
"name": "线性回归",
"type": 1
},
{
"name": "logistic回归",
"type": 1
},
{
"name": "梯度下降",
"type": 1
},
{
"name": "实际工程海量数据下的logistic回归使用",
"type": 1
},
{
"name": "分布拟合与回归、用LR分类与概率预测",
"type": 2
},
{
"name": "用LR完成Kaggle比赛迈开第一步",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 6,
"name": "第2课 决策树与树集成模型",
"video_id": 1119,
"point": [
{
"name": "不同类型的分类树模型",
"type": 1
},
{
"name": "决策树回归",
"type": 1
},
{
"name": "树模型过拟合与优化",
"type": 1
},
{
"name": "使用随机森林进行数据分类",
"type": 1
},
{
"name": "Bagging",
"type": 1
},
{
"name": "随机森林",
"type": 1
},
{
"name": "信用卡欺诈检测",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第3课 SVM",
"video_id": 1120,
"point": [
{
"name": "线性可分支持向量机、线性支持向量机",
"type": 1
},
{
"name": "非线性支持向量机",
"type": 1
},
{
"name": "SMO",
"type": 1
},
{
"name": "使用SVM进行数据分类",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第4课 最大熵与EM算法(上)",
"video_id": 1121,
"point": [
{
"name": "熵、相对熵、信息增益",
"type": 1
},
{
"name": "最大熵模型、IIS、GMM",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第二阶段 重中之重 特征工程",
"lesson": [
{
"is_video": 1,
"name": "第5课 机器学习中的特征工程处理",
"video_id": 1122,
"point": [
{
"name": "数据清洗、异常点处理",
"type": 1
},
{
"name": "特征抽取、选择与组合策略",
"type": 1
},
{
"name": "特征处理与特征选择模板",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第6课 多算法组合与模型最优化",
"video_id": 1123,
"point": [
{
"name": "机器学习问题场景分析、算法选择",
"type": 1
},
{
"name": "模型构建、模型性能分析与优化策略",
"type": 1
},
{
"name": "构建模型组合策略工具与模板",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第三阶段 工业实战 在实战中掌握一切",
"lesson": [
{
"is_video": 1,
"name": "第7课 sklearn与机器学习实战",
"video_id": 1124,
"point": [
{
"name": "sklearn板块介绍",
"type": 1
},
{
"name": "sklearn完成数据预处理与特征工程",
"type": 1
},
{
"name": "建模流水线搭建",
"type": 1
},
{
"name": "经典Titanic案例,商品销量预测案例等",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第8课 高级工具xgboost/lightGBM与建模实战",
"video_id": 1125,
"point": [
{
"name": "xgboost使用方法与高级功能",
"type": 1
},
{
"name": "lightGBM使用方法与高级功能",
"type": 1
},
{
"name": " Titanic与商品销量预测进阶,Kaggle案例实战",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第9课 电商推荐系统",
"video_id": 1126,
"point": [
{
"name": "推荐系统与评估",
"type": 1
},
{
"name": "基于内容的推荐",
"type": 1
},
{
"name": "基于近邻的推荐--协同过滤",
"type": 1
},
{
"name": "隐语义模型",
"type": 1
},
{
"name": "从头手写搭建协同过滤与隐语义模型推荐",
"type": 2
},
{
"name": "基于scikit-surprise的推荐系统",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第10课 聚类",
"video_id": 1127,
"point": [
{
"name": "K-means/K-Medoid",
"type": 1
},
{
"name": "层次聚类",
"type": 1
},
{
"name": "GMM",
"type": 1
},
{
"name": "K-means/GMM代码实现和实际应用分析",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第11课 聚类与推荐系统实战",
"video_id": 1128,
"point": [
{
"name": "基于用户聚类的推荐系统",
"type": 2
},
{
"name": "推荐系统比赛案例(数据、代码)",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第四阶段 高阶知识 深入机器学习",
"lesson": [
{
"is_video": 1,
"name": "第12课 贝叶斯网络",
"video_id": 1129,
"point": [
{
"name": "朴素贝叶斯",
"type": 1
},
{
"name": "有向分离",
"type": 1
},
{
"name": "马尔科夫模型",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第13课 隐马尔科夫模型HMM",
"video_id": 1130,
"point": [
{
"name": "概率计算问题",
"type": 1
},
{
"name": "参数学习问题",
"type": 1
},
{
"name": "状态预测问题",
"type": 1
},
{
"name": "使用HMM进行中文分词",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第14课 主题模型",
"video_id": 1131,
"point": [
{
"name": "pLSA",
"type": 1
},
{
"name": "共轭先验分布",
"type": 1
},
{
"name": "LDA",
"type": 1
},
{
"name": "使用LDA进行文档分类",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第五阶段 迈入深度学习 打开DL大门",
"lesson": [
{
"is_video": 1,
"name": "第15课 神经网络初步",
"video_id": 1132,
"point": [
{
"name": "全连接神经网络",
"type": 1
},
{
"name": "反向传播算法与权重优化",
"type": 1
},
{
"name": "训练注意点",
"type": 1
},
{
"name": "通用混合神经网络模板",
"type": 1
},
{
"name": "手写神经网络解决非线性切分问题",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第16课 卷积神经网络与计算机视觉",
"video_id": 1133,
"point": [
{
"name": "卷积神经网络结构分析",
"type": 1
},
{
"name": "过拟合与随机失活",
"type": 1
},
{
"name": "卷积神经网络理解",
"type": 1
},
{
"name": "典型网络结构详解",
"type": 1
},
{
"name": "利用ResNet与inception解决一般图像分类问题套路",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第17课 循环神经网络与自然语言处理",
"video_id": 1134,
"point": [
{
"name": "循环神经网络",
"type": 1
},
{
"name": "长时依赖问题与长短时记忆网络",
"type": 1
},
{
"name": "BPTT算法",
"type": 1
},
{
"name": "利用循环神经网络生成文本作诗",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第18课 深度学习实践",
"video_id": 1135,
"point": [
{
"name": "Caffe应用要点",
"type": 1
},
{
"name": "TensorFlow/Keras简介",
"type": 1
},
{
"name": "用神经网络完成图像分类与特征提取",
"type": 2
},
{
"name": "用Keras构建文本情感分析模型",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
}
]
auditionBox: false,
singleBox: false
}
toAudition() {
this.setState(status => ({
isshow: !status.isshow,
status: 0
}));
toApp = () => {
alert('toApp')
}
toSingleset() {
// 点击子组件试听按钮
toAudition = () => {
this.setState(status => ({
isshow: !status.isshow,
status: 1
auditionBox: true,
}));
}
colse(){
// 点击子组件单集购买按钮
toSingleset = () => {
this.setState(status => ({
isshow: !status.isshow,
singleBox: true,
}));
}
render() {
const tabs = [
{title: '介绍'},
{title: '大纲'}
];
// 自组件传给父组件的boxHide
boxHide = (val) => {
this.setState({auditionBox: val,singleBox: val})
}
render() {
return (
<div className='detail-box'>
<div className="toapp">APP打开</div>
{/*头部*/}
<div className="detail-header">
<i className={'iconfont iconiconfront-68 return'}></i>
<span className='herder'>课程详情</span>
<i className={'iconfont icongouwuche shopping-cart'}></i>
</div>
<ToApp className='toapp' toApp={this.toApp}></ToApp>
<HeaderBar title={'课程详情'}></HeaderBar>
{/*课程*/}
<div className='course-content'>
<div className='cover'>
......@@ -664,7 +79,6 @@ class Detail extends Component {
</div>
}
{/*服务承诺*/}
<div className='promise'>
<label>服务承诺</label>
......@@ -672,182 +86,24 @@ class Detail extends Component {
</div>
{/*分享赚钱*/}
<div className='share-ranking'>
<span className="title">排行榜:</span>
<span className="ranking-mess"><img src="https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg" alt=""/><i>22</i></span>
<span className="ranking-mess"><img src="https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg" alt=""/><i>22</i></span>
<img className="ranking-ellipsis" src="https://julyedu-img.oss-cn-beijing.aliyuncs.com/Image/train/ellipsis.png" alt=""/>
<button className="share">分享赚22</button>
</div>
<ShareRank/>
{/*砍价*/}
<Bargain/>
{/*课程介绍、大纲*/}
<div className='course-detail'>
<WhiteSpace/>
<Tabs tabs={tabs}>
{/*介绍*/}
<div className='introduce'>
讲师:寒小阳、褚博士、David、林老师、张雨石、李老师
课时:线上课每次至少2小时,线下课每次至少4小时
时间:随到随学,视频课件代码作考一应俱全,且讲师助教 答疑
<img
src='https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg'
alt=""/>
</div>
{/*大纲*/}
<div className='outline'>
{
this.state.stage_info.map((item, index) => {
return (
<div className='stagebox' key={index}>
<h1 className='stage text-overflow-1'>{item.stage_name}</h1>
{
item.lesson.map((item, index) => {
return (
<ul key={index}>
<h2 className='classhour text-overflow-1'>{item.name}
<OutLine toAudition={this.toAudition} toSingleset={this.toSingleset}/>
{ // 试听
item.is_video === 0 &&
<span className='btn-right-10 audition' onClick={this.toAudition.bind(this)}>试听</span>
}
{ // 未购买未开单集购买:上锁标志,点击提示购买
item.is_video === 3 &&
<i className='iconfont iconiconfront-74 icon-right-22'></i>
}
{ // 未购买已开单集购买:显示单集价格,点击购买单集
item.is_video === 2 &&
<span className='btn-right-10 singleset' onClick={this.toSingleset.bind(this)}>¥ {item.class_price}</span>
}
{
// 已购买直播中:正在直播,点击进入直播间
item.is_video === 4 &&
<span className='live icon-right-22'>正在直播<i className='iconfont icondanseshixintubiao-23'></i></span>
}
{
// 已购买直播结束已上传视频:正常播放按钮,点击播放课程
item.is_video === 5 &&
<i className='iconfont icondanseshixintubiao-23 icon-right-22'></i>
}
{
// 已购买未开课、已购买直播结束:空
}
</h2>
{
item.point.map((item, index) => {
const type = (
<span>
{item.type === 1 &&
<span>知识点{index + 1}</span>
} {item.type === 2 &&
<span className='red'>实战项目:</span>
}
</span>
)
{/*试听*/}
<Audition auditionBox={this.state.auditionBox} boxHide={this.boxHide}/>
return (
<li className='points text-overflow-1'
key={index}>{type}{item.name}</li>
)
{/*单集购买*/}
<Single singleBox={this.state.singleBox} boxHide={this.boxHide}/>
})
}
</ul>
)
})
}
</div>
)
})
}
</div>
</Tabs>
<WhiteSpace/>
</div>
{
this.state.isshow === true &&
<div>
<div className='popup-box'>
{
this.state.status === 0 &&
<div className='content audition-box'>
<p className='audition-header'>当前页面不支持试听</p>
<p className='audition-dec'>请前往APP试听</p>
<div className='btn btn-18B4ED'>立即前往</div>
</div>
}
{
this.state.status === 1 &&
<div className='content singleset-payment'>
<div className='price-box'>
<span>实付款:</span>
<p>25</p>
</div>
<div className='course-info'>
<p className='text-overflow-1'><span>课程:</span>机器学习</p>
<p className='text-overflow-1'><span>课时:</span>第2课时 决策树与树集成模型法法第2课时 决策树与树集成模型法法</p>
</div>
<div className='payment-type'>
<label>支付方式:</label>
<p>
<i className='iconfont iconzhifubaox-'></i>
<span>支付宝</span>
<i className='iconfont icondanseshixintubiao-5 redioed'></i>
</p>
<p>
<i className='iconfont iconweixinzhifu buy'></i>
<span>微信支付</span>
<i className='iconfont icondanseshixintubiao-5 redio'></i>
</p>
</div>
<div className='btn btn-18B4ED'>确认购买</div>
</div>
}
{
this.state.status === 2 &&
<div className='content payment-success'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 3天内购买全集,可直接抵扣该集费用,275元购买。</div>
<div className="dec">· 超过3天,按照未够集数/全部集数等比例计费,280元购买全集。</div>
<div className='btn btn-18B4ED'>开始学习</div>
<div className='btn btn-FF4000'>275购买全集</div>
</div>
}
{
this.state.status === 3 &&
<div className='content zero'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 恭喜您获得0元拼团购买剩余课时的机会。</div>
<div className='btn btn-FF4000'>0元参团</div>
</div>
}
{
this.state.status === 4 &&
<div className='content zero'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 恭喜您获得0元购买剩余课时的机会。</div>
<div className='btn btn-FF4000'>0元购</div>
</div>
}
<i onClick={this.colse.bind(this)} className={'iconfont iconiconfront-2 close'}></i>
</div>
</div>
}
</div>
);
)
}
}
export default Detail;
export default Detail
......@@ -15,25 +15,6 @@
color: $white;
z-index: 1;
}
.detail-header {
height: 44px;
line-height: 44px;
padding: 0 15px;
background-color: $bg_f7f9fc;
display: flex;
justify-content: space-between;
.shopping-cart, .return {
font-size: 18px !important;
}
.herder {
font-size: 16px;
color: $color_202426;
}
}
.course-content {
margin: 15px 12px 0 12px;
padding-bottom: 10px;
......@@ -196,132 +177,6 @@
}
}
.course-detail {
border-top: 8px solid $bg_f5f5f5;
margin-bottom: 50px;
.am-whitespace-md {
height: 0;
}
.am-tabs-default-bar-tab {
width: auto !important;
}
.am-tabs-default-bar-content {
border-bottom: 1px solid $sp_e7eaf1;
display: flex;
justify-content: space-around;
}
.am-tabs-default-bar-tab-active {
color: $active;
border-bottom: 1px solid $active !important;
}
.am-tabs-default-bar-underline {
display: none;
}
.am-tabs-default-bar-top .am-tabs-default-bar-tab::after {
background-color: $bg_fff !important;
}
.introduce {
padding: 15px 12px;
font-size: 14px;
color: $color_555;
}
.outline {
padding: 15px 0 15px 12px;
background-color: $bg_f5f5f5;
.stagebox {
margin-bottom: 15px;
}
.stage {
font-size: 14px;
color: $color_333;
}
.classhour {
height: 33px;
background-color: $bg_fff;
color: $color_4B4B4B;
line-height: 33px;
font-size: 14px;
padding-left: 10px;
margin-top: 10px;
margin-bottom: 5px;
position: relative;
}
.points {
font-size: 12px;
color: $color_666;
margin-left: 10px;
margin-top: 10px;
}
.red {
color: $color_FE2F2F;
}
.icon-right-22 {
position: absolute;
right: 22px;
}
.iconiconfront-74 {
font-size: 19px;
}
.icondanseshixintubiao-23 {
display: inline-block;
width: 22px;
height: 22px;
border-radius: 50%;
background-color: $bg_active;
color: $white;
text-align: center;
line-height: 22px;
font-size: 14px;
top: 6px;
margin-left: 5px;
}
.live {
color: $active;
font-size: 12px;
}
.btn-right-10 {
position: absolute;
right: 10px;
top: 6px;
display: inline-block;
min-width: 44px;
padding: 0 5px;
height: 22px;
line-height: 22px;
text-align: center;
color: $white;
font-size: 12px;
border-radius: 11px;
}
.audition {
background: linear-gradient(90deg, $bg_0078FF 0%, $bg_active 100%);
}
.singleset {
background-color: $bg_FE2F2F;
}
}
}
.popup-box {
position: fixed;
top: 0;
......
import React, {Component} from 'react'
import {Tabs, WhiteSpace} from 'antd-mobile'
import './index.scss'
class OutLine extends Component {
state = {
stage_info: [
{
"stage_name": "预习阶段 机器学习中的数学基础",
"lesson": [
{
"is_video": 0,
"name": "微积分",
"video_id": 1170,
"point": [
{
"name": "微积分的基本概念",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 2,
"name": "概率论",
"video_id": 1171,
"point": [
{
"name": "概率论简介",
"type": 1
}
],
"class_price": 22.99,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 3,
"name": "线性代数",
"video_id": 1172,
"point": [
{
"name": "线性代数基础",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 4,
"name": "凸优化",
"video_id": 1173,
"point": [
{
"name": "凸优化简介",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第一阶段 掌握基本模型 打开ML大门",
"lesson": [
{
"is_video": 5,
"name": "第1课 回归问题与应用",
"video_id": 1118,
"point": [
{
"name": "线性回归",
"type": 1
},
{
"name": "logistic回归",
"type": 1
},
{
"name": "梯度下降",
"type": 1
},
{
"name": "实际工程海量数据下的logistic回归使用",
"type": 1
},
{
"name": "分布拟合与回归、用LR分类与概率预测",
"type": 2
},
{
"name": "用LR完成Kaggle比赛迈开第一步",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 6,
"name": "第2课 决策树与树集成模型",
"video_id": 1119,
"point": [
{
"name": "不同类型的分类树模型",
"type": 1
},
{
"name": "决策树回归",
"type": 1
},
{
"name": "树模型过拟合与优化",
"type": 1
},
{
"name": "使用随机森林进行数据分类",
"type": 1
},
{
"name": "Bagging",
"type": 1
},
{
"name": "随机森林",
"type": 1
},
{
"name": "信用卡欺诈检测",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第3课 SVM",
"video_id": 1120,
"point": [
{
"name": "线性可分支持向量机、线性支持向量机",
"type": 1
},
{
"name": "非线性支持向量机",
"type": 1
},
{
"name": "SMO",
"type": 1
},
{
"name": "使用SVM进行数据分类",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第4课 最大熵与EM算法(上)",
"video_id": 1121,
"point": [
{
"name": "熵、相对熵、信息增益",
"type": 1
},
{
"name": "最大熵模型、IIS、GMM",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第二阶段 重中之重 特征工程",
"lesson": [
{
"is_video": 1,
"name": "第5课 机器学习中的特征工程处理",
"video_id": 1122,
"point": [
{
"name": "数据清洗、异常点处理",
"type": 1
},
{
"name": "特征抽取、选择与组合策略",
"type": 1
},
{
"name": "特征处理与特征选择模板",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第6课 多算法组合与模型最优化",
"video_id": 1123,
"point": [
{
"name": "机器学习问题场景分析、算法选择",
"type": 1
},
{
"name": "模型构建、模型性能分析与优化策略",
"type": 1
},
{
"name": "构建模型组合策略工具与模板",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第三阶段 工业实战 在实战中掌握一切",
"lesson": [
{
"is_video": 1,
"name": "第7课 sklearn与机器学习实战",
"video_id": 1124,
"point": [
{
"name": "sklearn板块介绍",
"type": 1
},
{
"name": "sklearn完成数据预处理与特征工程",
"type": 1
},
{
"name": "建模流水线搭建",
"type": 1
},
{
"name": "经典Titanic案例,商品销量预测案例等",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第8课 高级工具xgboost/lightGBM与建模实战",
"video_id": 1125,
"point": [
{
"name": "xgboost使用方法与高级功能",
"type": 1
},
{
"name": "lightGBM使用方法与高级功能",
"type": 1
},
{
"name": " Titanic与商品销量预测进阶,Kaggle案例实战",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第9课 电商推荐系统",
"video_id": 1126,
"point": [
{
"name": "推荐系统与评估",
"type": 1
},
{
"name": "基于内容的推荐",
"type": 1
},
{
"name": "基于近邻的推荐--协同过滤",
"type": 1
},
{
"name": "隐语义模型",
"type": 1
},
{
"name": "从头手写搭建协同过滤与隐语义模型推荐",
"type": 2
},
{
"name": "基于scikit-surprise的推荐系统",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第10课 聚类",
"video_id": 1127,
"point": [
{
"name": "K-means/K-Medoid",
"type": 1
},
{
"name": "层次聚类",
"type": 1
},
{
"name": "GMM",
"type": 1
},
{
"name": "K-means/GMM代码实现和实际应用分析",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第11课 聚类与推荐系统实战",
"video_id": 1128,
"point": [
{
"name": "基于用户聚类的推荐系统",
"type": 2
},
{
"name": "推荐系统比赛案例(数据、代码)",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第四阶段 高阶知识 深入机器学习",
"lesson": [
{
"is_video": 1,
"name": "第12课 贝叶斯网络",
"video_id": 1129,
"point": [
{
"name": "朴素贝叶斯",
"type": 1
},
{
"name": "有向分离",
"type": 1
},
{
"name": "马尔科夫模型",
"type": 1
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第13课 隐马尔科夫模型HMM",
"video_id": 1130,
"point": [
{
"name": "概率计算问题",
"type": 1
},
{
"name": "参数学习问题",
"type": 1
},
{
"name": "状态预测问题",
"type": 1
},
{
"name": "使用HMM进行中文分词",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第14课 主题模型",
"video_id": 1131,
"point": [
{
"name": "pLSA",
"type": 1
},
{
"name": "共轭先验分布",
"type": 1
},
{
"name": "LDA",
"type": 1
},
{
"name": "使用LDA进行文档分类",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
},
{
"stage_name": "第五阶段 迈入深度学习 打开DL大门",
"lesson": [
{
"is_video": 1,
"name": "第15课 神经网络初步",
"video_id": 1132,
"point": [
{
"name": "全连接神经网络",
"type": 1
},
{
"name": "反向传播算法与权重优化",
"type": 1
},
{
"name": "训练注意点",
"type": 1
},
{
"name": "通用混合神经网络模板",
"type": 1
},
{
"name": "手写神经网络解决非线性切分问题",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第16课 卷积神经网络与计算机视觉",
"video_id": 1133,
"point": [
{
"name": "卷积神经网络结构分析",
"type": 1
},
{
"name": "过拟合与随机失活",
"type": 1
},
{
"name": "卷积神经网络理解",
"type": 1
},
{
"name": "典型网络结构详解",
"type": 1
},
{
"name": "利用ResNet与inception解决一般图像分类问题套路",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第17课 循环神经网络与自然语言处理",
"video_id": 1134,
"point": [
{
"name": "循环神经网络",
"type": 1
},
{
"name": "长时依赖问题与长短时记忆网络",
"type": 1
},
{
"name": "BPTT算法",
"type": 1
},
{
"name": "利用循环神经网络生成文本作诗",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
},
{
"is_video": 1,
"name": "第18课 深度学习实践",
"video_id": 1135,
"point": [
{
"name": "Caffe应用要点",
"type": 1
},
{
"name": "TensorFlow/Keras简介",
"type": 1
},
{
"name": "用神经网络完成图像分类与特征提取",
"type": 2
},
{
"name": "用Keras构建文本情感分析模型",
"type": 2
}
],
"class_price": 0,
"is_preview": 0,
"is_class": 0,
"video_auth": 0
}
]
}
]
}
render() {
const tabs = [
{title: '介绍'},
{title: '大纲'}
];
return (
<div className='course-detail'>
<WhiteSpace/>
<Tabs tabs={tabs}>
{/*介绍*/}
<div className='introduce'>
讲师:寒小阳、褚博士、David、林老师、张雨石、李老师
课时:线上课每次至少2小时,线下课每次至少4小时
时间:随到随学,视频课件代码作考一应俱全,且讲师助教 答疑
<img
src='https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg'
alt=""/>
</div>
{/*大纲*/}
<div className='outline'>
{
this.state.stage_info.map((item, index) => {
return (
<div className='stagebox' key={index}>
<h1 className='stage text-overflow-1'>{item.stage_name}</h1>
{
item.lesson.map((item, index) => {
return (
<ul key={index}>
<h2 className='classhour text-overflow-1'>{item.name}
{ // 试听
item.is_video === 0 &&
<span className='btn-right-10 audition'
onClick={this.props.toAudition}>试听</span>
}
{ // 未购买未开单集购买:上锁标志,点击提示购买
item.is_video === 3 &&
<i className='iconfont iconiconfront-74 icon-right-22'></i>
}
{ // 未购买已开单集购买:显示单集价格,点击购买单集
item.is_video === 2 &&
<span className='btn-right-10 singleset'
onClick={this.props.toSingleset}>¥ {item.class_price}</span>
}
{
// 已购买直播中:正在直播,点击进入直播间
item.is_video === 4 &&
<span className='live icon-right-22'>正在直播<i
className='iconfont icondanseshixintubiao-23'></i></span>
}
{
// 已购买直播结束已上传视频:正常播放按钮,点击播放课程
item.is_video === 5 &&
<i className='iconfont icondanseshixintubiao-23 icon-right-22'></i>
}
{
// 已购买未开课、已购买直播结束:空
}
</h2>
{
item.point.map((item, index) => {
const type = (
<span>
{item.type === 1 &&
<span>知识点{index + 1}</span>
} {item.type === 2 &&
<span className='red'>实战项目:</span>
}
</span>
)
return (
<li className='points text-overflow-1'
key={index}>{type}{item.name}</li>
)
})
}
</ul>
)
})
}
</div>
)
})
}
</div>
</Tabs>
<WhiteSpace/>
</div>
);
}
}
export default OutLine;
.course-detail {
border-top: 8px solid $bg_f5f5f5;
margin-bottom: 50px;
.am-whitespace-md {
height: 0;
}
.am-tabs-default-bar-tab {
width: auto !important;
}
.am-tabs-default-bar-content {
border-bottom: 1px solid $sp_e7eaf1;
display: flex;
justify-content: space-around;
}
.am-tabs-default-bar-tab-active {
color: $active;
border-bottom: 1px solid $active !important;
}
.am-tabs-default-bar-underline {
display: none;
}
.am-tabs-default-bar-top .am-tabs-default-bar-tab::after {
background-color: $bg_fff !important;
}
.introduce {
padding: 15px 12px;
font-size: 14px;
color: $color_555;
}
.outline {
padding: 15px 0 15px 12px;
background-color: $bg_f5f5f5;
.stagebox {
margin-bottom: 15px;
}
.stage {
font-size: 14px;
color: $color_333;
}
.classhour {
height: 33px;
background-color: $bg_fff;
color: $color_4B4B4B;
line-height: 33px;
font-size: 14px;
padding-left: 10px;
margin-top: 10px;
margin-bottom: 5px;
position: relative;
}
.points {
font-size: 12px;
color: $color_666;
margin-left: 10px;
margin-top: 10px;
}
.red {
color: $color_FE2F2F;
}
.icon-right-22 {
position: absolute;
right: 22px;
}
.iconiconfront-74 {
font-size: 19px;
}
.icondanseshixintubiao-23 {
display: inline-block;
width: 22px;
height: 22px;
border-radius: 50%;
background-color: $bg_active;
color: $white;
text-align: center;
line-height: 22px;
font-size: 14px;
top: 6px;
margin-left: 5px;
}
.live {
color: $active;
font-size: 12px;
}
.btn-right-10 {
position: absolute;
right: 10px;
top: 6px;
display: inline-block;
min-width: 44px;
padding: 0 5px;
height: 22px;
line-height: 22px;
text-align: center;
color: $white;
font-size: 12px;
border-radius: 11px;
}
.audition {
background: linear-gradient(90deg, $bg_0078FF 0%, $bg_active 100%);
}
.singleset {
background-color: $bg_FE2F2F;
}
}
}
import React, {Component} from 'react'
import './index.scss'
class ShareRank extends Component {
render() {
return (
<div className='share-ranking'>
<span className="title">排行榜:</span>
<span className="ranking-mess"><img
src="https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg"
alt=""/><i>22</i></span>
<span className="ranking-mess"><img
src="https://julyedu-img-public.oss-cn-beijing.aliyuncs.com/Public/Image/4c5ccac604.jpg"
alt=""/><i>22</i></span>
<img className="ranking-ellipsis"
src="https://julyedu-img.oss-cn-beijing.aliyuncs.com/Image/train/ellipsis.png" alt=""/>
<button className="share">分享赚22</button>
</div>
);
}
}
export default ShareRank;
.share-ranking {
height: 60px;
line-height: 25px;
padding: 15px 12px;
border-top: 8px solid $bg_f5f5f5;
display: flex;
position: relative;
font-size: 12px;
.title {
font-size: 14px;
margin-right: 12px;
}
.ranking-mess {
margin-right: 20px;
img {
width: 22px;
height: 22px;
border-radius: 50%;
vertical-align: middle;
}
i {
display: inline-block;
margin-left: 5px;
color: $color_333;
font-style: normal;
}
}
.ranking-ellipsis {
width: 22px;
height: 22px;
border-radius: 50%;
}
.share {
position: absolute;
right: 12px;
padding: 5px 6px;
border: 1px solid $red;
border-radius: 3px;
color: $red;
background-color: $bg_fff;
}
}
import React, {Component} from 'react'
import './index.scss'
class Single extends Component {
state = {
status: 1,
}
colse = () => {
this.props.boxHide(false);
}
render() {
return (
<div>
{
this.props.singleBox &&
<div className='popup-box'>
{
this.state.status === 1 &&
<div className='content singleset-payment'>
<div className='price-box'>
<span>实付款:</span>
<p>25</p>
</div>
<div className='course-info'>
<p className='text-overflow-1'><span>课程:</span>机器学习</p>
<p className='text-overflow-1'><span>课时:</span>第2课时 决策树与树集成模型法法第2课时 决策树与树集成模型法
</p>
</div>
<div className='payment-type'>
<label>支付方式:</label>
<p>
<i className='iconfont iconzhifubaox-'></i>
<span>支付宝</span>
<i className='iconfont icondanseshixintubiao-5 redioed'></i>
</p>
<p>
<i className='iconfont iconweixinzhifu buy'></i>
<span>微信支付</span>
<i className='iconfont icondanseshixintubiao-5 redio'></i>
</p>
</div>
<div className='btn btn-18B4ED'>确认购买</div>
</div>
}
{
this.state.status === 2 &&
<div className='content payment-success'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 3天内购买全集,可直接抵扣该集费用,275元购买。</div>
<div className="dec">· 超过3天,按照未够集数/全部集数等比例计费,280元购买全集。</div>
<div className='btn btn-18B4ED'>开始学习</div>
<div className='btn btn-FF4000'>275购买全集</div>
</div>
}
{
this.state.status === 3 &&
<div className='content zero'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 恭喜您获得0元拼团购买剩余课时的机会。</div>
<div className='btn btn-FF4000'>0元参团</div>
</div>
}
{
this.state.status === 4 &&
<div className='content zero'>
<div className="header">
<i className='iconfont icondanseshixintubiao-5'></i>
<span>购买成功</span>
</div>
<div className="dec">· 恭喜您获得0元购买剩余课时的机会。</div>
<div className='btn btn-FF4000'>0元购</div>
</div>
}
<i onClick={this.colse} className={'iconfont iconiconfront-2 close'}></i>
</div>
}
</div>
);
}
}
export default Single;
.popup-box {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: rgba(0, 0, 0, .6);
z-index: 1;
.content {
width: 300px;
position: relative;
background-color: $white;
padding-top: 20px;
border-radius: 3px;
}
.close {
color: #fff;
font-size: 22px;
position: relative;
left: 50%;
margin-left: -11px;
}
.btn {
position: absolute;
bottom: 24px;
left: 83px;
width: 135px;
height: 30px;
border-radius: 3px;
font-size: 16px;
color: $white;
text-align: center;
line-height: 30px;
}
.btn-18B4ED {
background-color: $bg_18B4ED;
}
.btn-FF4000 {
background-color: $bg_FF4000;
}
.header {
color: $active;
height: 24px;
line-height: 24px;
text-align: center;
i {
font-size: 24px;
}
span {
font-size: 18px;
margin-left: 10px;
vertical-align: text-bottom;
}
}
.singleset-payment {
height: 305px;
margin: 140px auto 22px auto;
padding: 17px 20px;
.price-box {
padding-bottom: 15px;
border-bottom: 1px solid $sp_ddd;
span {
font-size: 12px;
color: $color_666;
}
p {
height: 22px;
line-height: 22px;
color: $color_FF4000;
font-size: 22px;
text-align: center;
margin-top: 5px;
}
}
.course-info {
font-size: 14px;
p {
height: 14px;
line-height: 14px;
margin-top: 10px;
color: $color_333;
span {
color: $color_666;
}
}
}
.payment-type {
margin-top: 20px;
label {
display: inline-block;
width: 100%;
border-bottom: 1px solid $sp_ddd;
color: $color_666;
font-size: 12px;
padding-bottom: 5px;
}
p {
height: 22px;
line-height: 22px;
margin-top: 10px;
position: relative;
.iconzhifubaox- {
font-size: 22px;
color: #01aaef;
}
.iconweixinzhifu {
font-size: 22px;
color: #3baf34;
}
span {
display: inline-block;
margin-left: 10px;
color: $color_333;
font-size: 14px;
vertical-align: text-bottom;
}
.icondanseshixintubiao-5 {
position: absolute;
right: 0;
font-size: 24px;
}
.redioed {
color: #4cd964;
}
.redio {
color: $border_ccc;
}
}
}
}
.zero {
height: 147px;
margin: 213px auto 22px auto;
text-align: center;
.header {
color: $active;
height: 24px;
line-height: 24px;
i {
font-size: 24px;
}
span {
font-size: 18px;
margin-left: 10px;
vertical-align: text-bottom;
}
}
.dec {
height: 14px;
line-height: 14px;
color: $color_666;
font-size: 14px;
margin-top: 15px;
}
}
.payment-success {
height: 258px;
margin: 143px auto 22px auto;
padding: 20px 24px;
.dec {
height: 33px;
line-height: 20px;
color: $color_666;
font-size: 14px;
margin-top: 12px;
}
.btn-18B4ED {
bottom: 70px;
}
}
}
\ No newline at end of file
......@@ -30,10 +30,9 @@ export default class Examination extends PureComponent {
}
render() {
// let {ques, type_id, options, analysis} = this.state.questionData
let {
questionData: {
ques, type_id, options, analysis
ques, type_id, options, analysis, category
},
isShowAnswer
} = this.state
......@@ -41,7 +40,7 @@ export default class Examination extends PureComponent {
<div className='examination'>
<div className="question-container">
<div className="topic">
<Tag className='category-tag'>深度学习</Tag>
<Tag className='category-tag'>{category}</Tag>
{ques}
</div>
{
......
.header {
padding: 38px 130px 52px;
flex: 0 0 auto;
.common-header {
padding: 38px 130px 52px;
flex: 0 0 auto;
img {
width: 117px;
height: 50px;
}
}
\ No newline at end of file
img {
width: 117px;
height: 50px;
}
}
\ No newline at end of file
......@@ -5,7 +5,7 @@ import logo from './logo.png'
const Header = React.memo(() => {
return (
<div className="header">
<div className="common-header">
<img src={logo} alt=""/>
</div>
);
......
import React, {Component} from 'react'
import {VList} from '../../common'
import {Tabs, WhiteSpace, SearchBar} from 'antd-mobile'
import {Tabs, WhiteSpace} from 'antd-mobile'
import './index.scss'
import {api} from "@/utils"
import HeaderSearch from '../../common/HeaderSearch/index'
import {http, api} from "@/utils"
class Preferential extends Component {
constructor(props) {
......@@ -18,8 +19,8 @@ class Preferential extends Component {
}
// 限时特惠
specialSale=()=>{
api.get('/m/home/weekDiscounts').then((res) => {
specialSale = () => {
http.get(`${api.home}/m/home/weekDiscounts`).then((res) => {
if (res.data.code === 200) {
this.setState({
dataList: res.data.data
......@@ -28,8 +29,8 @@ class Preferential extends Component {
})
}
// 砍价专区
bargain=()=>{
api.get('/m/home/bargainZone').then((res) => {
bargain = () => {
http.get(`${api.home}/m/home/bargainZone`).then((res) => {
if (res.data.code === 200) {
this.setState({
dataList: res.data.data
......@@ -38,8 +39,8 @@ class Preferential extends Component {
})
}
// 一键拼团
group=()=>{
api.get('/m/home/grouponList').then((res) => {
group = () => {
http.get(`${api.home}/m/home/grouponList`).then((res) => {
if (res.data.code === 200) {
this.setState({
dataList: res.data.data
......@@ -48,10 +49,10 @@ class Preferential extends Component {
})
}
// tab 切换
ontabclick=(tab, index)=> {
ontabclick = (tab, index) => {
console.log(tab, index)
this.state.courseStatus = index
switch(index) {
switch (index) {
case 0:
this.specialSale()
break
......@@ -63,17 +64,10 @@ class Preferential extends Component {
}
}
handleClick=(courseId)=>{
handleClick = (courseId) => {
console.log(courseId)
}
toSearch() {
window.location.href ='/search'
}
return() {
window.location.href ='/index'
}
render() {
const tabs = [
{title: '限时特惠'},
......@@ -82,16 +76,7 @@ class Preferential extends Component {
]
return (
<div className='preferential'>
<div className="search-nav">
<i className={'iconfont iconiconfront-68 return'} onClick={this.return.bind(this)}></i>
<SearchBar
placeholder="搜索课程"
cancelText={" "}
onFocus={this.toSearch.bind(this)}
showCancelButton={false}
/>
<i className={'iconfont icongouwuche shopping-cart'}></i>
</div>
<HeaderSearch></HeaderSearch>
<div className='class-content'>
<WhiteSpace/>
......@@ -106,15 +91,15 @@ class Preferential extends Component {
const Info = (
<div className="info">
<p className='title'>{item.course_title}</p>
<p className='contact text-overflow-2'>{item. course_desc}</p>
<p className='contact text-overflow-2'>{item.course_desc}</p>
<div className='des'>
{item.is_buy &&
<p className="course-price">
{this.state.courseStatus === 0 &&
<span className='price'>特惠价:</span>
<span className='price'>特惠价:</span>
}
<span className="new">¥{item.price2}</span>
<span className="old">¥{item.price1}</span>
<span className="new">¥{item.price1}</span>
<span className="old">¥{item.price0}</span>
</p>
}
{!item.is_buy &&
......@@ -126,7 +111,7 @@ class Preferential extends Component {
const status = (
<div>
{this.state.courseStatus === 1 &&
<p className='course-status'>砍价减{item.price2}</p>
<p className='course-status'>砍价减{item.price1}</p>
}
{this.state.courseStatus === 2 &&
<p className='course-status'>拼团减{item.price}</p>
......@@ -134,7 +119,8 @@ class Preferential extends Component {
</div>
)
return (
<VList handleClick={this.handleClick} key={index} img={item.image_name} id={item.course_id} status={status}
<VList handleClick={this.handleClick} key={index} img={item.image_name}
id={item.course_id} status={status}
info={Info}></VList>
)
})}
......
.preferential {
.search-nav {
height: 44px;
line-height: 44px;
padding: 0 15px;
background-color: $bg_f7f9fc;
display: flex;
justify-content: space-between;
.am-search {
width: 81%;
background-color: $bg_f7f9fc;
}
.am-search-input, .am-search-synthetic-ph, .am-search-value {
text-align: left;
padding-left: 15px;
height: 26px;
line-height: 26px;
}
.am-search-input {
background-color: $bg_EBEFF5;
border-radius: 13px;
}
.shopping-cart, .return {
font-size: 18px !important;
}
}
.class-content {
padding: 0 12px;
......
import React, { Component } from 'react';
import React, { PureComponent } from 'react';
import SearchHead from './searchHead'
import Tag from '@common/Tag/index.js'
import { http, api } from '@/utils'
import './index.scss';
import { Link } from 'react-router-dom'
class Search extends Component {
class Search extends PureComponent {
constructor(props) {
super(props);
this.state = {
history: JSON.parse(localStorage.getItem('history')) || [],
searchHot: ['rec', '电脑', '照片扫描仪', '智能手表', '功夫茶杯', '广角镜头手机'],
hot_words: [],
searchList: []
}
}
async componentDidMount() {
const res = await http.get(`${api['search-api']}/search_hot_word`)
if (res.data.errno === 0) {
this.setState({
hot_words: res.data.data.info.hot_words
})
}
}
search = text => {
}
render() {
let querystring = this.props.location.query ? this.props.location.query.s : '';
return (
<div className="search-page">
<SearchHead value={querystring} returnbtn={true} ></SearchHead>
<SearchHead value={querystring} returnbtn={true}/>
<div className="search-main">
<div className="search-land search-history">
<label>
<span>最近搜索</span>
<i className="iconfont iconiconfront-56" onClick={() => {
this.removeHistory()
}} >
</i>
<i className="iconfont iconiconfront-56"/>
</label>
<div className="search-tag">
{
this.state.history.length > 0 ?
this.state.history.map((v, i) => {
return (<Tag key={i} onClick={() => {
this.gotoList(v)
}}>{v}</Tag>)
return (<Tag key={i}>{v}</Tag>)
})
: <div style={{ textAlign: 'center', padding: '20px' }}>暂无历史</div>
: <div style={{textAlign: 'center', padding: '20px'}}>暂无历史</div>
}
</div>
</div>
<div className="search-land search-hot">
<label>
<span>热门搜索</span>
</label>
<div className="search-tag">
{
this.state.searchHot.length>0?
this.state.searchHot.map((v,i)=>{
return (<Tag key={i} onClick={()=>{
this.gotoList(v)
}}>{v}</Tag>)
})
:<div style={{textAlign:'center',padding:'20px'}}>暂无热门</div>
}
</div>
<label>
<span>热门搜索</span>
</label>
<div className="search-tag">
{
this.state['hot_words'].length > 0 ?
this.state['hot_words'].map((v, i) => {
return (
<Link key={i} to={`/search-result?word=${v}`}>
<Tag>{v}</Tag>
</Link>
)
})
: <div style={{textAlign: 'center', padding: '20px'}}>暂无热门</div>
}
</div>
</div>
</div>
</div>
</div>
</div>
)
}
......
import React, { PureComponent } from 'react';
import SearchHeader from './searchHead'
import VList from '@/common/VList'
import { http, api, getParam } from '@/utils'
import './search-result.scss'
const Bottom = ({item}) => {
return (
<div className='bottom'>
<span className='price'>¥{item.price1}</span>
<span className='stale-price'>¥{item.price0}</span>
</div>
)
}
class SearchResult extends PureComponent {
state = {
courseList: []
}
componentDidMount() {
http.get(`${api['search-api']}/search/${encodeURIComponent(getParam('word'))}?type=course&page=1`)
.then(res => {
const data = res.data
if (data.errno === 0) {
this.setState({
courseList: data.data.info.search_data.course
});
}
})
}
render() {
const {courseList} = this.state
return (
<div className='search-result'>
<SearchHeader/>
<ul>
{
courseList && courseList.length > 0 ?
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>
)
return (
<VList img={item.image_name}
handleClick={this.handleClick}
key={item.course_id}
info={Info}/>
)
}) : null
}
</ul>
</div>
);
}
}
export default SearchResult;
\ No newline at end of file
.search-result {
ul {
list-style: none;
}
.info {
display: flex;
flex-wrap: wrap;
.des {
font-size: $font_14;
line-height: 16px;
align-self: flex-start;
}
.price {
color: $red;
font-size: $font_16;
margin-right: 14px;
}
.stale-price {
text-decoration: line-through;
color: $color_999;
font-size: $font_12;
}
.bottom{
align-self: flex-end;
}
}
}
\ No newline at end of file
import React, { Component } from 'react'
//引入redux
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import * as searchAction from './store'
//引入antd-mobile组件
import React, { PureComponent } from 'react'
import { SearchBar } from 'antd-mobile'
//引入路由跳转装饰器
import { withRouter } from 'react-router-dom'
import './search_header.scss'
class SearchHead extends Component {
//默认参数
static defaultProps = {
returnbtn: false
}
// 构造函数
class SearchHead extends PureComponent {
constructor(props) {
super(props);
this.state = {
......@@ -24,30 +13,28 @@ class SearchHead extends Component {
val: this.props.value || ''
}
}
// 返回某个页面
returnPage() {
console.log(111);
this.props.history.go(-1)
}
//组件装载完毕
componentDidMount() {
this.refs.search.focus();
}
render() {
return (
<div className="search-head">
{
this.props.returnbtn
?
<div className="left" onClick={() => {
// 返回某个页面
this.returnPage()
}}>
{/* <img src={require("@common/images/return.png")} alt="return" /> */}
<i className="iconfont iconiconfront-68"></i>
</div>
: null
}
<div className="left" onClick={() => {
// 返回某个页面
this.returnPage()
}}>
<i className="iconfont iconiconfront-68"/>
</div>
<div className="center">
<SearchBar
value={this.state.val}
......@@ -55,30 +42,21 @@ class SearchHead extends Component {
cancelText={" "}
ref="search"
focus={true}
onChange={(val) => {
this.setState({ val })
this.setState({val})
this.props.search.changeVal(val)
}}
placeholder="搜索课程"></SearchBar>
placeholder="搜索课程"/>
</div>
<div className="right right-btn">
<div className="submit-btn"
>搜索</div>
<div className="submit-btn"
>搜索
</div>
</div>
</div>
)
}
}
export default connect(
({ searchReducer }) => {
return {
searchVal: searchReducer.val
}
},
(dispatch) => {
return {
search: bindActionCreators(searchAction, dispatch)
}
}
)(withRouter(SearchHead))
\ No newline at end of file
export default withRouter(SearchHead)
\ No newline at end of file
export const CHANGEVAL = 'CHANGEVAL'
\ No newline at end of file
import reducer from './reducer';
import * as constants from './constants';
export { reducer, constants };
\ No newline at end of file
const initState = {
}
export default (state = initState, actions) => {
switch (actions.type) {
default:
return state
}
}
\ No newline at end of file
import React, { PureComponent } from 'react'
import { Course, Tag } from '../../../common'
import { api } from '@/utils'
import { http, api } from '@/utils'
import './free-courses.scss'
......@@ -42,11 +42,11 @@ class FreeCourse extends PureComponent {
}
getFreeCourses = () => {
return api.get(`/m/free_course/${this.state.page}/${this.state.num}`)
return http.get(`${api.home}/m/free_course/${this.state.page}/${this.state.num}`)
}
getFreeLive = () => {
return api.get(`/m/live/free_list`)
return http.get(`${api.home}/m/live/free_list`)
}
render() {
......
import { api } from '@/utils'
import { http, api } from '@/utils'
export const RECEIVE_MY_COURSES = 'RECEIVE_MY_COURSES'
......@@ -22,7 +22,7 @@ export const fetchCoursesListIfNeeded = () => (dispatch, getState) => {
}
export const getMyCourses = payload => dispatch => {
return api.get(`/m/my_course/${payload.page}/${payload.num}`)
return http.get(`${api.home}/m/my_course/${payload.page}/${payload.num}`)
.then(res => {
const {data, code, msg} = res.data
if (data.length === 0) {
......
import React from 'react';
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom';
import Index from './components/Index';
import Classify from './components/classify';
import Study from './components/study';
import My from './components/my';
import CourseList from './components/classify/courselist';
import Order from './components/order/index';
import Preferential from './components/preferential/index';
import Search from './components/search/index'
import Detail from './components/detail/index'
import Examination from './components/examination'
import ExchangeCoupons from './components/coupons/exchange-coupons'
import UseCoupon from './components/coupons/use-coupons'
// import OrderInfo from './components/order/orderinfo';
import ShopCard from './components/shopCard/index';
import BargainMiddlePage from './components/bargainMiddlePage';
import Passport from './components/passport'
const router = () => (
<Router>
<Switch>
<Route exact path="/" component={Index}/>
<Route path="/index" component={Index}/>
<Route path='/classify' component={Classify}/>
<Route path='/study' component={Study}/>
<Route path='/my' component={My}/>
<Route path='/courselist' component={CourseList}/>
<Route path='/preferential' component={Preferential}/>
<Route path='/search' component={Search}/>
<Route path='/order' component={Order}/>
<Route path='/detail' component={Detail}/>
<Route path='/examination' component={Examination}/>
<Route path='/exchange-coupons' component={ExchangeCoupons}/>
<Route path='/use-coupon' component={UseCoupon}/>
{/*<Route path='/orderinfo' component={OrderInfo}></Route>*/}
<Route path='/shopcard' component={ShopCard}/>
<Route path='/bargain-middle-page' component={BargainMiddlePage}/>
<Route path='/passport' component={Passport}/>
</Switch>
</Router>
)
export default router;
\ No newline at end of file
import React from 'react'
import { BrowserRouter as Router, Switch, Route } from 'react-router-dom'
import RouterConfig from './router-config'
export default function () {
return (
<Router>
<Switch>
{RouterConfig.map((item, index) => {
let {CustomRoute, ...rest} = item
if (CustomRoute) {
return <CustomRoute {...rest}/>
} else {
return (
<Route {...rest} key={index}/>
)
}
})}
</Switch>
</Router>
)
}
\ No newline at end of file
import Index from '@/components/Index';
import Classify from '@/components/classify';
import Study from '@/components/study';
import My from '@/components/my';
import CourseList from '@/components/classify/courselist';
import Order from '@/components/order/index';
import Preferential from '@/components/preferential/index';
import Search from '@/components/search/index'
import SearchResult from '@/components/search/search-result'
import Detail from '@/components/detail/index'
import Examination from '@/components/examination'
import ExchangeCoupons from '@/components/coupons/exchange-coupons'
import UseCoupon from '@/components/coupons/use-coupons'
import ShopCard from '@/components/shopCard/index';
import BargainMiddlePage from '@/components/bargainMiddlePage';
import Passport from '@/components/passport'
export default [
{
path: '/',
exact: true,
component: Index
},
{
path: '/classify',
component: Classify
},
{
path: '/study',
component: Study
},
{
path: '/my',
component: My
},
{
path: '/courselist',
component: CourseList
},
{
path: '/preferential',
component: Preferential
},
{
path: '/search',
exact: true,
component: Search
},
{
path: '/search-result',
component: SearchResult
},
{
path: '/order',
component: Order
},
{
path: '/detail',
component: Detail
},
{
path: '/examination',
component: Examination
},
{
path: '/exchange-coupons',
component: ExchangeCoupons
},
{
path: '/use-coupon',
component: UseCoupon
},
{
path: '/shopcard',
component: ShopCard
},
{
path: '/bargain-middle-page',
component: BargainMiddlePage
},
{
path: '/passport',
component: Passport
},
]
\ No newline at end of file
const config = require('./utils/proxy-config')
const proxy = require('http-proxy-middleware')
const target = 'http://fast-test.julyedu.com'
module.exports = function (app) {
app.use(proxy(
'/api',
{
target,
changeOrigin: true,
pathRewrite: {
'^/api': ''
Object.keys(config).forEach(item => {
app.use(proxy(
config[item]['development'], {
target: config[item]['test'],
changeOrigin: true,
pathRewrite: {
[`^${config[item]['development']}`]: ''
},
...item['proxy']
}
})
)
};
))
})
};
\ No newline at end of file
import { combineReducers } from 'redux';
import searchReducer from '@/components/search/store/reducer';
import myCourses from '@/components/study/myCourses/reducers'
const reducer = combineReducers({
searchReducer,
myCourses
});
......
import axios from "axios";
import qs from 'qs'
import config from './proxy-config'
export const BASE_URL = process.env.NODE_ENV === 'development' ? '/api' : 'https://api.julyedu.com'
let api = {}
const instance = axios.create({
baseURL: BASE_URL,
transformRequest: [
(data) => qs.stringify(data)
],
headers: {
HTTP_PLAT_FORM: 5,
HTTP_PLAT: 5
Object.keys(config).forEach(item => {
if(item !== 'proxy'){
api[item] = config[item][process.env.NODE_ENV]
}
})
export default instance
\ No newline at end of file
export default api
\ No newline at end of file
import axios from "axios";
import qs from 'qs'
const instance = axios.create({
transformRequest: [
(data) => qs.stringify(data)
],
headers: {
HTTP_PLAT_FORM: 5,
HTTP_PLAT: 5
}
})
export default instance
\ No newline at end of file
export { default as http } from './http'
export { default as api } from './api'
// 计算时间相差fn(过去距离当前时间)
export const computingTime = (pastTime) => {
var currentTime = (new Date()).getTime(),
......@@ -50,4 +50,11 @@ export const isPhone = ($poneInput) => {
} else {
return false;
}
}
\ No newline at end of file
}
export const getParam = (key, str) => {
const _s = str ? str : location.href;
const re = new RegExp(`(?:\\?|#|&)(${key})=([^=&#\\?]+)`, 'ig');
let found;
return (found = re.exec(_s)) ? found[2] : null;
}
\ No newline at end of file
const config = {
home: {
development: '/api',
test: 'http://fast-test.julyedu.com',
production: 'https://m.julyedu.com',
proxy: {}
},
'search-api': {
development: '/search-api',
test: 'https://search.julyedu.com',
production: 'https://search.julyedu.com',
proxy: {}
},
}
module.exports = config
\ No newline at end of file
......@@ -2540,16 +2540,16 @@ comma-separated-tokens@^1.0.0:
resolved "https://registry.yarnpkg.com/comma-separated-tokens/-/comma-separated-tokens-1.0.6.tgz#3cd3d8adc725ab473843db338bcdfd4a7bb087bf"
integrity sha512-f20oA7jsrrmERTS70r3tmRSxR8IJV2MTN7qe6hzgX+3ARfXrdMJFvGWvWQK0xpcBurg9j9eO2MiqzZ8Y+/UPCA==
commander@*, commander@^2.11.0, commander@^2.19.0, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@2.17.x:
version "2.17.1"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.17.1.tgz#bd77ab7de6de94205ceacc72f1716d29f20a77bf"
integrity sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==
commander@^2.11.0, commander@^2.19.0, commander@~2.20.0:
version "2.20.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422"
integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ==
commander@~2.19.0:
version "2.19.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.19.0.tgz#f6198aa84e5b83c46054b94ddedbfed5ee9ff12a"
......@@ -5934,6 +5934,11 @@ js-base64@^2.1.8:
resolved "https://registry.yarnpkg.com/js-base64/-/js-base64-2.5.1.tgz#1efa39ef2c5f7980bb1784ade4a8af2de3291121"
integrity sha512-M7kLczedRMYX4L8Mdh4MzyAMM9O5osx+4FcOQuTvr3A9F2D9S5JXheN0ewNbrvK2UatkTRhL5ejGmGSjNMiZuw==
js-cookie@^2.2.0:
version "2.2.0"
resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.0.tgz#1b2c279a6eece380a12168b92485265b35b1effb"
integrity sha1-Gywnmm7s44ChIWi5JIUmWzWx7/s=
js-levenshtein@^1.1.3:
version "1.1.6"
resolved "https://registry.yarnpkg.com/js-levenshtein/-/js-levenshtein-1.1.6.tgz#c6cee58eb3550372df8deb85fad5ce66ce01d59d"
......@@ -6730,6 +6735,13 @@ mkdirp@0.5.1, mkdirp@0.5.x, "mkdirp@>=0.5 0", mkdirp@^0.5.0, mkdirp@^0.5.1, mkdi
dependencies:
minimist "0.0.8"
mockjs@^1.0.1-beta3:
version "1.0.1-beta3"
resolved "https://registry.yarnpkg.com/mockjs/-/mockjs-1.0.1-beta3.tgz#d234f3c27256397564f2c955142e891909537209"
integrity sha1-0jTzwnJWOXVk8slVFC6JGQlTcgk=
dependencies:
commander "*"
move-concurrently@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92"
......@@ -8651,6 +8663,13 @@ react-fast-compare@^2.0.1:
resolved "https://registry.yarnpkg.com/react-fast-compare/-/react-fast-compare-2.0.4.tgz#e84b4d455b0fec113e0402c329352715196f81f9"
integrity sha512-suNP+J1VU1MWFKcyt7RtjiSWUjvidmQSlqu+eHslq+342xCbGTYmC0mEhPCOHxlW0CywylOC1u2DFAT+bv4dBw==
react-infinite-scroller@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/react-infinite-scroller/-/react-infinite-scroller-1.2.4.tgz#f67eaec4940a4ce6417bebdd6e3433bfc38826e9"
integrity sha512-/oOa0QhZjXPqaD6sictN2edFMsd3kkMiE19Vcz5JDgHpzEJVqYcmq+V3mkwO88087kvKGe1URNksHEOt839Ubw==
dependencies:
prop-types "^15.5.8"
react-is@^16.6.0, react-is@^16.7.0, react-is@^16.8.1, react-is@^16.8.6:
version "16.8.6"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.8.6.tgz#5bbc1e2d29141c9fbdfed456343fe2bc430a6a16"
......
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