UNPKG

react-app-shell

Version:

react打包脚本和example, 这里的版本请忽略

687 lines (623 loc) 23.8 kB
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'; /** * 大转盘抽奖活动 */ @inject(({lotteryStore}) => ({ configShareOptions: lotteryStore.configShareOptions })) @checkUserAuth({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> ); } }