活动页面和1774

main
wwl 2024-04-23 19:01:43 +08:00
parent 113bd5f979
commit f1be6694c0
13 changed files with 888 additions and 222 deletions

View File

@ -19,6 +19,7 @@ const config = {
'pages/article/index', // 文章页面
'pages/recommend/list', // 推荐软文列表 现在改为活动介绍
'pages/recommend/detail', // 活动介绍
'pages/recommend/apply', // 报名信息
'pages/recommend/status', // 活动状态
'pages/other/goods', // 特殊商品页面
'pages/member/item-fav', // 收藏页面

View File

@ -10,13 +10,13 @@ function SpCheckboxNew (props) {
checked = false,
label,
onChange = () => { },
disabled = false
disabled = false,
isRadio = false
} = props
const [isChecked, setChecked] = useState(checked)
const onChangeCheckbox = () => {
console.log("🚀 ~ file: index.js:23 ~ disabled:", disabled)
if (disabled) return
setChecked(!isChecked)
onChange && onChange(!isChecked)
@ -36,7 +36,7 @@ function SpCheckboxNew (props) {
)}
onClick={onChangeCheckbox}
>
{/* <Text
{isRadio ? <Text
className={classNames(
{
iconfont: true
@ -44,18 +44,18 @@ function SpCheckboxNew (props) {
disabled ? 'icon-circle1' : isChecked ? 'icon-roundcheckfill' : 'icon-round',
disabled && isChecked && 'icon-roundcheckfill'
)}
></Text> */}
<Text
style={{ color: disabled ? '#ccc !important' : '#000' }}
className={classNames(
{
// iconfont: true,
"icon-my": true
},
disabled ? 'icon-checkbox-weixuan' : isChecked ? 'icon-checkbox-xuanzhong' : 'icon-checkbox-weixuan',
disabled && isChecked && 'icon-checkbox-xuanzhong'
)}
></Text>
: <Text
style={{ color: disabled ? '#ccc !important' : '#000' }}
className={classNames(
{
// iconfont: true,
"icon-my": true
},
disabled ? 'icon-checkbox-weixuan' : isChecked ? 'icon-checkbox-xuanzhong' : 'icon-checkbox-weixuan',
disabled && isChecked && 'icon-checkbox-xuanzhong'
)}
></Text>}
<View className='sp-checkbox-new__label'>{label || children}</View>
</View>
)

View File

@ -54,6 +54,7 @@ function SpPage (props, ref) {
showNavSearchIcon = false,
showLogoLoading = false,
alwaysBackUrl = '',
showNavBackIcon = true
} = props
let { renderTitle } = props
const wrapRef = useRef(null)
@ -298,7 +299,7 @@ function SpPage (props, ref) {
{/* <Image className="chazhao" src={require("@/assets/chazhao-light.png")}></Image> */}
{showCustomNavigation ? <SpImage onClick={() => Taro.navigateTo({ url: '/pages/item/list?showSearch=true' })} src={`member/chazhao-${isBlack ? "black" : "light"}.png`} height={34} mode='heightFix' isNew />
: <View className='icon-wrap'>
<Text
{showNavBackIcon && <Text
className={classNames('iconfont', {
// 'icon-home1': cusCurrentPage == 1,
'icon-fanhui': alwaysBackUrl ? true : cusCurrentPage != 1
@ -318,7 +319,7 @@ function SpPage (props, ref) {
Taro.navigateBack()
}
}}
/>
/>}
{showNavCartIcon ? cartCount > 0 ? <AtBadge value={cartCount} maxValue={99}><SpImage src={`member/cart.png`} onClick={() => Taro.redirectTo({ url: '/pages/cart/espier-index' })} height={36} mode='heightFix' isNew /></AtBadge> : <SpImage src={`member/cart.png`} onClick={() => Taro.redirectTo({ url: '/pages/cart/espier-index' })} height={36} mode='heightFix' isNew /> : null}
{showNavHomeIcon && <SpImage src={`cart/home.png`} onClick={() => Taro.redirectTo({ url: '/pages/index' })} height={36} mode='heightFix' isNew />}
{showNavSearchIcon && <SpImage onClick={() => Taro.navigateTo({ url: '/pages/item/list?showSearch=true' })} src={`member/chazhao-${isBlack ? "black" : "light"}.png`} height={34} mode='heightFix' isNew />}

View File

@ -43,16 +43,16 @@ import { useImmer } from 'use-immer'
import { useLogin, useNavigation } from '@/hooks'
import HomeWgts from './home/comps/home-wgts'
import { WgtHomeHeader, WgtHomeHeaderShop } from './home/wgts'
// import CompAddTip from './home/comps/comp-addtip'
// import CompFloatMenu from './home/comps/comp-floatmenu'
import CompAddTip from './home/comps/comp-addtip'
import CompFloatMenu from './home/comps/comp-floatmenu'
import './home/index.scss'
// const MCompAddTip = React.memo(CompAddTip)
const MCompAddTip = React.memo(CompAddTip)
const initialState = {
wgts: [],
showBackToTop: false,
loading: false,
loading: true,
searchComp: null,
pageData: null,
fixedTop: false,
@ -340,12 +340,12 @@ function Home () {
}
const getSwiperList = async () => {
// const { status, activity_info = {}, total_count } = await api.user.registrationActivity({ activity_id: 1 })
// const activeSwiper = activity_info.pics.map(item => ({
// type: 'image',
// src: item,
// goods: []
// }))
const { status, activity_info = {}, total_count } = await api.user.registrationActivity({ activity_id: 2 })
const activeSwiper = activity_info.pics.map(item => ({
type: 'image',
src: item,
goods: []
}))
const res = await api.shop.homeSwiperList({ page: 1, pageSize: 999 })
const list = (res?.list?.map((item) => {
return {
@ -367,15 +367,14 @@ function Home () {
}
}) || []).sort((a, b) => a.sort - b.sort)
setState((draft) => {
// draft.swiperList = [...activeSwiper, ...list]
draft.swiperList = list
draft.swiperList = [...activeSwiper, ...list]
draft.goodList = list[0].goods || []
draft.loading = false
// draft.activeInfo = {
// ...activity_info,
// total_count,
// status
// }
draft.activeInfo = {
...activity_info,
total_count,
status
}
})
}
@ -481,7 +480,7 @@ function Home () {
}, 500)
}
} else if (deltaY < 0) {
// if (currentIndex === 0) return
if (currentIndex === 0) return
// 上滑操作
setState((draft) => {
draft.showBottom = true
@ -525,12 +524,12 @@ function Home () {
const onSwiperChange = (e) => {
const { current } = e.detail
// if (current === 0) {
// setState((draft) => {
// draft.showBottom = false
// draft.isUpOperation = false
// })
// }
if (current === 0) {
setState((draft) => {
draft.showBottom = false
draft.isUpOperation = false
})
}
setState((draft) => {
draft.currentIndex = current
draft.goodList = swiperList[current].goods || []
@ -658,8 +657,10 @@ function Home () {
objectFit="cover"
style={{ width: "100%", height: "100%" }}
onPlay={() => {
}}
onEnded={() => {
}}
/>
)}
@ -670,17 +671,26 @@ function Home () {
<View className="item-btn-icon icon-my icon-arrow-right"></View>
</View>
</View>} */}
{item.type === "video" && <View className="mutedBtn" onClick={() => setState(v => { v.muted = !state.muted })} >
{!isUpOperation && item.type === "video" && <View className="mutedBtn" onClick={() => setState(v => { v.muted = !state.muted })} >
<Image className="muted-icon" src={`${process.env.APP_IMAGE_CDN_NEW}/index/${state.muted ? 'muted' : 'muted-no'}.jpg`}></Image>
</View>}
</SwiperItem>
))}
</Swiper>
{!isUpOperation && <>
<View className="item-img-box">
<View className="item-img-txt"> </View>
<Image className="item-img" height="62" src={require('../assets/i-sou.gif')} isShowMenuByLongpress={false} lazyLoad isNew={false} />
</View>
{currentIndex === 0 ? <View className="item-btns">
<View className="item-tit">{activeInfo.activity_name}</View>
{/* <SpLogin newUser={isNewUser} onChange={handleApply}> */}
{activeInfo.end_time * 1000 >= Date.now() && <View className="item-btn" style={{ padding: '30rpx 60rpx' }} onClick={() => handleApply()}>
<View className="item-btn-txt">{activeInfo.total_count ? '已报名' : '活动申请'}</View>
{/* <Image className="jiantou" mode="aspectFit" src={require('../assets/hengjiantou.gif')}></Image> */}
</View>}
{/* </SpLogin> */}
</View> :
<View className="item-img-box">
<View className="item-img-txt"> </View>
<Image className="item-img" height="62" src={require('../assets/i-sou.gif')} isShowMenuByLongpress={false} lazyLoad isNew={false} />
</View>}
<View className='spot-pagination'>
{swiperList.map((_, index) => (
<View key={index} className={'spot-pagination-bullet ' + ((state.currentIndex == index) ? 'spot-pagination-bullet-active' : "")} style={{ width: 1 / state.length * 100 + '%' }}></View>

View File

@ -43,16 +43,16 @@ import { useImmer } from 'use-immer'
import { useLogin, useNavigation } from '@/hooks'
import HomeWgts from './home/comps/home-wgts'
import { WgtHomeHeader, WgtHomeHeaderShop } from './home/wgts'
import CompAddTip from './home/comps/comp-addtip'
import CompFloatMenu from './home/comps/comp-floatmenu'
// import CompAddTip from './home/comps/comp-addtip'
// import CompFloatMenu from './home/comps/comp-floatmenu'
import './home/index.scss'
const MCompAddTip = React.memo(CompAddTip)
// const MCompAddTip = React.memo(CompAddTip)
const initialState = {
wgts: [],
showBackToTop: false,
loading: true,
loading: false,
searchComp: null,
pageData: null,
fixedTop: false,
@ -340,12 +340,12 @@ function Home () {
}
const getSwiperList = async () => {
const { status, activity_info = {}, total_count } = await api.user.registrationActivity({ activity_id: 1 })
const activeSwiper = activity_info.pics.map(item => ({
type: 'image',
src: item,
goods: []
}))
// const { status, activity_info = {}, total_count } = await api.user.registrationActivity({ activity_id: 1 })
// const activeSwiper = activity_info.pics.map(item => ({
// type: 'image',
// src: item,
// goods: []
// }))
const res = await api.shop.homeSwiperList({ page: 1, pageSize: 999 })
const list = (res?.list?.map((item) => {
return {
@ -367,14 +367,15 @@ function Home () {
}
}) || []).sort((a, b) => a.sort - b.sort)
setState((draft) => {
draft.swiperList = [...activeSwiper, ...list]
// draft.swiperList = [...activeSwiper, ...list]
draft.swiperList = list
draft.goodList = list[0].goods || []
draft.loading = false
draft.activeInfo = {
...activity_info,
total_count,
status
}
// draft.activeInfo = {
// ...activity_info,
// total_count,
// status
// }
})
}
@ -480,7 +481,7 @@ function Home () {
}, 500)
}
} else if (deltaY < 0) {
if (currentIndex === 0) return
// if (currentIndex === 0) return
// 上滑操作
setState((draft) => {
draft.showBottom = true
@ -524,12 +525,12 @@ function Home () {
const onSwiperChange = (e) => {
const { current } = e.detail
if (current === 0) {
setState((draft) => {
draft.showBottom = false
draft.isUpOperation = false
})
}
// if (current === 0) {
// setState((draft) => {
// draft.showBottom = false
// draft.isUpOperation = false
// })
// }
setState((draft) => {
draft.currentIndex = current
draft.goodList = swiperList[current].goods || []
@ -657,10 +658,8 @@ function Home () {
objectFit="cover"
style={{ width: "100%", height: "100%" }}
onPlay={() => {
}}
onEnded={() => {
}}
/>
)}
@ -671,26 +670,17 @@ function Home () {
<View className="item-btn-icon icon-my icon-arrow-right"></View>
</View>
</View>} */}
{!isUpOperation && item.type === "video" && <View className="mutedBtn" onClick={() => setState(v => { v.muted = !state.muted })} >
{item.type === "video" && <View className="mutedBtn" onClick={() => setState(v => { v.muted = !state.muted })} >
<Image className="muted-icon" src={`${process.env.APP_IMAGE_CDN_NEW}/index/${state.muted ? 'muted' : 'muted-no'}.jpg`}></Image>
</View>}
</SwiperItem>
))}
</Swiper>
{!isUpOperation && <>
{currentIndex === 0 ? <View className="item-btns">
<View className="item-tit">{activeInfo.activity_name}</View>
{/* <SpLogin newUser={isNewUser} onChange={handleApply}> */}
{activeInfo.end_time * 1000 >= Date.now() && <View className="item-btn" style={{ padding: '30rpx 60rpx' }} onClick={() => handleApply()}>
<View className="item-btn-txt">{activeInfo.total_count ? '已报名' : '活动申请'}</View>
{/* <Image className="jiantou" mode="aspectFit" src={require('../assets/hengjiantou.gif')}></Image> */}
</View>}
{/* </SpLogin> */}
</View> :
<View className="item-img-box">
<View className="item-img-txt"> </View>
<Image className="item-img" height="62" src={require('../assets/i-sou.gif')} isShowMenuByLongpress={false} lazyLoad isNew={false} />
</View>}
<View className="item-img-box">
<View className="item-img-txt"> </View>
<Image className="item-img" height="62" src={require('../assets/i-sou.gif')} isShowMenuByLongpress={false} lazyLoad isNew={false} />
</View>
<View className='spot-pagination'>
{swiperList.map((_, index) => (
<View key={index} className={'spot-pagination-bullet ' + ((state.currentIndex == index) ? 'spot-pagination-bullet-active' : "")} style={{ width: 1 / state.length * 100 + '%' }}></View>

View File

@ -117,6 +117,12 @@ function EspierDetail (props) {
const { setNavigationBarTitle } = useNavigation()
const dispatch = useDispatch()
const skuSelectRef = useRef()
const { windowWidth } = Taro.getSystemInfoSync()
const width = windowWidth * 2
const goods_1774 = {
1: ['1/1-1.jpg', '1/1-2.jpg', '1/1-3.jpg'],
2: ['2/2-1.jpg', '2/2-2.jpg', '2/2-3.jpg'],
}
const [state, setState] = useImmer(initialState)
const {
@ -396,7 +402,6 @@ function EspierDetail (props) {
}
}
const { windowWidth } = Taro.getSystemInfoSync()
let sessionFrom = {}
if (info) {
@ -752,29 +757,53 @@ function EspierDetail (props) {
<SpGoodsPrice info={curItem ? curItem : info} />
</View>
</View> */}
{isArray(info.intro) ? (
<View>
{info.intro.map((item, idx) => (
<View className='wgt-wrap' key={`wgt-wrap__${idx}`}>
{item.name === 'film' && <WgtFilm info={item} />}
{item.name === 'slider' && <WgtSlider info={item} />}
{item.name === 'writing' && <WgtWriting info={item} />}
{/* {item.name === 'heading' && <WgtHeading info={item} />} */}
{item.name === 'headline' && <WgtHeadline info={item} />}
{item.name === 'goods' && <WgtGoods info={item} />}
</View>
))}
</View>
) : (
<>
{/* <SpHtml content={info.intro} /> */}
</>
)}
{introList.length ? introList.map((item, index) => <View className={classNames('sp-accordion')} key={`item__${index}`}>
<AtAccordion
open={item.isOpen}
isAnimation={false}
onClick={() => {
{true ? <>
{goods_1774[1].map((item, index) => <SpImage src={`1774/${item}`} width={width} isNew >
</SpImage>)}
</> : <>
{isArray(info.intro) ? (
<View>
{info.intro.map((item, idx) => (
<View className='wgt-wrap' key={`wgt-wrap__${idx}`}>
{item.name === 'film' && <WgtFilm info={item} />}
{item.name === 'slider' && <WgtSlider info={item} />}
{item.name === 'writing' && <WgtWriting info={item} />}
{/* {item.name === 'heading' && <WgtHeading info={item} />} */}
{item.name === 'headline' && <WgtHeadline info={item} />}
{item.name === 'goods' && <WgtGoods info={item} />}
</View>
))}
</View>
) : (
<>
{/* <SpHtml content={info.intro} /> */}
</>
)}
{introList.length ? introList.map((item, index) => <View className={classNames('sp-accordion')} key={`item__${index}`}>
<AtAccordion
open={item.isOpen}
isAnimation={false}
onClick={() => {
setState((draft) => {
draft.introList = draft.introList.map((v, i) => {
v.isOpen = false
return v
})
draft.introList[index].isOpen = !item.isOpen
})
// if (!item.isOpen) {
// setState((draft) => {
// draft.scrollTop = 1042 + Math.random() / 10
// })
// }
}}
title={item.title}
>
{item.type !== 'eva' ? <SpHtml content={item.content} /> :
<CompEvaluation list={evaluationList} itemId={info.itemId}></CompEvaluation>
}
</AtAccordion>
<View onClick={() => {
setState((draft) => {
draft.introList = draft.introList.map((v, i) => {
v.isOpen = false
@ -787,51 +816,32 @@ function EspierDetail (props) {
// draft.scrollTop = 1042 + Math.random() / 10
// })
// }
}}
title={item.title}
>
{item.type !== 'eva' ? <SpHtml content={item.content} /> :
<CompEvaluation list={evaluationList} itemId={info.itemId}></CompEvaluation>
}
</AtAccordion>
<View onClick={() => {
setState((draft) => {
draft.introList = draft.introList.map((v, i) => {
v.isOpen = false
return v
})
draft.introList[index].isOpen = !item.isOpen
})
// if (!item.isOpen) {
// setState((draft) => {
// draft.scrollTop = 1042 + Math.random() / 10
// })
// }
}}>
{item.isOpen ? <AtIcon value='subtract' size='16' color='#000' /> :
<AtIcon value='add' size='16' color='#000' />}
{item.isOpen ? <></> : <View className="line"></View>}
</View>
</View>) : <View style={{ height: `calc(100% - 380px)` }}></View>}
{/* 商品评价 */}
}}>
{item.isOpen ? <AtIcon value='subtract' size='16' color='#000' /> :
<AtIcon value='add' size='16' color='#000' />}
{item.isOpen ? <></> : <View className="line"></View>}
</View>
</View>) : <View style={{ height: `calc(100% - 380px)` }}></View>}
{/* 商品评价 */}
{/* <CompEvaluation list={evaluationList} itemId={info.itemId}></CompEvaluation> */}
{isArray(historyList) ? <View className='bottom-box'>
<View className="bottom-box-tit">浏览历史</View>
<ScrollView scrollX scrollWithAnimation showScrollbar={true} scrollLeft={0} className="shop-box">
{historyList.map((item, idx) => (
<View className='goods-item-wrap' key={`goods-item-l__${idx}`}>
<SpGoodsItem
showSalePrice={false}
height={250}
width={250}
onStoreClick={handleClickStore}
info={item}
/>
</View>
))}
</ScrollView>
</View> : <></>}
{/* <CompEvaluation list={evaluationList} itemId={info.itemId}></CompEvaluation> */}
{isArray(historyList) ? <View className='bottom-box'>
<View className="bottom-box-tit">浏览历史</View>
<ScrollView scrollX scrollWithAnimation showScrollbar={true} scrollLeft={0} className="shop-box">
{historyList.map((item, idx) => (
<View className='goods-item-wrap' key={`goods-item-l__${idx}`}>
<SpGoodsItem
showSalePrice={false}
height={250}
width={250}
onStoreClick={handleClickStore}
info={item}
/>
</View>
))}
</ScrollView>
</View> : <></>}
</>}
</View>
</ScrollView>
)}

View File

@ -0,0 +1,403 @@
import React, { useEffect } from 'react'
import { View, Text, Input, Image, Button, Picker } from '@tarojs/components'
import Taro, { getCurrentInstance, useDidShow, useShareAppMessage } from '@tarojs/taro'
import { SpPage, SpHtml, SpCheckbox, SpLogin, SpImage } from '@/components'
import { useSelector } from 'react-redux'
import { useImmer } from 'use-immer'
import api from '@/api'
import dayjs from 'dayjs'
import { AtIcon } from 'taro-ui'
import { classNames, navigateTo, pickBy } from '@/utils'
import { useLogin } from '@/hooks'
import './apply.scss'
const initState = {
activeInfo: {},
isLoading: true,
visible: false,
checked: false,
formInfo: {},
status: '',
isShare: false,
alwaysBackUrl: "/pages/index",
isSub: false,
formData: {},
formList: [{}],
areaList: [],
}
export default function detail () {
const $instance = getCurrentInstance()
const [state, setState] = useImmer(initState)
const { appName } = useSelector((_state) => _state.sys)
const { userInfo = {} } = useSelector((_state) => _state.user)
const { isLogin } = useLogin({
autoLogin: true,
})
const getActiveDetail = async () => {
const { id: activity_id, alwaysBackUrl } = $instance.router.params
if (!activity_id) return
const { status, activity_info = {}, total_count, user_code, recordList = {} } = await api.user.registrationActivity({ activity_id })
if (total_count > 0 && !alwaysBackUrl) {
Taro.redirectTo({ url: '/pages/recommend/status?&id=' + activity_id })
return
}
const _start = dayjs(activity_info.start_time * 1000)
const _end = dayjs(activity_info.end_time * 1000)
if (alwaysBackUrl) {
setState(draft => {
draft.alwaysBackUrl = alwaysBackUrl + "?id=" + activity_id
})
}
const _item = recordList.list?.[0] || {}
setState(draft => {
draft.isLoading = false
draft.activeInfo = {
...activity_info,
user_code,
total_count,
start: `${_start.month() + 1}${_start.date()}`,
end: `${_end.month() + 1}${_end.date()}`,
status: _item.is_write_off === '1' ? 'done' : _item.status,
isLoading: false
}
draft.checked = !!_item
})
}
useEffect(() => {
getActiveDetail()
fetchAreaData()
}, [])
useEffect(() => {
if (isLogin && userInfo) {
setState(draft => {
draft.formInfo = {
username: userInfo.username,
mobile: userInfo.mobile,
}
})
}
}, [userInfo, isLogin])
const { isLoading, activeInfo = {}, visible, formInfo, checked, status, isShare, alwaysBackUrl, isSub, formData, formList, areaList } = state
const handleConfirm = async () => {
if (!isLogin || !userInfo) return
if (activeInfo.status) {
Taro.navigateTo({ url: '/pages/recommend/status?success=true&id=' + activeInfo.activity_id })
return
}
if (!checked) {
const res = await Taro.showModal({
title: '提示',
content: `请先阅读并同意${appName}活动细则`,
showCancel: true,
cancel: '取消',
cancelText: '拒绝',
confirmText: '同意',
cancelColor: '#a5a5a5',
confirmColor: '#000'
})
if (!res.confirm) return
setState((draft) => {
draft.checked = true
draft.visible = true
})
}
setState((draft) => {
draft.visible = true
})
}
const fetchAreaData = async () => {
let res = await api.member.areaList()
const _nList = pickBy(res, {
label: 'label',
value: 'id',
// children: 'children'
})
setState(draft => {
draft.areaList = _nList
})
}
const renderFooter = () => {
if (isLoading || status === 'passed') {
return null
}
return <View className={"bottom"}>
<View className='check-box'>
<SpCheckbox disabled={!!activeInfo.status} checked={checked} colors="#000" onChange={() => setState((draft) => { draft.checked = !checked })} />
<View>
<Text onClick={() => !activeInfo.status && setState((draft) => { draft.checked = !checked })} >我已经阅读并同意</Text>
<Text
onClick={() => Taro.navigateTo({ url: '/subpages/auth/reg-rule?type=activity_rule' })}
style={`color: #000000;text-decoration: underline;`}
>
{`${appName}活动细则》`}
</Text>
</View>
</View>
{/* <View onClick={handleConfirm} className={"btn"}>{!status ? '确认报名' : status === 'pending' ? '报名中' : '已报名'}</View> */}
<SpLogin onChange={getActiveDetail}>
<View onClick={handleConfirm} className={"btn"}>{!activeInfo.status ? '确认报名' : '报名详情'}</View>
</SpLogin>
</View>
}
const onIptChange = (e, name) => {
const { value } = e.detail
setState((draft) => {
draft.formData[name] = value
})
}
const handleSubmit = async () => {
if (isSub) {
return
}
setState((draft) => {
draft.isSub = true
})
if (isShare) {
handeleShare()
return
}
if (!formInfo.username?.trim()) {
Taro.showToast({
title: '请输入姓名',
icon: 'none'
})
return
}
if (!formInfo.mobile?.trim()) {
Taro.showToast({
title: '请输入手机号',
icon: 'none'
})
return
}
const content = {
title: '',
sort: 1,
formdata: formItem.map((d) => {
return {
...d,
answer: formInfo[d.field_name]
}
})
}
const { status } = await api.user.registrationSubmit({
formdata: { content: JSON.stringify([content]) },
activity_id: activeInfo.activity_id
})
if (status) {
setState((draft) => {
draft.visible = false
draft.status = status
})
const templeparams = {
temp_name: 'yykweishop',
source_type: 'activity'
}
const { template_id } = await api.user.newWxaMsgTmpl(templeparams)
Taro.requestSubscribeMessage({
tmplIds: template_id,
success: () => {
},
fail: (err) => {
},
complete: () => {
Taro.navigateTo({ url: '/pages/recommend/status?success=true&id=' + activeInfo.activity_id })
}
})
}
setState((draft) => {
draft.isSub = false
})
}
const onClickShare = () => {
setState((draft) => {
draft.visible = true
draft.isShare = true
})
}
useShareAppMessage(() => {
return {
title: activeInfo.activity_name,
path: `/pages/recommend/detail?id=${activeInfo.activity_id}`,
// imageUrl: activeInfo.pics[0]
imageUrl: `${process.env.APP_IMAGE_CDN_NEW}/share-logo.jpg`
}
})
const handleClose = () => {
setState((draft) => {
draft.visible = false
})
setTimeout(() => {
setState((draft) => {
draft.isShare = false
})
}, 800)
}
const pickerChange = (e) => {
const { value } = e.detail
console.log("🚀 ~ file: apply.js:247 ~ value:", value)
// setState((draft) => {
// draft.formData.sex = value
// })
}
const handleAddApply = (flag) => {
if (formList.length > 2) {
return
}
if (flag) {
setState((draft) => {
draft.formList = [...formList, {}]
})
} else {
setState((draft) => {
draft.formList = [formList[0]]
})
}
}
const formItem = activeInfo.formdata?.key_index || []
// !!activeInfo?.total_count ? <></> :
return (
<SpPage title='报名信息' renderFooter={!!activeInfo?.total_count ? <></> : renderFooter()} loading={isLoading} className='page-recommend-apply' alwaysBackUrl={alwaysBackUrl} isBlack>
<View className="activity_apply_time">第一场 13:00-14:00</View>
<View className="activity_apply_tit">请填写您的个人信息</View>
{formList.map((item, index) => <View className='user-form' key={index}>
<View className="user-form-item">
<View className="user-form-item-title">姓名</View>
<View className='cell-item'>
<Input
value={item.username}
className="user-form-item-ipt"
type="text"
placeholder={`请输入${index > 0 ? '他人' : ''}姓名`}
onInput={(e) => onIptChange(e, 'username')}
/>
</View>
</View>
<View className="user-form-item">
<View className="user-form-item-title">手机</View>
<View className='cell-item'>
<Input
className="user-form-item-ipt"
type="text"
placeholder={`请输入${index > 0 ? '他人' : ''}手机号`}
onInput={(e) => onIptChange(e, 'mobile')}
/>
</View>
</View>
<View className="user-form-item">
<View className='cell-item'>
<View className="cell-item-tit">性别</View>
<View className='flex-row'>
<View className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: true })}></View>
</View>
<View className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: true })}></View>
</View>
</View>
</View>
</View>
<View className="user-form-item">
<View className='cell-item'>
<View className="cell-item-tit">是否拥有BIRKENSTOCK鞋履</View>
<View className='flex-row'>
<View className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: true })}></View>
</View>
<View className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: true })}></View>
</View>
</View>
</View>
</View>
<View className="user-form-item">
<View className='cell-item'>
<View className="cell-item-tit">常驻城市选填</View>
<Picker
mode='selector'
onChange={pickerChange}
range={areaList}
rangeKey="label"
>
<View className='flex-row'>
<View className="sex-label">测试</View>
<View className="iconfont icon-arrowRight"></View>
</View>
</Picker>
</View>
</View>
{index === 0 && <View className="user-form-item">
<View className='cell-item'>
<View className="cell-item-tit">是否协同他人一起参加</View>
<View className='flex-row'>
<View onClick={() => handleAddApply(1)} className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: true })}></View>
</View>
<View onClick={() => handleAddApply(0)} className="flex-row">
<View className="sex-label"></View>
<View className={classNames("radio ", { checked: false })}></View>
</View>
</View>
</View>
</View>}
</View>)}
<View className="sp-picker">
<View
className={classNames('mask', {
visible: visible
})}
onTap={handleClose}
catchtouchmove
></View>
<View
className={classNames('sp-picker-cnt', {
visible: visible
})}
>
<View className={classNames('sp-picker-hd')} catchtouchmove>
<Text className='center'>{isShare ? '分享' : '报名信息'}</Text>
<AtIcon onClick={handleClose} value='close' size={14} color='#000' ></AtIcon>
</View>
<View className='sp-picker-bd'>
{!isShare && formItem.map((item, index) => (
<View className="user-form-item" key={`userinfo-item__${index}`}>
<View className="user-form-item-title">{item.field_title}</View>
<View className="user-form-item-input">
{item.form_element === 'text' ? <Input
name={item.field_name}
value={formInfo[item.field_name]}
class='input-field-1'
placeholder={`请输入`}
onInput={(e) => onIptChange(e, item.field_name)}
/> : null}
</View>
</View>
))}
{isShare ? <Button openType="share" className={"btn share"} onClick={handleClose} plain>发送给朋友</Button> :
<View onClick={handleSubmit} className={"btn"}>{'确认报名信息'}</View>}
</View>
</View>
</View>
</SpPage>
)
}

View File

@ -0,0 +1,126 @@
.page-recommend-apply {
.sp-page-body {
padding: 0 50px 60px;
}
.activity_apply_time {
font-size: 30rpx;
font-weight: 500;
color: #000;
margin-bottom: 50rpx;
margin-top: 14rpx;
text-align: center;
}
.activity_apply_tit {
font-size: 34rpx;
font-weight: 500;
color: #000;
margin-bottom: 30rpx;
}
.user-form {
margin-bottom: 80px;
.icon-arrowRight {
color: #000;
font-size: 36rpx;
rotate: 90deg;
}
}
.user-form-item {
margin-bottom: 30rpx;
&-title {
margin-bottom: 6rpx;
}
&-ipt {
width: 100%;
color: #000 !important;
}
.cell-item {
display: flex;
align-items: center;
justify-content: space-between;
border-radius: 6rpx;
background: #e1e1e1;
padding: 22rpx 22rpx 22rpx 42rpx;
color: #999;
&-tit {
font-size: 28rpx;
color: #000;
}
.flex-row {
margin-left: 20rpx;
}
}
}
.flex-row {
display: flex;
align-items: center;
justify-content: space-between;
}
.sex-label {
color: #000;
margin: 0 20px;
}
.radio {
width: 26px;
height: 26px;
border-radius: 50%;
/* prettier-ignore */
border: 1PX solid #000;
position: relative;
transition: all 0.3s ease-in-out 0s;
&.checked::after {
content: '';
display: block;
width: 18px;
height: 18px;
border-radius: 50%;
background-color: #000;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
}
}
.sp-page-footer {
min-height: 200px;
padding: 0 50px;
.check-box {
width: 100%;
display: flex;
align-items: center;
justify-content: center;
margin: 16px auto;
.icon-my {
font-size: 30px;
}
view {
font-size: 22px;
}
}
.bottom {
// position: fixed;
// bottom: 80px;
// left: 0;
// right: 0;
width: 100%;
margin-bottom: 50px;
.btn {
display: flex;
height: 80px;
align-items: center;
justify-content: center;
font-size: 32px;
line-height: 1;
background: #000;
color: #fff;
border-radius: 6px;
&.notop {
margin-top: 10px;
}
&-disabled {
background: #666;
}
}
}
}
}

View File

@ -1,7 +1,7 @@
import React, { useEffect } from 'react'
import { View, Text, Input, Image, Button } from '@tarojs/components'
import Taro, { getCurrentInstance, useDidShow, useShareAppMessage } from '@tarojs/taro'
import { SpPage, SpHtml, SpCheckbox, SpLogin } from '@/components'
import { SpPage, SpHtml, SpCheckbox, SpLogin, SpImage } from '@/components'
import { useSelector } from 'react-redux'
import { useImmer } from 'use-immer'
import api from '@/api'
@ -232,11 +232,15 @@ export default function detail () {
const formItem = activeInfo.formdata?.key_index || []
// !!activeInfo?.total_count ? <></> :
// renderFooter={!!activeInfo?.total_count ? <></> : renderFooter()}
return (
<SpPage renderFooter={!!activeInfo?.total_count ? <></> : renderFooter()} loading={isLoading} className='page-recommend-detail' alwaysBackUrl={alwaysBackUrl} isBlack>
<SpPage loading={isLoading} className='page-recommend-detail' alwaysBackUrl={alwaysBackUrl} isBlack>
<View style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<SpImage src='member/logo-black.png' height={42} mode='heightFix' isNew ></SpImage>
<Image onClick={onClickShare} className="share_icon" src={require('../../assets/share.jpg')} mode='widthFix' ></Image>
</View>
<View className="name-box">
<View className="activity_name">{activeInfo.activity_name}</View>
<Image onClick={onClickShare} className="share_icon" src={require('../../assets/share.jpg')} mode='widthFix' ></Image>
</View>
<View className="activity_time">{activeInfo.start} - {activeInfo.end}</View>
<View className="activity_addr">
@ -244,6 +248,19 @@ export default function detail () {
<Text>{activeInfo.address}</Text>
</View>
<SpHtml content={activeInfo.intro} />
<View className="activity_apply_tit">
<View className="big">选择活动时段报名</View>
<View className="small">(为确保您的体验活动当天每场次仅限5人)</View>
</View>
<View style={{ paddingBottom: '80px' }}>
{[{}, {}, {}].map((item, index) => <View className='time-item' key={index + '__item'}>
<Text className="time-item-title">{index + 1} 13:00-14:00</Text>
<View className="btn" onClick={() => navigateTo('/pages/recommend/apply?id=' + activeInfo.activity_id + '&time=' + index)} >{2}席可选</View>
</View>)}
</View>
<View className="sp-picker">
<View
className={classNames('mask', {

View File

@ -6,26 +6,26 @@
display: flex;
align-items: flex-start;
justify-content: space-between;
.share_icon {
height: 40px;
width: 60px;
padding: 10px 0 10px 20px;
}
}
.share_icon {
height: 60px;
width: 40px;
padding: 10px 0 10px 20px;
}
.activity_name {
font-size: 40px;
font-weight: bold;
margin-bottom: 30px;
margin-bottom: 24px;
}
.activity_time {
font-size: 26px;
// color: #999;
margin-bottom: 60px;
margin-bottom: 50px;
}
.activity_addr {
font-size: 26px;
// color: #999;
margin-bottom: 40px;
margin-bottom: 30px;
display: flex;
align-items: center;
> image {
@ -203,46 +203,84 @@
opacity: 1;
}
}
}
.sp-page-footer {
min-height: 200px;
padding: 0 50px;
.check-box {
margin-top: 100px;
width: 100%;
.activity_apply_tit {
color: #000;
display: flex;
align-items: baseline;
margin-bottom: 20rpx;
.big {
font-size: 30rpx;
font-weight: 500;
}
.small {
font-size: 20rpx;
margin-left: 10rpx;
}
}
.time-item {
display: flex;
align-items: center;
justify-content: center;
margin: 10px auto;
.icon-my {
font-size: 36px;
}
view {
font-size: 22px;
justify-content: space-between;
border-radius: 6rpx;
background: #e1e1e1;
padding: 16rpx 16rpx 16rpx 36rpx;
color: #999;
margin-bottom: 16rpx;
.btn {
width: 140rpx;
height: 54rpx;
line-height: 54rpx;
border-radius: 6rpx;
font-size: 24rpx;
text-align: center;
color: #fff;
background: #000;
&.disabled {
background: #c7c7c795;
opacity: 0.8;
}
}
}
.bottom {
// position: fixed;
// bottom: 80px;
// left: 0;
// right: 0;
width: 100%;
margin-bottom: 50px;
.btn {
.sp-page-footer {
min-height: 200px;
padding: 0 50px;
.check-box {
margin-top: 100px;
width: 100%;
display: flex;
height: 80px;
align-items: center;
justify-content: center;
font-size: 32px;
line-height: 1;
background: #000;
color: #fff;
border-radius: 6px;
&.notop {
margin-top: 10px;
margin: 10px auto;
.icon-my {
font-size: 30px;
}
&-disabled {
background: #666;
view {
font-size: 22px;
}
}
.bottom {
// position: fixed;
// bottom: 80px;
// left: 0;
// right: 0;
width: 100%;
margin-bottom: 50px;
.btn {
display: flex;
height: 80px;
align-items: center;
justify-content: center;
font-size: 32px;
line-height: 1;
background: #000;
color: #fff;
border-radius: 6px;
&.notop {
margin-top: 10px;
}
&-disabled {
background: #666;
}
}
}
}

View File

@ -1,4 +1,4 @@
import React, { useEffect } from 'react'
import React, { useEffect, useState } from 'react'
import { View, Text, Input, Image, Button } from '@tarojs/components'
import Taro, { getCurrentInstance, useDidShow, useShareAppMessage } from '@tarojs/taro'
import { SpPage, SpHtml, SpCheckbox, SpImage } from '@/components'
@ -7,7 +7,7 @@ import { getActiveDetail } from '@/api/community'
import { useImmer } from 'use-immer'
import api from '@/api'
import dayjs from 'dayjs'
import { AtIcon } from 'taro-ui'
import { AtIcon, AtModal } from 'taro-ui'
import { classNames, navigateTo, isArray } from '@/utils'
import QRCode from 'qrcode'
import './status.scss'
@ -23,6 +23,7 @@ const initState = {
export default function status () {
const $instance = getCurrentInstance()
const [state, setState] = useImmer(initState)
const [showModal, setShowModal] = useState(false)
const { cur_activity_info, loading, activeInfo, qrUrl, visible } = state
useEffect(() => {
@ -111,17 +112,18 @@ export default function status () {
}
const handleCancel = async () => {
const res = await Taro.showModal({
title: '提示',
content: `确定要取消预约吗?`,
showCancel: true,
cancel: '取消',
cancelText: '取消',
confirmText: '确认',
cancelColor: '#a5a5a5',
confirmColor: '#000'
})
if (!res.confirm) return
setShowModal(false)
// const res = await Taro.showModal({
// title: '提示',
// content: `确定要取消预约吗?`,
// showCancel: true,
// cancel: '取消',
// cancelText: '取消',
// confirmText: '确认',
// cancelColor: '#a5a5a5',
// confirmColor: '#000'
// })
// if (!res.confirm) return
const { id } = $instance.router.params
await api.user.cancelRegistrationRecord({
activity_id: id
@ -150,12 +152,16 @@ export default function status () {
return (
<SpPage loading={loading} title={activeInfo.status === 'pending' ? '待审核' : '预约成功'} className='page-recommend-status' alwaysBackUrl="/pages/index" isBlack>
<View className="">
<SpCheckbox checked={true} colors="#000" label={activeInfo.status === 'pending' ? '待审核' : activeInfo.status === 'done' ? '已签到' : "已预约"}></SpCheckbox>
<View className="tit__label">
{/* <SpCheckbox checked={true} colors="#000" label={activeInfo.status === 'pending' ? '待审核' : activeInfo.status === 'done' ? '已签到' : "已预约"}></SpCheckbox> */}
{activeInfo.status === 'pending' ? '待审核' : activeInfo.status === 'done' ? '已签到' : "已报名 待通过"}
</View>
<View style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
<SpImage src='member/logo-black.png' height={42} mode='heightFix' isNew ></SpImage>
<Image onClick={onClickShare} className="share_icon" src={require('../../assets/share.jpg')} mode='widthFix' ></Image>
</View>
<View className="name-box">
<View className="activity_name">{activeInfo.activity_name}</View>
<Image onClick={onClickShare} className="share_icon" src={require('../../assets/share.jpg')} mode='widthFix' ></Image>
</View>
<View className="activity_info">
<View className="activity_info-item flex-col">
@ -167,6 +173,17 @@ export default function status () {
<Text className="value">{activeInfo?.mobile}</Text>
</View>
</View>
<View style={{ margin: '20px 0 14px' }}>同行朋友</View>
<View className="activity_info">
<View className="activity_info-item flex-col">
<Text className="title">姓名</Text>
<Text className="value">{activeInfo?.username}</Text>
</View>
<View className="activity_info-item flex-col">
<Text className="title">手机号</Text>
<Text className="value">{activeInfo?.mobile}</Text>
</View>
</View>
<View className="activity_time flex-col">
<Text className="title">活动时间</Text>
<Text className="value">{activeInfo?.start} - {activeInfo?.end}</Text>
@ -185,7 +202,7 @@ export default function status () {
</View>
<View className="code-box-txt">入场请出示预约凭证</View>
</View> : <View style={'height:315px;'}></View>}
{activeInfo.status !== 'done' && <View className="cancel-txt" onClick={handleCancel}>取消预约</View>}
{activeInfo.status !== 'done' && <View className="cancel-txt" onClick={() => setShowModal(true)}>取消预约</View>}
<View className="sp-picker">
<View
className={classNames('mask', {
@ -208,6 +225,19 @@ export default function status () {
</View>
</View>
</View>
<AtModal
isOpened={showModal}
title=''
cancelText='是,我要取消'
confirmText='否,我要保留'
onClose={() => setShowModal(false)}
onCancel={() => handleCancel}
onConfirm={() => {
setShowModal(false)
}}
content={'尊敬的用户:\n现场活动席位数量有限如取消目前报名\n可能导致您无法选择其他时间段活动\n请问您确认要取消吗'}
/>
</SpPage>
)
}

View File

@ -9,6 +9,12 @@
font-size: 40px;
}
}
.tit__label {
font-size: 40px;
text-align: center;
margin-bottom: 20px;
font-weight: bold;
}
.activity_name {
font-size: 40px;
font-weight: bold;
@ -49,14 +55,14 @@
.activity_time {
font-size: 24px;
color: #999;
margin-bottom: 50px;
margin-bottom: 80px;
}
.activity_addr {
font-size: 24px;
color: #999;
}
.activity_intro {
font-size: 30px;
font-size: 34px;
text-decoration: underline;
margin: 90px 0 50px;
}
@ -91,20 +97,21 @@
}
}
.cancel-txt {
font-size: 18px;
font-size: 22px;
text-align: center;
margin-top: 30px;
margin-top: 20px;
text-decoration: underline;
font-weight: bold;
}
.name-box {
display: flex;
align-items: flex-start;
justify-content: space-between;
.share_icon {
height: 40px;
width: 60px;
padding: 10px 0 10px 20px;
}
}
.share_icon {
height: 60px;
width: 40px;
padding: 10px 0 10px 20px;
}
.sp-picker {
.mask {
@ -248,4 +255,37 @@
}
}
}
.at-modal {
&__overlay {
background-color: rgba(0, 0, 0, 0.6);
}
&__container {
width: 560px;
border-radius: 10px;
}
&__header {
font-size: 40px;
font-weight: bold;
padding-top: 40px;
}
&__content {
padding: 60rpx 20rpx 50rpx;
text-align: center;
min-height: auto;
display: flex;
.content-simple {
font-size: 28px;
white-space: pre-wrap;
min-height: 150px;
text-align: left;
display: flex;
text {
margin: 0 auto;
}
}
}
.at-modal__footer--simple .at-modal__action > button:last-child:nth-child(2) {
color: #222;
}
}
}

View File

@ -469,7 +469,7 @@ function MemberIndex (props) {
// console.log('====config===', config.menu)
return (
<SpPage loading={state.loading} className='pages-member-index has-navbar' renderFooter={<SpTabbar />} title='' showNavSearchIcon={false} showNavLogo isBlack isTop>
<SpPage loading={state.loading} className='pages-member-index has-navbar' renderFooter={<SpTabbar />} title='' showNavSearchIcon={false} showNavBackIcon={false} showNavLogo isBlack isTop>
<View
className='header-block'
style={styleNames({