react-app-shell
Version:
react打包脚本和example, 这里的版本请忽略
687 lines (623 loc) • 23.8 kB
JavaScript
import React from 'react';
import classNames from 'classnames';
import querystring from 'query-string';
import {inject} from 'mobx-react';
import {checkUserAuth, WechatConfig} from '../../components';
import {appConfig} from '../../config';
import {AccountsType} from '../../constants';
import {tools, message, myToast} from '../../utils';
import Modal from './components/modal';
import ShareLayer from './components/shareLayer';
import WinnerList from './components/winnerList';
import {ModalLogin} from '../../components/';
import {MODAL_KEY, ERROR_CODE, PRIZE_TYPE} from '../../constants/lottery';
import {lotteryService, authService} from '../../service';
import plate_8 from '../../public/images/lottery/plate_8.png';
import rule from '../../public/images/lottery/rule.png';
import wechatLogo from '../../public/images/lottery/wechat_logo.jpg';
import packageImage from '../../public/images/lottery/package.png';
import weepRabbit from '../../public/images/common/weep-rabbit.png';
import styles from './lottery.less';
/**
* 大转盘抽奖活动
*/
(({lotteryStore}) => ({
configShareOptions: lotteryStore.configShareOptions
}))
({account: AccountsType.MAIN}) // 微信授权--魔力耳朵公众号
export default class Lottery extends React.Component {
constructor(props) {
super(props);
let context = this;
this.isWechat = tools.isWeiXin();
this.lotteryId = Number(this.props.match.params.id);
this.params = querystring.parse(location.search);
this.isAllow = true;
this.winnerListKey = Date.now();
this.shareKey = Date.now() + 1;
this.state = {
shareOptions: {
title: 'Hi,快来一起领奖吧,超赞哦!',
success() {
context.handleWechatShare();
}
},
lotteryStyleSheet: {}, // 根元素样式
lotteryResult: {}, // 抽奖后的中奖信息
remainingShareTimes: '', // 分享后可获得抽奖次数
remainingTimes: '', // 当日剩余抽奖次数
loading: false,
modalKey: '',
rotateZ: 0,
lotteryInfo: {},
isLogin: false, // 是否登录
};
}
componentDidMount() {
if (!window.mmears_pv) {
lotteryService.lotteryPv(this.lotteryId);
window.mmears_pv = true;
}
this.loadData();
}
componentDidUpdate(prevProps, prevState) {
if (this.state.loading !== prevState.loading) {
if (this.state.loading) {
message.showLoading();
} else {
message.closeLoading();
}
}
}
/**
* @description 微信分享弹窗出现后 调用分享接口 成功后 获取个人信息
*/
handleWechatShare = async () => {
if (this.state.modalKey === MODAL_KEY.SHOW_WECHAT_SHARE) {
this.setState({
loading: true,
});
this.modalClose();
try {
await tools.delayEvent(100);
await lotteryService.lotteryShare(this.lotteryId);
await this.loadUserInfo();
} catch (e) {
console.error(e);
}
this.setState({loading: false});
}
};
/**
* @description 获取用户抽奖信息
*/
loadUserInfo = () => {
return lotteryService.getUserInfo(this.lotteryId).then(res => {
const {remainingShareTimes, remainingTimes} = res;
this.setState({
remainingShareTimes,
remainingTimes
});
});
};
/**
* @description 获取活动信息
*/
loadLotteryInfo = () => {
return lotteryService.getLotteryInfoById(this.lotteryId).then(res => {
document.title = res.name;
const lotteryStyleSheet = {};
if (res.bgImg) {
lotteryStyleSheet.backgroundImage = `url(${res.bgImg})`;
}
this.shareKey = Date.now() + 1;
this.setState({
lotteryInfo: {
...res,
prizeConfig: res.prizeConfig.sort((a, b) => Number(a.sort) - Number(b.sort))
},
lotteryStyleSheet,
shareOptions: {
...this.state.shareOptions,
title: res.shareTitle,
desc: res.shareDesc,
imgUrl: res.shareImgUrl,
}
});
this.props.configShareOptions(res, res.activityId);
}).catch(e => {
switch (e.code) {
case ERROR_CODE.BIZ_LUCKY_DRAW_NO_ACTIVITY: {
return myToast.warning('没有这个抽奖活动');
}
}
});
};
/**
* @description 加载数据
*/
loadData = async () => {
this.setState({
loading: true
});
const isLogin = await authService.checkLogin();
const allPromise = [this.loadLotteryInfo()];
if (isLogin) {
// 如果已经登录了 获取用户信息
allPromise.push(this.loadUserInfo());
}
Promise.all(allPromise).then(() => {
this.setState({
loading: false,
isLogin
});
}).catch(() => {
this.setState({
loading: false,
isLogin
});
});
};
/**
* @description 重置抽奖角度
*/
resetRotateZ = () => {
this.plateRef.style.transitionDuration = '0s';
this.plateRef.style.OTransitionDuration = '0s';
this.plateRef.style.MozTransitionDuration = '0s';
this.plateRef.style.WebkitTransitionDuration = '0s';
this.setState({
rotateZ: 0,
});
};
/**
* @description 转盘动画结束事件
*/
transitionEnd = () => {
this.isAllow = true;
this.setState({
modalKey: MODAL_KEY.WINNING
}, () => {
this.resetRotateZ();
this.winnerListKey = Date.now();
});
};
/**
* @description 关闭模态框
*/
modalClose = () => {
this.setState({
modalKey: ''
});
};
/**
* @description 诱导分享
*/
handleShowShare = () => {
this.setState({
modalKey: MODAL_KEY.SHOW_WECHAT_SHARE
});
};
/**
* @description 登录成功后的回调
*/
loginSuccess = () => {
this.loadUserInfo().then(() => {
this.setState({isLogin: true});
this.modalClose();
});
};
/**
* @description 跳转到中奖结果页面
*/
handleToprize = () => {
if (!this.state.isLogin) {
return this.setState({
modalKey: MODAL_KEY.LOGIN,
});
}
let url = `/lottery/prize/${this.lotteryId}`;
this.handleNavigatorTo(url)();
};
/**
* @description 渲染模态框
*/
renderModal = () => {
const {modalKey, lotteryInfo} = this.state;
switch (modalKey) {
case MODAL_KEY.RULE: {
return <Modal
onClose={this.modalClose}
title={'活动规则'}
>
<div className={styles.modalRule}>
<img src={lotteryInfo.ruleImg} alt={'rule'}/>
</div>
</Modal>;
}
case MODAL_KEY.LOGIN: {
return <ModalLogin
onCancel={this.modalClose}
onOk={this.loginSuccess}
/>;
}
case MODAL_KEY.WAITER: {
return <Modal
title={'咨询客服'}
onClose={this.modalClose}
>
<div className={styles.modalWaiter}>
<img src={wechatLogo} alt={'wechat'}/>
<p>长按识别二维码</p>
<article>客服时间:9:00 ~ 21:00</article>
</div>
</Modal>;
}
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_START: {
let diff = String(Math.ceil((lotteryInfo.startTime - Date.now()) / 1000 / 60 / 60 / 24));
if (diff.length === 1) {
diff = '0' + diff;
}
return <Modal title={'提示'} onClose={this.modalClose}>
<div className={styles.modalNotBegin}>
<p>亲,活动还未开始哦,距离抽奖时间还有</p>
<div className={styles.time}>
<p className={styles.wrapper}>
{diff.split('').map((item, key) => {
return <span key={`diff-${key}`}>{item}</span>;
})}
</p>
<p className={styles.desc}>/天</p>
</div>
<article>敬请期待哦~</article>
</div>
</Modal>;
}
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_HAS_END: {
return <Modal
title={'活动已结束'}
onClose={this.modalClose}
>
<div className={styles.modalEnd}>
<p>啊哦~抽奖活动已经结束啦</p>
<p>更多精彩活动关注“少儿英语专业启蒙”服务号</p>
<img src={wechatLogo} alt={'wechat'}/>
<article>长按识别二维码</article>
</div>
</Modal>;
}
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_ONLINE: {
return <Modal title={'提示'} onClose={this.modalClose}>
<div className={styles.modalBeginOffline}>
<p>亲,活动还未上线,请耐心等待~</p>
<img src={wechatLogo} alt={'wechat'}/>
<article>关注“少儿英语专业启蒙”服务号,可查看更多哦 !</article>
</div>
</Modal>;
}
case MODAL_KEY.SHOW_WECHAT_SHARE: {
return <ShareLayer onCancel={this.modalClose}/>;
}
case MODAL_KEY.WINNING: {
return this.renderShakeModal();
}
case MODAL_KEY.LOTTERY_NUM_NONE: {
return <Modal title={'温馨提示'} onClose={this.modalClose}>
<div className={styles.num_none}>
<img src={weepRabbit} alt="weep"/>
<p>{lotteryInfo.luckyDailyLimit}次抽奖机会已用完,分享朋友圈可再抽 1 次</p>
<div className={styles.modalFooter}>
<div className={styles.confirmBtn} onClick={this.handleShowShare}>分享再抽一次</div>
</div>
</div>
</Modal>;
}
case MODAL_KEY.LOTTERY_SHARE_NUM_NONE: {
return <Modal title={'今天抽奖机会用完啦'} onClose={this.modalClose}>
<div className={styles.share_num_none}>
<img src={packageImage} alt=""/>
<p>明天再来吧~</p>
</div>
</Modal>;
}
}
return null;
};
/**
* @description 抽奖的modal
*/
renderShakeModal = () => {
const {lotteryResult, lotteryInfo, remainingTimes, remainingShareTimes} = this.state;
const actions = [];
let content = null;
let afterFooter = null;
let title = '';
const shareAndAgain = <div
key={'shareAndAgain'}
className={styles.confirmBtn}
onClick={this.handleShowShare}>
分享再抽一次
</div>;
const again = <div
className={styles.confirmBtn}
key={'again'}
onClick={() => {
this.setState({modalKey: ''});
this.handleShake();
}}>
再抽一次
</div>;
switch (lotteryResult.prizeType) {
case PRIZE_TYPE.TRAIL_COURSE: {
title = '恭喜您中奖啦';
actions.push(<div
key={'booking'}
className={styles.cancelBtn}
onClick={this.handleNavigatorTo(appConfig.resources.bookingUrl, 'location')}
>
去约课
</div>);
if (remainingTimes > 0) {
actions.push(again);
} else if (remainingShareTimes > 0) {
actions.push(shareAndAgain);
}
content = <div className={styles.shakeTrailCourse}>
<img src={lotteryResult.prizeImg} alt=""/>
<p>{lotteryResult.name}</p>
</div>;
break;
}
case PRIZE_TYPE.NO_PRIZE: {
title = '哎呀,差点就中奖了';
content = <div className={styles.no_prize}>
<img src={weepRabbit} alt=""/>
</div>;
if (remainingTimes === 0 && remainingShareTimes === 0) {
content = <div className={styles.no_prize}>
<img src={weepRabbit} alt=""/>
</div>;
afterFooter = <p className={styles.afterFooter}>今天的抽奖机会已经用完啦,明天再来吧~</p>;
} else if (remainingTimes > 0) {
actions.push(again);
} else if (remainingShareTimes > 0) {
actions.push(shareAndAgain);
}
break;
}
case PRIZE_TYPE.PRIZE: {
title = '恭喜您中奖啦';
let showTips = false;
let show_none = false;
if (remainingTimes <= 0 && remainingShareTimes <= 0) {
show_none = true;
} else if (remainingTimes <= 0 && remainingShareTimes > 0) {
showTips = true;
}
actions.push(<div
key={'look'}
className={classNames({
[styles.cancelBtn]: remainingShareTimes > 0,
[styles.confirmBtn]: remainingShareTimes <= 0,
})}
onClick={this.handleToprize}
>查看奖品
</div>);
if (remainingTimes > 0) {
actions.push(again);
} else if (remainingShareTimes > 0) {
actions.push(shareAndAgain);
}
content = <div className={styles.prize}>
<img src={lotteryResult.prizeImg} alt=""/>
<p>{lotteryResult.name}</p>
</div>;
afterFooter = <article className={styles.afterFooter}>
{showTips && `${lotteryInfo.luckyDailyLimit}次抽奖机会已用完,分享朋友圈可再抽 1 次`}
{show_none && `今天的抽奖机会已经用完啦,明天再来吧~`}
</article>;
break;
}
}
return <Modal
title={title}
onClose={this.modalClose}
>
{content}
{actions.length > 0 &&
<div className={styles.modalFooter}>
{actions}
</div>}
{afterFooter}
</Modal>;
};
/**
* @description 抽奖 先判断 活动状态 后判断 登录状态
*/
handleShake = async () => {
if (!this.isAllow) return;
const {lotteryInfo: {prizeConfig}} = this.state;
if (!prizeConfig) {
await this.loadData();
}
this.isAllow = false;
this.setState({
loading: true,
lotteryResult: {}
});
lotteryService.getLotteryDraw(this.lotteryId).then(res => {
this.loadUserInfo().then(() => {
const {lotteryInfo: {prizeConfig}} = this.state;
const updateState = {
loading: false,
lotteryResult: res || {}
};
this.setState(updateState);
let lotteryIndex;
prizeConfig.forEach((item, index) => {
if (item.prizeId === res.id) {
lotteryIndex = index;
}
});
const deg = lotteryIndex * 360 / prizeConfig.length;
// 2520 + 计算出来的角度
this.plateRef.style.transitionDuration = '5s';
this.plateRef.style.OTransitionDuration = '5s';
this.plateRef.style.MozTransitionDuration = '5s';
this.plateRef.style.WebkitTransitionDuration = '5s';
this.setState(() => ({
rotateZ: 2520 + deg,
}));
});
}).catch(e => {
this.isAllow = true;
this.setState({
loading: false
});
switch (e.code) {
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_START: {
return this.setState({
modalKey: ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_START, // 未开始
});
}
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_ONLINE: {
return this.setState({
modalKey: ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_NOT_ONLINE, // 开始 并 下线
});
}
case ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_HAS_END: {
return this.setState({
modalKey: ERROR_CODE.BIZ_LUCKY_DRAW_ACTIVITY_HAS_END, // 结束
});
}
case ERROR_CODE.LOGIN_REQUIRED: {
return this.setState({
modalKey: MODAL_KEY.LOGIN
});
}
case ERROR_CODE.BIZ_LUCKY_DRAW_NOT_COUNT_AND_HAVE_SHARECOUNT: {
return this.setState({
modalKey: MODAL_KEY.LOTTERY_NUM_NONE
});
}
case ERROR_CODE.BIZ_LUCKY_DRAW_NOT_COUNT_AND_NO_SHARECOUNT: {
return this.setState({
modalKey: MODAL_KEY.LOTTERY_SHARE_NUM_NONE
});
}
default: {
return message.error(e.msg);
}
}
});
};
/**
* @description 设置模态框的key值
* @param modalKey
* @return {Function}
*/
handleSetModalKey = modalKey => () => {
this.setState({
modalKey
});
};
/**
* @description 跳转链接
* @param url 链接
* @param mode 模式
* @return {Function}
*/
handleNavigatorTo = (url, mode = 'push') => () => {
const {rf} = this.params;
if (rf) {
url += `?rf=${rf}`;
}
if (mode === 'location') {
location.href = url;
return;
}
this.props.history[mode](url);
};
/**
* @description 如果是微信环境 设置分享 不然不设置
* @return {component}
*/
renderWechatConfig = () => {
if (this.isWechat) {
return <WechatConfig showShare key={this.shareKey} shareOptions={this.state.shareOptions}/>;
}
return null;
};
render() {
const {rotateZ, lotteryInfo, remainingTimes, lotteryStyleSheet, isLogin} = this.state;
let maxNum = Number(lotteryInfo.shareLimit) + Number(lotteryInfo.luckyDailyLimit);
if (isNaN(maxNum)) {
maxNum = 0;
}
return (
<div className={styles.lottery} style={lotteryStyleSheet}>
{this.renderModal()}
<div className={styles.rule} onClick={this.handleSetModalKey(MODAL_KEY.RULE)}>
<img src={rule} alt={'rule'}/>
</div>
<div className={styles.plateWrapper}>
<div
className={styles.plate}
onTransitionEnd={this.transitionEnd}
ref={ref => {
this.plateRef = ref;
}}
style={{
transform: `rotateZ(${rotateZ}deg)`,
MSTransform: `rotateZ(${rotateZ}deg)`,
MozTransform: `rotateZ(${rotateZ}deg)`,
WebkitTransform: `rotateZ(${rotateZ}deg)`,
OTransform: `rotateZ(${rotateZ}deg)`,
}}
>
<img src={lotteryInfo.wheelImg || plate_8} alt={'plate'}/>
<div className={classNames({
[styles.awards_8]: lotteryInfo.prizeNum === 8,
[styles.awards_6]: lotteryInfo.prizeNum === 6,
})}>
{lotteryInfo.prizeConfig &&
lotteryInfo.prizeConfig.length > 0 &&
lotteryInfo.prizeConfig.map(item => {
return (
<div
key={item.prizeId}
>
<p>{item.name}</p>
<img src={item.wheelIcon} alt=""/>
</div>
);
})}
</div>
</div>
<div
className={styles.pointer}
onClick={this.handleShake}
>
<div/>
</div>
</div>
<div className={styles.tips}>
<div className={styles.last}>
今天还有
<span>{isLogin ? remainingTimes : lotteryInfo.luckyDailyLimit}</span>
次抽奖机会
</div>
<div className={styles.message}>
(每天{lotteryInfo.luckyDailyLimit}次抽奖机会,分享朋友圈多得{lotteryInfo.shareLimit}次,每天最多抽{maxNum}次)
</div>
</div>
<div className={styles.actions}>
<div className={styles.waiter} onClick={this.handleSetModalKey(MODAL_KEY.WAITER)} alt="咨询客服"/>
<div className={styles.view} onClick={this.handleToprize} alt="查看我的中奖结果"/>
</div>
<WinnerList key={this.winnerListKey} luckyListImg={lotteryInfo.luckyListImg}/>
{this.renderWechatConfig()}
</div>
);
}
}