react-app-shell
Version:
react打包脚本和example, 这里的版本请忽略
730 lines (667 loc) • 21.9 kB
JavaScript
import React, { Component } from 'react';
import { observer, inject } from 'mobx-react';
import { withRouter } from 'react-router-dom';
import queryString from 'query-string';
import NotBeginCountDown from './not-begin-count-down';
import { WechatConfig, ModalLogin } from '../../../components';
import { groupService } from '../../../service';
import {
JOIN_STATUS,
GROUP_STATUS,
SYSTEM_MODAL_KEY,
CREATE_RESULT_CODE
} from '../../../constants';
import { message, tools, monitor } from '../../../utils';
import { appConfig, shareConfig } from '../../../config';
import { CustomServiceModal, WeiXinModal, NoJoinTipsModal, ShareLayerModal } from '../../component';
import styles from './styles.less';
// 约课链接
const { bookingUrl } = appConfig.resources;
/**
* 环境
* @type {string}
*/
const NODE_ENV = process.env.NODE_ENV || 'development';
/**
* 默认分享
* @type {shareConfig.group|{title, desc, imgUrl, type, dataUrl}}
*/
const defaultShareOptions = shareConfig.group;
/**
* 团购底部按钮
*/
class Footer extends Component {
constructor(props) {
super(props);
// 同步检查用户授权
// wechatUtils.checkUserAuth();
this.urlParams = queryString.parse(window.location.search);
// 获取用户的主公众号授权的openId
this.openId = tools.getMainOpenId();
this.state = {
modalKey: '',
shareOptions: {
...defaultShareOptions,
link: this.getDefaultShareLink()
},
tipsText: ''
};
this.throttleCreateTeam = tools.throttle(this.handleCreateTeam, 1000);
this.throttleJoinTeam = tools.throttle(this.handleJoinTeam, 1000);
}
componentWillReceiveProps(nextProps) {
// 当团购活动Id或者teamId变化时, 重新设置分享信息
const { groupId, teamId } = this.props;
if (nextProps.groupId !== groupId || nextProps.teamId !== teamId) {
let nextTeamId = nextProps.teamId;
// 如果是单独购买, 则分享的链接里,不需要带teamId参数, 需要设置为默认值-1
if (nextProps.joinStatus === JOIN_STATUS.SINGLE_BUY) {
nextTeamId = -1;
}
this.updateShareOptions(nextProps.groupId, nextTeamId, nextProps.shareInfo);
}
}
componentDidUpdate(prevProps) {
// 如果groupId或teamId发生变化, 检查是否关注过公众号
if (this.props.groupId !== prevProps.groupId || this.props.teamId !== prevProps.teamId) {
this.checkFollow();
}
}
/**
* 获取默认分享的链接
*/
getDefaultShareLink = () => {
const { groupId, teamId, rf } = this.urlParams;
const searchObj = {
groupId,
teamId: teamId,
rf: rf || -1
};
// 分享链接
const link = `${location.protocol}//${location.host}${
location.pathname
}?${queryString.stringify(searchObj)}`;
return link;
};
/**
* 更新分享配置
* @param groupId
* @param teamId
* @param shareInfo
*/
updateShareOptions = (groupId, teamId, shareInfo = {}) => {
const searchObj = {
groupId,
teamId: teamId,
rf: this.urlParams.rf || -1
};
// 分享链接
const link = `${window.location.protocol}//${window.location.host}${
window.location.pathname
}?${queryString.stringify(searchObj)}`;
const shareOptions = {
...defaultShareOptions,
title: shareInfo.title || defaultShareOptions.title,
desc: shareInfo.description || defaultShareOptions.desc,
imgUrl: shareInfo.imageUrl || defaultShareOptions.imgUrl,
link
};
// 更新分享内容
this.setState({
shareOptions
});
};
/**
* 当支付后跳转回团购页面时, 引导关注公众号
* @returns {Promise<void>}
*/
checkFollow = async () => {
const { groupId, joinStatus } = this.props;
const { from } = this.urlParams;
// 如果不是从支付页跳转回来的
if (from !== 'pay') {
return;
}
try {
// 当单独购买成功 或者 开团/参团成功后, 引导关注公众号
if (joinStatus === JOIN_STATUS.SINGLE_BUY || joinStatus === JOIN_STATUS.MY_TEAM) {
const followStatus = await groupService.getFollowInfo(groupId);
if (!followStatus) {
this.setState({
modalKey: SYSTEM_MODAL_KEY.GROUP_SUCCESS_MODAL // 团购购买成功, 引导关注公众号
});
}
}
} catch (error) {
console.error(error);
// message.error(error.msg);
}
};
/**
* 获取支付Url
* @param orderNo 订单号
* @param teamId 开团/单独购买的链接不需要传teamId参数
* @returns {string}
*/
getPayUrl = (orderNo, teamId) => {
const { groupId } = this.props;
const { rf } = this.urlParams;
const searchObj = {
groupId,
teamId: teamId,
rf: rf || -1,
from: 'pay' // 支付成功之后跳转回来, 根据该字段去判断是否关注过公众号
};
const callbackUrl = encodeURIComponent(
`${window.location.protocol}//${window.location.host}${
window.location.pathname
}?${queryString.stringify(searchObj)}`
);
const url = `${appConfig.domain.mobileDomain}/pay/order_info?channel=wechat&type=WechatMP&order_no=${orderNo}&callback_url=${callbackUrl}`;
return url;
};
/**
* 开团
*/
handleCreateTeam = async () => {
const { groupId } = this.props;
const { rf } = this.urlParams;
// 本地开发环境没有openId, 所以不做判断
if (NODE_ENV !== 'development') {
if (!this.openId) {
message.error('未获取到授权的用户信息');
return;
}
}
monitor.log('', '立即开团');
// 开团
groupService
.createTeam(groupId, rf, this.openId)
.then(({ orderNo }) => {
if (orderNo) {
monitor.log('', '参团成功');
// 跳转订单支付页面
// 单独购买的链接不需要传teamId参数, 开团/参团的时候需要带上teamId参数
const payUrl = this.getPayUrl(orderNo);
window.location.href = payUrl;
} else {
message.error('订单号为空');
}
})
.catch((error) => {
monitor.log('', '开团失败!!! ' + error.msg || '接口发生错误');
switch (error.code) {
case CREATE_RESULT_CODE.LOGIN_REQUIRED: {
// 需要登录
this.setState({
modalKey: 'Login'
});
break;
}
case CREATE_RESULT_CODE.BIZ_GROUP_JOIN_LIMIT_SHEEPMOM: {
const errorMsg = `啊哦...您已参与过试听优惠活动,本次不能参团啦~`;
monitor.log('', `开团未成功:${errorMsg}`);
this.handleSetTipsText(errorMsg);
break;
}
case CREATE_RESULT_CODE.BIZ_GROUP_ACTIVITY_NOT_QUALIFIED: {
let errorMsg = '开团失败';
const { currentMemberConditionType } = error.data;
switch (currentMemberConditionType) {
case 2:
errorMsg = '您是非正式付费学员,本次不能开团哦~';
break;
case 3:
errorMsg = '您是付费学员,本次不能开团哦~';
break;
case 4:
errorMsg = '您已经参加过团购,本次不能开团啦~';
break;
case 5:
errorMsg = '您没有参加过团购,本次不能开团哦~';
break;
}
monitor.log('', `开团未成功:${errorMsg}`);
this.handleSetTipsText(errorMsg);
break;
}
default: {
message.error(error.msg || '发生错误了');
break;
}
}
});
};
/**
* 参团
*/
handleJoinTeam = async () => {
const { groupId, teamId } = this.props;
const { rf } = this.urlParams;
monitor.log('', '立即参团');
groupService
.joinTeam(groupId, teamId, rf, this.openId)
.then(({ orderNo }) => {
if (orderNo) {
monitor.log('', '参团成功');
// 跳转订单支付页面
// 单独购买的链接不需要传teamId参数, 开团/参团的时候需要带上teamId参数
const payUrl = this.getPayUrl(orderNo);
window.location.href = payUrl;
} else {
message.error('订单号为空');
}
})
.catch((error) => {
monitor.log('', '参团失败!!! ' + error.msg || '接口发生错误');
switch (error.code) {
case CREATE_RESULT_CODE.LOGIN_REQUIRED: {
// 需要登录
this.setState({
modalKey: 'Login'
});
break;
}
case CREATE_RESULT_CODE.BIZ_GROUP_JOIN_LIMIT_SHEEPMOM: {
const errorMsg = `啊哦...您已参与过试听优惠活动,本次不能参团啦~`;
monitor.log('', `开团未成功:${errorMsg}`);
this.handleSetTipsText(errorMsg);
break;
}
case CREATE_RESULT_CODE.BIZ_GROUP_ACTIVITY_NOT_QUALIFIED: {
let errorMsg = '参团失败';
const { currentMemberConditionType } = error.data;
switch (currentMemberConditionType) {
case 2:
errorMsg = '您是非正式付费学员,本次不能参团哦~';
break;
case 3:
errorMsg = '您是付费学员,本次不能参团哦~';
break;
case 4:
errorMsg = '您已经参加过团购,本次不能参团啦~';
break;
case 5:
errorMsg = '您没有参加过团购,本次不能参团哦~';
break;
}
monitor.log('', `参团未成功:${errorMsg}`);
this.handleSetTipsText(errorMsg);
break;
}
default: {
message.error(error.msg || '发生错误了');
break;
}
}
});
};
/**
* 单独购买
*/
handleSingleBuy = async () => {
const { groupId } = this.props;
const { rf } = this.urlParams;
monitor.log('', '单独购买');
// 单独购买
groupService
.singleBuy(groupId, rf, this.openId)
.then(({ orderNo }) => {
if (orderNo) {
monitor.log('', '单独购买成功');
// 跳转订单支付页面
// 单独购买的链接不需要传teamId参数, 开团/参团的时候需要带上teamId参数
const payUrl = this.getPayUrl(orderNo);
window.location.href = payUrl;
} else {
message.error('订单号为空');
}
})
.catch((error) => {
monitor.log('', '单独购买失败!!! ' + error.msg || '接口发生错误');
switch (error.code) {
case CREATE_RESULT_CODE.LOGIN_REQUIRED: {
// 需要登录
this.setState({
modalKey: 'Login'
});
break;
}
case CREATE_RESULT_CODE.BUSINESS_FAULT: {
this.handleSetTipsText(error.msg || '购买失败');
break;
}
default: {
message.error(error.msg || '发生错误了');
break;
}
}
});
};
handleHrefChange = (url) => {
return () => {
monitor.log('', '马上约课');
window.location.href = url;
};
};
handleSetTipsText = (text) => {
this.setState({
modalKey: SYSTEM_MODAL_KEY.NOT_JOIN_TIPS_MODAL,
tipsText: text
});
};
/**
* 团购活动未开始
* 活动倒计时
* @returns {*}
*/
renderNotBegin = () => {
const { singlePrice, groupPrice, startTime, serverTime } = this.props;
const currentDate = new Date(startTime).format('MM月dd日 HH:mm开抢');
return (
<div className={styles['button-countdown']}>
<div className={styles['button-left']}>
<span>{groupPrice ? '¥' + groupPrice : ''}</span>
<span>{singlePrice ? '¥' + singlePrice : ''}</span>
</div>
<div className={styles['button-right']}>
<i>{currentDate}</i>
<div className={styles['count-down']}>
<NotBeginCountDown startTime={startTime} serverTime={serverTime}></NotBeginCountDown>
</div>
</div>
</div>
);
};
/**
* 团购活动已结束
* 只显示马上约课
*/
renderEnd = () => {
return (
<div className={styles['button-normal']} onClick={this.handleHrefChange(bookingUrl)}>
马上约课
</div>
);
};
/**
* 没有开团/参团
* 1. 未登录==未参团
* 2. 登录未参团
* @returns {*}
*/
renderNotJoin = () => {
const { singlePrice, groupPrice, teamId, isFull, isAllowFullJoin } = this.props;
// 1. 有teamId参数
// 2. 并且 ( 未满团 || 满团时允许参团 )
if (teamId && String(teamId) !== '-1' && (!isFull || isAllowFullJoin)) {
return (
<div className={styles['button-group']}>
<div className={styles['button-left']} onClick={this.handleSingleBuy}>
<span>{singlePrice ? '¥' + singlePrice : ''}</span>
<i>单独购买</i>
</div>
<div className={styles['button-right']} onClick={this.throttleJoinTeam}>
<span>{groupPrice ? '¥' + groupPrice : ''}</span>
<i>立即参团</i>
</div>
</div>
);
} else {
return (
<div className={styles['button-group']}>
<div className={styles['button-left']} onClick={this.handleSingleBuy}>
<span>{singlePrice ? '¥' + singlePrice : ''}</span>
<i>单独购买</i>
</div>
<div className={styles['button-right']} onClick={this.throttleCreateTeam}>
<span>{groupPrice ? '¥' + groupPrice : ''}</span>
<i>立即开团</i>
</div>
</div>
);
}
};
/**
* 显示我要当团长
* @returns {*}
*/
renderGroupLeader = () => {
const { teamId, isFull, isAllowFullJoin } = this.props;
// 1. 有teamId参数 并且不等于-1
// 2. 并且 ( 未满团 || 满团时允许参团 )
if (teamId && String(teamId) !== '-1' && (!isFull || isAllowFullJoin)) {
return (
<div className={styles['become-commander']} onClick={this.throttleCreateTeam}>
<div className={styles['button-commander']}>我要当团长</div>
</div>
);
}
return null;
};
/**
* 已经单独购买
* 马上约课, 分享给好友
*/
renderSingleBuy = () => {
return (
<div className={styles['button-group']}>
<div className={styles['button-left']} onClick={this.handleHrefChange(bookingUrl)}>
马上约课
</div>
<div className={styles['button-right']} onClick={this.handleOpenShareModal}>
分享给好友
</div>
</div>
);
};
/**
* 已经开团/参团, 但是打开的不是自己的团
* 显示 查看我的团购
*/
renderOtherTeam = () => {
const { groupId, teamId } = this.props;
// 查看我的团购
const searchObj = {
groupId,
teamId, // 查看我的团购, teamId传值-1
rf: this.urlParams.rf || -1
};
const url = `${appConfig.basename}/group?${queryString.stringify(searchObj)}`;
return (
<div className={styles['button-normal']} onClick={this.handleHrefChange(url)}>
查看我的团购
</div>
);
};
/**
* 已经开团/参团, 包括(已经参团 没有teamId参数 或者有teamId参数并且等于自己的参加的团 )
* 马上约课, 邀请好友参团
*/
renderMyTeam = () => {
return (
<div className={styles['button-group']}>
<div className={styles['button-left']} onClick={this.handleHrefChange(bookingUrl)}>
马上约课
</div>
<div className={styles['button-right']} onClick={this.handleOpenShareModal}>
邀请好友参团
</div>
</div>
);
};
/**
* 登录/注册成功的回调
*/
handleLoginCallback = () => {
const { loadData, groupId, teamId } = this.props;
this.setState({
modalKey: ''
});
// 登录成功之后 重新获取团购数据
loadData(groupId, teamId);
};
/**
* 关闭modal
*/
handleHideModal = () => {
this.setState({
modalKey: ''
});
};
/**
* 打开客服弹窗
*/
handleOpenCustom = () => {
monitor.log('', '客服弹窗');
this.setState({
modalKey: SYSTEM_MODAL_KEY.CUSTOM_SERVICE_MODAL
});
};
/**
* 打开微信弹窗
*/
handleOpenWeiXinModal = () => {
monitor.log('', '打开微信公众号弹窗');
this.setState({
modalKey: SYSTEM_MODAL_KEY.WEIXIN_MODAL
});
};
/**
* 打开分享给好友弹窗
*/
handleOpenShareModal = () => {
monitor.log('', '打开分享给好友弹窗');
this.setState({
modalKey: SYSTEM_MODAL_KEY.SHARE_MODAL
});
};
/**
* 显示弹窗
* @returns {*}
*/
renderModal = () => {
const { modalKey, tipsText = '啊哦,你不能作为团员参加哦~' } = this.state;
// 团长Id
const { teamLeaderId, groupId } = this.props;
switch (modalKey) {
case 'Login': // 登录或者注册
return (
<ModalLogin
onOk={this.handleLoginCallback}
onCancel={this.handleHideModal}
actId={groupId}
actType="group"
promotion="group"
teamLeaderId={teamLeaderId}
></ModalLogin>
);
case SYSTEM_MODAL_KEY.CUSTOM_SERVICE_MODAL: // 底部客服弹窗类型
return (
<CustomServiceModal
onOpenWeiXinModal={this.handleOpenWeiXinModal}
onCancel={this.handleHideModal}
/>
);
case SYSTEM_MODAL_KEY.WEIXIN_MODAL: // 微信客服弹窗类型
return <WeiXinModal onCancel={this.handleHideModal} />;
case SYSTEM_MODAL_KEY.NOT_JOIN_TIPS_MODAL: // 不能参加团购弹窗提示
return <NoJoinTipsModal tipsText={tipsText} onOk={this.handleHideModal} />;
case SYSTEM_MODAL_KEY.GROUP_SUCCESS_MODAL: // 团购成功,引导关注公众号
return (
<WeiXinModal
header={
<div>
<p>恭喜您成功购买团购课程,</p>
<p>关注魔力耳朵服务号,赶紧约课吧!</p>
</div>
}
onCancel={this.handleHideModal}
/>
);
case SYSTEM_MODAL_KEY.SHARE_MODAL: // 提示分享
return <ShareLayerModal onCancel={this.handleHideModal} />;
}
return null;
};
render() {
const { shareOptions } = this.state;
const { groupStatus, joinStatus, groupId, teamId } = this.props;
console.log('Footer >>> render >>> ', this.props);
let element = null;
let groupLeaderElement = null;
// 活动状态未知
if (groupStatus === GROUP_STATUS.UNKNOWN) {
return null;
}
// 判断活动状态
if (groupStatus === GROUP_STATUS.NOT_BEGIN) {
// 活动未开始
element = this.renderNotBegin();
} else if (groupStatus === GROUP_STATUS.END) {
// 活动已结束
element = this.renderEnd();
} else {
// 活动进行中
switch (joinStatus) {
case JOIN_STATUS.NOT_JOIN: // 未登录 或者 没有开团/参团
element = this.renderNotJoin();
groupLeaderElement = this.renderGroupLeader();
break;
case JOIN_STATUS.SINGLE_BUY: // 已经单独购买
element = this.renderSingleBuy();
break;
case JOIN_STATUS.MY_TEAM: // 已经开团/参团, 包括(已经参团 没有teamId参数 或者有teamId参数并且等于自己的参加的团 )
element = this.renderMyTeam();
break;
case JOIN_STATUS.OTHER_TEAM: // 已经开团/参团, 但是打开的不是自己的团
element = this.renderOtherTeam();
break;
default:
element = this.renderEnd();
break;
}
}
return (
<div>
<div className={styles['footer']}>
<div className={styles['service']} onClick={this.handleOpenCustom}>
客服
</div>
{element}
</div>
{groupLeaderElement}
{this.renderModal()}
<WechatConfig
key={groupId + teamId}
showShare={true}
shareOptions={shareOptions}
></WechatConfig>
</div>
);
}
}
export default withRouter(Footer);