Commit 129ec776 authored by wanghuan's avatar wanghuan

Merge branch 'c_client_taro-pack' of...

Merge branch 'c_client_taro-pack' of http://gitlab2.dui88.com/qinhaitao/taobao-mini-template into c_client_taro-pack
parents 14f8514e bc01f0ad
...@@ -4,7 +4,8 @@ export default { ...@@ -4,7 +4,8 @@ export default {
'pages/packageGood/browseGoods/browseGoods', 'pages/packageGood/browseGoods/browseGoods',
'pages/packageGood/collectGoods/collectGoods', 'pages/packageGood/collectGoods/collectGoods',
'pages/packageGood/orderGoods/orderGoods', 'pages/packageGood/orderGoods/orderGoods',
'pages/packageGood/cartGoods/cartGoods' 'pages/packageGood/cartGoods/cartGoods',
'pages/preComp/preComp'
], ],
subPackages: [ subPackages: [
{ {
......
...@@ -3,14 +3,15 @@ import React from 'react' ...@@ -3,14 +3,15 @@ import React from 'react'
import styles from './ContainerFit.module.less' import styles from './ContainerFit.module.less'
export default function ContainerFit(props) { export default function ContainerFit(props) {
const { bg = ''} = props const { bg = '', hasFitPsd = false } = props
return ( return (
<View className={styles['page-container']}> <View className={styles['page-container']}>
<View className={styles['page-psd-container']} style={{ background: `url(${bg}) no-repeat`, backgroundSize: '7.5rem 16.24rem' }}> <View className={styles['page-psd-container']} style={{ background: `url(${bg}) no-repeat`, backgroundSize: '7.5rem 16.24rem' }}>
<View className={styles['page-content']}> {!hasFitPsd && <View className={styles['page-content']}>
{props.children} {props.children}
</View> </View>}
{hasFitPsd && props.children}
</View> </View>
</View> </View>
) )
......
# 垂直弹幕参数
| 参数 | 说明 | 类型 | 默认值 |
| :------------------------- | :------------- | :------ | :----- |
| dataList | 弹幕列表 | String[] | - |
| barrageNum | 弹幕循环数量 | Number | 30 |
| quantity | 弹幕同时显示数量 | Number | 2 |
## 垂直弹幕使用步骤
1. 引入VerticalBarrage
2. 直接进入文件的<View className={styles.text}>{item}</View>处,定制自己需要的样式
# 横向弹幕参数
| 参数 | 说明 | 类型 | 默认值 |
| :------------------------- | :------------- | :------ | :----- |
| dataList | 弹幕列表 | String[] | - |
| trackCount | 弹幕轨道数量 | Number | 1 |
## 横向弹幕使用步骤
1. 引入Barrage
2. 直接进入文件的<View className={styles.text}>{item}</View>处,定制自己需要的样式
\ No newline at end of file
import React from 'react'
import { View, Text } from '@tarojs/components'
import styles from './Barrage.module.less'
class Barrage extends React.Component {
constructor(props) {
super(props)
// 页面数据存储
this.state = {
barrageWay: [],
barrageList: []
}
this.timer = null
}
componentDidMount() {
this.createData()
const self = this
setTimeout(() => {
self.addBarrageListObj()
}, 200)
}
componentWillUnmount() {
clearInterval(this.timer)
}
createData() {
const { dataList, trackCount = 1 } = this.props
const Tracks = Array.from(
{ length: trackCount },
(v, k) => (k + 1) * 40 - 40
)
this.setState({
barrageList: dataList.map((item, index) => ({
width: item.length * 17 + 5,
top: Tracks[index < Tracks.length ? index : index % trackCount],
time: 5,
context: item
}))
})
}
/* *
* 因为从后台获取到的是全部的数据,所以要把数据分开,让每条数据有先后之分
* 每隔一秒往barrageList 数组插入一条数据
* */
addBarrageListObj() {
const self = this
const { barrageList, barrageWay } = this.state
let i = 0
this.timer = setInterval(function () {
barrageWay.push(barrageList[i])
self.setState({
barrageWay: barrageWay
})
i++
if (i === barrageList.length - 1) {
if (self.props.Infinite) {
i = 0
} else {
clearInterval(self.timer)
}
}
}, 1500)
}
render() {
const { barrageWay } = this.state
return (
<View className={styles['barrage-fly']}>
{barrageWay.map((item, i) => {
if (!item?.context) return null
return (
<View
key={i}
className={styles['barrage-textFly']}
style={`animation: ${styles.first} ${item.time}s linear forwards; top: ${item.top}px`}
>
{/* 弹幕内容 */}
<Text className={styles['barrage-text']}>{item.context}</Text>
</View>
)
})}
</View>
)
}
}
export default Barrage
.barrage-fly {
position: relative;
height: 100%;
width: 700px;
z-index: 3;
.barrage-textFly {
position: absolute;
height: 64px;
line-height: 64px;
color: #f9c797;
font-size: 32px;
padding-right: 30px;
}
.barrage-text {
white-space: nowrap;
}
}
@keyframes first {
from {
left: 100%;
}
to {
left: -100%;
}
}
import React, { useState, useMemo, useEffect, useRef, useCallback } from 'react'
import { View } from '@tarojs/components'
import Taro, { useReady } from '@tarojs/taro'
import styles from './VerticalBarrage.module.less'
const animation = Taro.createAnimation({
transformOrigin: 'top right',
duration: 850,
timeFunction: 'ease-in-out',
delay: 150
})
const VerticalBarrage = (props) => {
const { dataList, barrageNum = 30, quantity = 2 } = props
const [ height, setHeight ] = useState(0)
const [ animationData, setAnimationData ] = useState(null)
const nowIndex = useRef(0)
const timer = useRef(null)
useReady(() => {
const query = Taro.createSelectorQuery()
query.select('#barrage_0').boundingClientRect().exec((res) => {
console.log(res)
const h = res[0].height
setHeight(h)
})
})
const barrageList = useMemo(() => {
if (!dataList.length) return []
if (barrageNum && dataList.length < barrageNum) {
let reslut = [ ...dataList ]
while (reslut.length < barrageNum) {
reslut = [ ...reslut, ...dataList ]
}
return [ ...reslut.slice(0, barrageNum), ...reslut.slice(0, quantity) ]
} else {
return [ ...dataList.slice(0, barrageNum), ...dataList.slice(0, quantity) ]
}
}, [ dataList ])
const callback = useCallback(() => {
timer.current = setInterval(() => {
const data = animation.translateY(-nowIndex.current * height).step()
setAnimationData(data.export())
if (nowIndex.current < barrageList.length - quantity) {
nowIndex.current = nowIndex.current + 1
} else {
nowIndex.current = 0
}
}, 1000)
}, [ barrageList, height ])
useEffect(() => {
callback()
return () => clearInterval(timer.current)
}, [ callback ])
// 控制淡入淡出
const barrageStyle = (index) => {
if (quantity === 1) {
return `${(nowIndex.current === index && nowIndex.current !== 0) ? styles.in : ''} ${(nowIndex.current - 1 === index) ? styles.out : ''}`
} else {
return `${(nowIndex.current + quantity - 1 === index && nowIndex.current !== 0) ? styles.in : ''} ${nowIndex.current - 1 === index ? styles.out : ''}`
}
}
return (
<View className={styles['barrage-container']} style={{ height: height * quantity }}>
<View
className={styles['barrage-box']}
animation={animationData}
style={nowIndex.current === 0 && { transform: 'translateY(0)' }}
>
{
barrageList.map((item, i) => (
<View key={`barrage-${i}`} id={`barrage_${i}`} className={barrageStyle(i)}>
<View className={styles.text}>{item}</View>
</View>
))
}
</View>
</View>
)
}
export default VerticalBarrage
.barrage-container {
border: 1px solid red;
overflow: hidden;
}
.barrage-box {
z-index: 1;
.text {
padding: 10px 0;
}
}
.in {
animation: fadeIn 1.5s;
animation-fill-mode: forwards;
}
.out {
animation: fadeOut 1s;
animation-fill-mode: forwards;
}
@keyframes fadeIn {
0% {
opacity: 0;
}
100% {
opacity: 1;
}
}
@keyframes fadeOut {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
\ No newline at end of file
import VerticalBarrage from './VerticalBarrage/VerticalBarrage'
import Barrage from './HorizontalBarrage/Barrage'
export {
VerticalBarrage,
Barrage
}
import React, { useState, useEffect, useRef } from 'react' import React from 'react'
import { View, Text } from '@tarojs/components' import { View, Text } from '@tarojs/components'
import { useDidShow, useDidHide } from '@tarojs/taro'
import tbcc from 'tbcc-sdk-ts' import tbcc from 'tbcc-sdk-ts'
import './CountDown.less' import './Countdown.less'
const { getServerTime } = tbcc.tb const { getServerTime } = tbcc.tb
export default function CountDown(props) { export default class Countdown extends React.Component {
const { endTime, startTime, onUpdate, type = 1, color = '#000', bgColor = 'transparent', fontSize = '26rpx', padding = '0' } = props static defaultProps = {
const [countDown, setCountDown] = useState(type === 1 ? ['00', ':', '00', ':', '00'] : ['00', '天', '00', '时', '00', '分', '00', '秒']) targetTime: '', // 以时间来进行倒计时
const [nowTime, setNowTime] = useState(startTime || Date.now()) startTime: '', // 开始时间
const countTimer = useRef(null) count: '', // 以秒数来进行倒计时
const isAccessRender = useRef(false)
// targetTime 模式下生效
showText: false, // 显示时分秒
showDay: false, // 显示天数
symbol: ':', // 间隔符号
isClose: false, // 手动关闭倒计时
// 共用事件
onTick: () => { }, // 倒计时过程事件
onEnd: () => { } // 倒计时结束事件
};
constructor() {
super(...arguments)
this.state = {
day: '0',
hour: '00',
minute: '00',
second: '00',
countText: '0'
}
this.targetTimestamp = null
this.startTimestamp = null
this.timer = null
}
componentDidMount() {
const { targetTime, count } = this.props
if (targetTime) {
this.formatTargetTime(targetTime)
} else if (count) {
this.setCountdown(count)
}
}
UNSAFE_componentWillReceiveProps(nextProps) {
const { targetTime, count } = nextProps
if (targetTime && targetTime !== this.props.targetTime) {
this.formatTargetTime(targetTime)
} else if (count && count !== this.props.count) {
clearInterval(this.timer)
this.setCountdown(count)
}
}
componentWillUnmount() {
this.targetTimestamp = null
clearInterval(this.timer)
}
componentDidHide() {
this.targetTimestamp = null
clearInterval(this.timer)
}
useEffect(() => { componentDidShow() {
countTimeFn() const { targetTime, count } = this.props
return () => clearInterval(countTimer.current) if (targetTime) {
}, [endTime, nowTime]) this.formatTargetTime(targetTime)
} else if (count) {
this.setCountdown(count)
}
}
useDidShow(() => { setCountdown(count) {
if(isAccessRender.current) { if (count <= 0) {
setNowTime(startTime || Date.now()) return
} }
isAccessRender.current = true let second = count
this.setState({
countText: second
}) })
this.timer = setInterval(() => {
second--
this.setState({
countText: second
})
this.props.onTick && this.props.onTick(second)
if (second <= 0) {
clearInterval(this.timer)
this.onTimeEnd()
}
}, 1000)
}
// 处理日期格式
formatTargetTime(targetTime) {
if (!targetTime) {
return
}
// 避免iOS端上的日期格式有问题
const time = targetTime.replace(/-/g, '/')
this.targetTimestamp = new Date(time).getTime()
this.getRemainingSecond()
}
const countTimeFn = async () => { // 计算剩余时间秒数
const _nowTime = await getServerTime() async getRemainingSecond() {
if (!this.targetTimestamp) return
let diffTime = endTime - (startTime || _nowTime) // 当前时间
countTimer.current = setInterval(() => { const currentTimestamp = await getServerTime()
if (diffTime > 1000) { // 剩余时间
let day = Math.floor(diffTime / (3600 * 1000) / 24) const remainingSecond = Math.floor((this.targetTimestamp - currentTimestamp) / 1000)
let hour = Math.floor((diffTime / 1000 / 3600) % 24) // 天 时 分 秒
let minute = Math.floor((diffTime / 1000 / 60) % 60) let day = ''
let second = Math.floor(diffTime / 1000 % 60) let hour = ''
day = day < 10 ? '0' + day : day let minute = ''
hour = hour < 10 ? '0' + hour : hour let second = ''
minute = minute < 10 ? '0' + minute : minute if (remainingSecond > 0 && !this.props.isClose) {
second = second < 10 ? '0' + second : second day = this.formatNum(parseInt(remainingSecond / 86400))
setCountDown(type === 1 ? [hour, ':', minute, ':', second] : [day, '天', hour, '时', minute, '分', second, '秒']) hour = this.props.showDay
diffTime -= 1000 ? this.formatNum(parseInt((remainingSecond % 86400) / 3600))
: this.formatNum(parseInt(remainingSecond / 3600))
minute = this.formatNum(parseInt((remainingSecond % 3600) / 60))
second = this.formatNum(parseInt((remainingSecond % 3600) % 60))
this.timeTick(remainingSecond)
} else { } else {
setCountDown(type === 1 ? ['00', ':', '00', ':', '00'] : ['00', '天', '00', '时', '00', '分', '00', '秒']) day = '0'
clearInterval(countTimer.current) hour = minute = second = '00'
onUpdate && onUpdate() this.onTimeEnd()
}
this.setTimeState(day, hour, minute, second)
}
// 设置时间
setTimeState(day, hour, minute, second) {
// 是否显示天时分秒文字
if (this.props.showText) {
hour += '时'
minute += '分'
second += '秒'
}
this.setState({
day,
hour,
minute,
second
})
} }
// 格式数字
formatNum(num) {
return num > 9 ? `${num}` : `0${num}`
}
// 倒计时过程事件
timeTick(remainingSecond) {
this.props.onTick && this.props.onTick(remainingSecond)
setTimeout(() => {
this.getRemainingSecond()
}, 1000) }, 1000)
} }
// 倒计时结束触发事件
onTimeEnd() {
this.targetTimestamp = null
this.props.onEnd && this.props.onEnd()
}
render() {
const { symbol, showDay, showText, className, targetTime } = this.props
const { day, hour, minute, second, countText } = this.state
// 末尾有空格
let countdownClass = 'countdown '
if (className) countdownClass += className
if (targetTime) {
return ( return (
<View className="count-down"> <View className={countdownClass}>
{ {showDay && day !== '00' && (
countDown.map((item, i) => { <Text>
return ( <Text className='day'>{day}</Text>
<Text className="count-down-time" key={i} style={{ backgroundColor: item !== ':' ? bgColor : 'transparent', fontSize, color, padding }}>{item}</Text> <Text className='day-text'></Text>
</Text>
)}
<Text>
<Text className='hour'>{hour}</Text>
{!showText && <Text className='symbol'>{symbol}</Text>}
</Text>
<Text className='minute'>{minute}</Text>
{!showText && <Text className='symbol'>{symbol}</Text>}
<Text className='second'>{second}</Text>
</View>
) )
})
} }
return (
<View className={countdownClass}>
<Text className='second'>{countText}</Text>
</View> </View>
) )
}
} }
.count-down { .countdown {
display: flex; display: inline-block;
align-items: center; box-sizing: border-box;
}
.count-down-time {
border-radius: 4rpx;
} }
\ No newline at end of file
## 参数
| 参数 | 说明 | 类型 | 默认值 | 注意 |
| :------------------------- | :------------- | :------ | :----- | :------ |
| targetTime | 目标时间 | String | - | 优先级比count高 |
| count | 倒计秒数 | Number | - | - |
| 以下为使用targetTime 生效 |
| symbol | 间隔符号 | String | - | - |
| showDay | 是否显示天 | Boolean | false | 配合showText同时搭配 |
| showText | 是否显示时分秒 | Boolean | false | 打开自动无视symbol |
| isClose | 是否关闭倒计时 | Boolean | false | - |
## 事件
| 事件名称 | 说明 | 返回参数 |
| :------- | :--------------- | :--------- |
| onTick | 倒计时过程事件 | 剩余的秒数 |
| onEnd | 倒计时结束时触发 | - |
## 实例
```jsx
<CounDown targetTime="2021-10-01 09:00:00">
```
import Countdown from './CountDown'
export default Countdown
import React, { useState, useEffect, useRef } from 'react'
import { View, Text } from '@tarojs/components'
import { useDidShow, useDidHide } from '@tarojs/taro'
import tbcc from 'tbcc-sdk-ts'
import './CountDown.less'
const { getServerTime } = tbcc.tb
export default function CountDown(props) {
const { endTime, startTime, onUpdate, type = 1, color = '#000', bgColor = 'transparent', fontSize = '26rpx', padding = '0' } = props
const [countDown, setCountDown] = useState(type === 1 ? ['00', ':', '00', ':', '00'] : ['00', '天', '00', '时', '00', '分', '00', '秒'])
const [nowTime, setNowTime] = useState(startTime || Date.now())
const countTimer = useRef(null)
const isAccessRender = useRef(false)
useEffect(() => {
countTimeFn()
return () => clearInterval(countTimer.current)
}, [endTime, nowTime])
useDidShow(() => {
if(isAccessRender.current) {
setNowTime(startTime || Date.now())
}
isAccessRender.current = true
})
const countTimeFn = async () => {
const _nowTime = await getServerTime()
let diffTime = endTime - (startTime || _nowTime)
countTimer.current = setInterval(() => {
if (diffTime > 1000) {
let day = Math.floor(diffTime / (3600 * 1000) / 24)
let hour = Math.floor((diffTime / 1000 / 3600) % 24)
let minute = Math.floor((diffTime / 1000 / 60) % 60)
let second = Math.floor(diffTime / 1000 % 60)
day = day < 10 ? '0' + day : day
hour = hour < 10 ? '0' + hour : hour
minute = minute < 10 ? '0' + minute : minute
second = second < 10 ? '0' + second : second
setCountDown(type === 1 ? [hour, ':', minute, ':', second] : [day, '天', hour, '时', minute, '分', second, '秒'])
diffTime -= 1000
} else {
setCountDown(type === 1 ? ['00', ':', '00', ':', '00'] : ['00', '天', '00', '时', '00', '分', '00', '秒'])
clearInterval(countTimer.current)
onUpdate && onUpdate()
}
}, 1000)
}
return (
<View className="count-down">
{
countDown.map((item, i) => {
return (
<Text className="count-down-time" key={i} style={{ backgroundColor: item !== ':' ? bgColor : 'transparent', fontSize, color, padding }}>{item}</Text>
)
})
}
</View>
)
}
\ No newline at end of file
.count-down {
display: flex;
align-items: center;
}
.count-down-time {
border-radius: 4rpx;
}
\ No newline at end of file
import React, { useState } from 'react'
import { View, Image, ScrollView } from '@tarojs/components'
import Taro, { useShareAppMessage, useDidShow } from '@tarojs/taro'
import classnames from 'classnames'
import styles from './Swiper.module.less'
function Swiper(props) {
return (
<>
</>
)
}
export default Swiper
\ No newline at end of file
...@@ -7,34 +7,8 @@ import API from '@/api' ...@@ -7,34 +7,8 @@ import API from '@/api'
import { useLoginInfoModel, useActivityInfoModel } from '@/store' import { useLoginInfoModel, useActivityInfoModel } from '@/store'
import { checkIsMember } from 'tbcc-sdk-ts/lib/utils' import { checkIsMember } from 'tbcc-sdk-ts/lib/utils'
import { commonToast } from 'tbcc-sdk-ts/lib/core/tb' import { commonToast } from 'tbcc-sdk-ts/lib/core/tb'
import { HELP_MODAL_TYPE } from '@/const' import { HELP_MODAL_TYPE, HELP_CONFIG } from '@/config/help.config'
const helpConfig = {
1: {
width: 639,
height: 730,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_01.png',
title: '您的好友正在参与XXXX\n快来一起参与吧~',
marginBottom: 80
},
2: {
width: 639,
height: 701,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg_02.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_02.png',
title: '您已是会员',
marginBottom: 80
},
3: {
width: 639,
height: 800,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg_03.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_02.png',
title: '',
marginBottom: 120
}
}
export default function RuleModal(props) { export default function RuleModal(props) {
const { activityInfo } = useActivityInfoModel() const { activityInfo } = useActivityInfoModel()
const { type = HELP_MODAL_TYPE.HELP, onClose = () => {}, newVip = true, helpInfo = {} } = props const { type = HELP_MODAL_TYPE.HELP, onClose = () => {}, newVip = true, helpInfo = {} } = props
...@@ -104,16 +78,16 @@ export default function RuleModal(props) { ...@@ -104,16 +78,16 @@ export default function RuleModal(props) {
<View> <View>
<Modal hideCloseButton={false} onClose={onCloseModal} top={'50%'} closePos={{ right: 0, top: 0 }}> <Modal hideCloseButton={false} onClose={onCloseModal} top={'50%'} closePos={{ right: 0, top: 0 }}>
<View className={styles.container} style={ <View className={styles.container} style={
{ width: helpConfig[type].width / 100 + 'rem', { width: HELP_CONFIG[type].width / 100 + 'rem',
height: helpConfig[type].height / 100 + 'rem', height: HELP_CONFIG[type].height / 100 + 'rem',
backgroundImage: `url(${helpConfig[type].bg})` backgroundImage: `url(${HELP_CONFIG[type].bg})`
}}> }}>
<Text className={styles['help-title']}>{ <Text className={styles['help-title']}>{
type !== HELP_MODAL_TYPE.REWARDS ? helpConfig[type].title : type !== HELP_MODAL_TYPE.REWARDS ? HELP_CONFIG[type].title :
`恭喜你成功邀请${helpInfo.inviteCount}名好友\n获得XXX奖励` } `恭喜你成功邀请${helpInfo.inviteCount}名好友\n获得XXX奖励` }
</Text> </Text>
<Image src={helpConfig[type].btnTxt} <Image src={HELP_CONFIG[type].btnTxt}
style={{ marginBottom: helpConfig[type].marginBottom / 100 + 'rem' }} style={{ marginBottom: HELP_CONFIG[type].marginBottom / 100 + 'rem' }}
className={styles['help-btn']} onClick={() => onHandleHelp()} /> className={styles['help-btn']} onClick={() => onHandleHelp()} />
</View> </View>
</Modal> </Modal>
......
import React from 'react'
import { View, Text, Image } from '@tarojs/components'
import Modal from '@/components/_base/Modal/Modal'
import API from '@/api'
import tbcc from 'tbcc-sdk-ts'
import { useThrottle } from '@/hooks/useThrottle'
import './JackpotModal.less'
import useReceive from '@/hooks/useReceive'
const { receiveEnamePrize, receiveObjectPrize } = API
const { commonToast } = tbcc.tb
const JackpotModal = (props) => {
const { onClose, top = '50%', bg = '', width = 300, height = 300, prizesData = {}, receive = false } = props
const [ getReceive ] = useReceive({ receiveEnamePrize, receiveObjectPrize })
const handleClick = useThrottle(async() => {
if (receive) {
const prizeId = prizesData.id || prizesData._id
const type = prizesData.type
const result = await getReceive({ prizeId, type })
if (result) {
commonToast(result.message)
}
} else {
onClose()
}
})
return (
<Modal onClose={onClose} top={top}>
<View className='jackpot_content' style={{ width: `${width / 100}rem`, height: `${height / 100}rem`, backgroundImage: `url(${bg})` }}>
<View className='title_box'>
<Text className='title'>恭喜您</Text>
</View>
<Text className='notify'>抽到了以下奖品</Text>
<View className='gift_box'>
<View className='gift'>
<Image src={prizesData?.image} />
</View>
<Text className='gift_name'>{prizesData?.name}</Text>
</View>
<View className='btn' onTap={handleClick}>领取奖励</View>
<Text className='hint'>奖品可在<Text className='hint_hot'>“我的奖品”</Text>中查看</Text>
</View>
</Modal>
)
}
export default JackpotModal
.jackpot_content {
background-color: #FFF;
.image-property();
overflow: hidden;
display: flex;
flex-direction: column;
align-items: center;
box-shadow: inset 0.469px 0.883px 1px 0px rgba(249, 223, 203, 0.6);
.title_box {
display: flex;
justify-content: center;
align-items: center;
width: 322px;
height: 70px;
.title {
font-size: 36.364px;
color: #000
}
}
.notify {
margin-top: 45px;
}
.gift_box {
margin-top: 25px;
text-align: center;
.gift {
border-radius: 12px;
background-color: rgb(255, 244, 235);
width: 224px;
height: 225px;
overflow: hidden;
image {
width: 100%;
height: 100%;
}
}
.gift_name {
margin-top: 10px;
}
}
.btn {
margin-top: 40px;
width: 361px;
height: 100px;
display: flex;
justify-content: center;
align-items: center;
}
}
\ No newline at end of file
## 参数
| 参数 | 说明 | 类型 | 默认值 |
| :--------- | :----------------------------- | :------- | :----- |
| width | 宽度 | Number | - |
| height | 高度 | Number | - |
| top | 定位 | String | - |
| bg | 背景 | String | false |
| prizesData | 奖品数据 | Object | false |
| receive | 领取按钮是回到页面还是直接领取 | Boolean | false |
| onClose | 关闭按钮的回调 | Function | false |
### 注
```javascript
prizesData = {
_id: "奖品的id",
type: "奖品的类型",
image: "奖品图片url",
name: "奖品名字"
}
```
## useReceive 用法
```javascript
const [ getReceive ] = useReceive({ receiveEnamePrize, receiveObjectPrize })
// 引入useReceive Hooks,调用时传入receiveEnamePrize(优惠券和积分接口), receiveObjectPrize(实物接口),返回一个处理函数。
const result = await getReceive({ prizeId, type })
// 在用户领取时调用它,传入奖品id以及type(符合PRIZE_TYPE枚举格式),返回一个promise对象,处理完毕后成功或者用户身份验证失败等会返回对象(message, stest),如果是上阶段传入的领取接口失败则不返回任何信息。
```
\ No newline at end of file
import JackpotModal from './JackpotModal'
import useReceive from '@/hooks/useReceive'
export { useReceive }
export default JackpotModal
// 助力弹窗类型
export const HELP_MODAL_TYPE = {
HELP: 1, // 邀请助力
FAIL: 2, // 助力失败
REWARDS: 3, // 助力信息展示
}
// 助力弹窗是否已弹
export const HELP_MODAL_SHOW = {
SHOW: 1, // 已弹
NOT_SHOW: 2, // 未弹
}
// 助力配置
export const HELP_CONFIG = {
1: {
width: 639,
height: 730,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_01.png',
title: '您的好友正在参与XXXX\n快来一起参与吧~',
marginBottom: 80
},
2: {
width: 639,
height: 701,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg_02.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_02.png',
title: '您已是会员',
marginBottom: 80
},
3: {
width: 639,
height: 800,
bg: '//yun.dui88.com/taobaomini/pike_call/m_help_bg_03.png',
btnTxt: '//yun.dui88.com/taobaomini/pike_call/m_help_btn_02.png',
title: '',
marginBottom: 120
}
}
\ No newline at end of file
...@@ -14,17 +14,6 @@ export const ACTIVITY_STATUS = { ...@@ -14,17 +14,6 @@ export const ACTIVITY_STATUS = {
// 店铺ID // 店铺ID
export const SHOP_ID = '60014226' export const SHOP_ID = '60014226'
// 助力弹窗类型
export const HELP_MODAL_TYPE = {
HELP: 1, // 邀请助力
FAIL: 2, // 助力失败
REWARDS: 3, // 助力信息展示
}
// 助力弹窗是否已弹
export const HELP_MODAL_SHOW = {
SHOW: 1, // 已弹
NOT_SHOW: 2, // 未弹
}
/* 背景音乐 应用:牧场消消乐有效,其他应用需要重新上传文件 */ /* 背景音乐 应用:牧场消消乐有效,其他应用需要重新上传文件 */
export const BGMUSIC_URL = { export const BGMUSIC_URL = {
MUSIC:'cloud://FBE3C154661ACEEBA164E8B70B4D71E2/yoga bgm.mp3' MUSIC:'cloud://FBE3C154661ACEEBA164E8B70B4D71E2/yoga bgm.mp3'
......
import { useEffect, useState } from 'react' import { useEffect, useState, useReducer } from 'react'
import { useRouter } from '@tarojs/taro' import { useRouter } from '@tarojs/taro'
import { useLoginInfoModel } from '../store/loginInfo' import { useLoginInfoModel } from '../store/loginInfo'
import API from '../api' import API from '../api'
......
import { useCallback } from 'react'
import { checkIsMember } from 'tbcc-sdk-ts/lib/utils'
import tbccTs from 'tbcc-sdk-ts'
import { PRIZE_TYPE } from '@/const'
const { getUserAddress } = tbccTs.tb
const useReceive = (config) => {
const { receiveEnamePrize = () => { }, receiveObjectPrize = () => { } } = config
// 积分
const handleGetCredits = useCallback(async (id) => {
// 判断是否为会员
const isVip = await checkIsMember()
console.log(isVip)
if (!isVip) {
return {
message: '需加入会员才能领取成功哦',
state: 'error'
}
}
const { success, data } = await receiveEnamePrize({ id })
if (success && data) {
return {
message: '领取成功',
state: 'success'
}
}
}, [checkIsMember, receiveEnamePrize])
// 优惠券
const handleGetEquity = useCallback(async (id) => {
const { success, data } = await receiveEnamePrize({ id })
if (success && data) {
return {
message: '领取成功',
state: '领取成功'
}
}
}, [receiveEnamePrize])
// 实物
const handleReceiveObjectPrize = useCallback(async (params) => {
let errorMessage = ''
const { success, data } = await receiveObjectPrize(params).catch(res => {
errorMessage = res && res.message
}) || {}
if (success && data) {
return {
message: '领取成功',
state: 'success'
}
} else {
return {
message: errorMessage,
state: 'error'
}
}
}, [receiveObjectPrize])
// 确认地址
const handleChooseAddress = useCallback(async (id) => {
let errorMessage = ''
const userAddress = await getUserAddress().catch(err => {
errorMessage = err && err.errorMessage
})
if (!userAddress) {
return {
message: errorMessage,
state: 'error'
}
}
const { name, telNumber, provinceName, cityName, cityCode, countyName, detailInfo, streetName } = userAddress || {}
const params = {
name,
phone: telNumber,
addressDetail: detailInfo,
cityCode,
city: cityName,
province: provinceName,
area: countyName,
streetName,
id
}
const result = await my.confirm({
title: '提示',
content: '确认使用该收货地址:' + name + telNumber + userAddress.duibaAddress.address,
confirmButtonText: '确定',
cancelButtonText: '取消'
})
if (result.confirm) {
return await handleReceiveObjectPrize(params)
}
}, [getUserAddress])
// 导出的方法
const exportFn = useCallback(async ({ type, prizeId }) => {
// 领取优惠券
if (type === PRIZE_TYPE.ENAME) return await handleGetEquity(prizeId)
// 领取实物
if (type === PRIZE_TYPE.OBJECT) return await handleChooseAddress(prizeId)
// 领取积分
if (type === PRIZE_TYPE.CREDITS) return await handleGetCredits(prizeId)
}, [handleGetEquity, handleChooseAddress, handleGetCredits])
return [exportFn]
}
export default useReceive
...@@ -2,14 +2,15 @@ import React, { useRef, useState } from 'react' ...@@ -2,14 +2,15 @@ import React, { useRef, useState } from 'react'
import { View, Image } from '@tarojs/components' import { View, Image } from '@tarojs/components'
import Taro, { useShareAppMessage, useDidShow, getApp } from '@tarojs/taro' import Taro, { useShareAppMessage, useDidShow, getApp } from '@tarojs/taro'
import classnames from 'classnames' import classnames from 'classnames'
import { SHARE_CONFIG, HELP_MODAL_TYPE, HELP_MODAL_SHOW } from '@/const.js' import { SHARE_CONFIG } from '@/const.js'
import { HELP_MODAL_TYPE } from '@/config/help.config'
import { useLogin, useLoginFromShare } from '@/hooks/useLogin' import { useLogin, useLoginFromShare } from '@/hooks/useLogin'
import { useActivityInfoModel, useLoginInfoModel } from '@/store' import { useActivityInfoModel, useLoginInfoModel } from '@/store'
import API from '@/api' import API from '@/api'
import RuleModal from '@/components/_tb_modal/RuleModal/RuleModal' import RuleModal from '@/components/_tb_modal/RuleModal/RuleModal'
import DoHelpModal from '@/components/_tb_modal/DoHelpModal/DoHelpModal' import DoHelpModal from '@/components/_tb_modal/DoHelpModal/DoHelpModal'
import TasksModal from '@/components/_tb_modal/TasksModal/TasksModal' import TasksModal from '@/components/_tb_modal/TasksModal/TasksModal'
import CountDown from '@/components/_tb_comps/CountDown/CountDown' import CountDown from '@/components/_tb_comps/CountDown'
import styles from './index.module.less' import styles from './index.module.less'
import tbcc from 'tbcc-sdk-ts' import tbcc from 'tbcc-sdk-ts'
import { useEffect } from 'react' import { useEffect } from 'react'
...@@ -128,10 +129,12 @@ function Index() { ...@@ -128,10 +129,12 @@ function Index() {
// }) // })
},[]) },[])
// 授权登录完成 // 授权登录完成
// useLogin(async (info) => { useLogin(async (info) => {
// handleVisibleModal(info) console.warn(info)
// // setUpdateFlag(1) console.warn(loginInfo)
// }) handleVisibleModal(info)
// setUpdateFlag(1)
})
// 查看是否有助力信息 // 查看是否有助力信息
const getShareInfo = async () => { const getShareInfo = async () => {
const { success, data } = await API.getShareInfo() const { success, data } = await API.getShareInfo()
......
...@@ -4,20 +4,85 @@ import { useDidShow, useRouter, useDidHide, getApp } from '@tarojs/taro' ...@@ -4,20 +4,85 @@ import { useDidShow, useRouter, useDidHide, getApp } from '@tarojs/taro'
import API from '@/api' import API from '@/api'
import { useLogin, useLoginFromShare } from '@/hooks/useLogin' import { useLogin, useLoginFromShare } from '@/hooks/useLogin'
import { useActivityInfoModel, useLoginInfoModel } from '@/store' import { useActivityInfoModel, useLoginInfoModel } from '@/store'
import { prizeList } from '@/mock'
import styles from './preComp.module.less'
import {useAudio} from '@/hooks/useAudio' import {useAudio} from '@/hooks/useAudio'
import {CLOUD_OBJ, BGMUSIC_URL} from '@/const' import {CLOUD_OBJ, BGMUSIC_URL} from '@/const'
import ContainerFit from '@/components/_base/ContainerFit/ContainerFit'
import ScrollXView from '@/components/_tb_comps/ScrollXView/ScrollXView' import ScrollXView from '@/components/_tb_comps/ScrollXView/ScrollXView'
import SwiperView from '@/components/_tb_comps/SwiperView/SwiperView' import SwiperView from '@/components/_tb_comps/SwiperView/SwiperView'
import RotateWheel from '@/components/_tb_comps/RotateWheel/RotateWheel' import RotateWheel from '@/components/_tb_comps/RotateWheel/RotateWheel'
import RankTitle from '@/components/_tb_comps/Rank/RankTitle/RankTitle'
import RankList from '@/components/_tb_comps/Rank/RankList/RankList'
const rotateConfig = {
bg: 'https://yun.duiba.com.cn/spark/assets/8b6e920ffd09fab8f9ac2de09f9154879f4d0607.png',
ratio: 0.65,
radius: 300,
circles: 4,
divideNum: 8,
duration: 5000,
timeFunction:'ease-in-out',
nodeInfo:{
width:100,
height:100
},
imgInfo:{width:80,height:80},
showWay:'negative',//positive/negative
isShowPrizeName:true,
prizeNameWidthRatio:1.2
}
const SCROLLXVIEW_CONFIG = {
prizeList: [],
containerWidth : 200,
containerHeight : 200,
imgWidth:120,
imgHeight:120,
isShowPrizeName:true,
prizeInCenterNum:3,
marginRight:26,
backgroundColor:'#E7E7EF',
backgroundImage:''
}
const swiper_config = {
easingFunction:`linear`,
circular:true,
autoplay:true,
vertical:false,
duration:1000,
interval:1500,
disableTouch:false,
swiperGroup:{width:300,height:400},
swiperContent:{width:300,height:400},
imgContent:{width:200,height:200},
textContent:{width:300,height:60}
}
export default function PreComp(props) { export default function PreComp(props) {
return( return(
<View> <ContainerFit hasFitPsd={true}>
<View className={styles['scroll-view']}>
<ScrollXView prizeList={prizeList} />
</View>
<View className={styles['comp-view']}>
{/* 大转盘 */}
<RotateWheel />
</View>
<View className={styles['comp-view']}>
{/* swiper左右滑动 */}
<SwiperView swiperList={prizeList} />
</View> </View>
</ContainerFit>
) )
} }
\ No newline at end of file
.scroll-view {
margin-top: 208px;
}
.comp-view {
margin-top: 50px;
width: 100%;
height: auto;
}
\ No newline at end of file
import { useState } from 'react' import { useState, useReducer } from 'react'
import { createModel } from 'hox' import { createModel } from 'hox'
function useLoginInfo() { function useLoginInfo() {
...@@ -10,7 +10,6 @@ function useLoginInfo() { ...@@ -10,7 +10,6 @@ function useLoginInfo() {
avatar: '', avatar: '',
inviteId: '' inviteId: ''
}) })
return { return {
loginInfo, loginInfo,
setLoginInfo setLoginInfo
......
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