feat: 详情页联调
This commit is contained in:
@@ -16,6 +16,8 @@
|
|||||||
position: sticky;
|
position: sticky;
|
||||||
top: 0;
|
top: 0;
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
|
overflow: hidden;
|
||||||
|
background-color: rgba(0, 0, 0, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-navigator {
|
.detail-navigator {
|
||||||
@@ -63,12 +65,26 @@
|
|||||||
left: 0;
|
left: 0;
|
||||||
top: 0;
|
top: 0;
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
filter: blur(40px);
|
// filter: blur(40px);
|
||||||
transform: scale(1.5);
|
// transform: scale(1.5);
|
||||||
z-index: -2;
|
z-index: -2;
|
||||||
width: calc(100% + 20px);
|
// width: calc(100% + 20px);
|
||||||
height: calc(100% + 20px);
|
// height: calc(100% + 20px);
|
||||||
margin: -10px;
|
// margin: -10px;
|
||||||
|
width: 100vw;
|
||||||
|
height: 100vh;
|
||||||
|
|
||||||
|
&::after {
|
||||||
|
content: '';
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
z-index: -1;
|
||||||
|
background: linear-gradient(180deg, rgba(0, 0, 0, 0.80) 0%, rgba(0, 0, 0, 0.40) 100%);
|
||||||
|
backdrop-filter: blur(100px);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.detail-page-bg-text {
|
.detail-page-bg-text {
|
||||||
@@ -215,7 +231,6 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
height: 48px;
|
height: 48px;
|
||||||
padding-bottom: 6px;
|
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -225,6 +240,7 @@
|
|||||||
background: rgba(255, 255, 255, 0.25);
|
background: rgba(255, 255, 255, 0.25);
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
|
background: #536272;
|
||||||
|
|
||||||
.month {
|
.month {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -235,20 +251,21 @@
|
|||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
// border-bottom: 1px solid rgba(255, 255, 255, 0.08);
|
||||||
background: #7B828B;
|
background: #7B828B;
|
||||||
}
|
}
|
||||||
|
|
||||||
.day {
|
.day {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 48px;
|
width: 48px;
|
||||||
padding-bottom: 6px;
|
height: 30px;
|
||||||
|
// padding-bottom: 6px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 4px;
|
|
||||||
// border: 0.5px solid rgba(255, 255, 255, 0.08);
|
// border: 0.5px solid rgba(255, 255, 255, 0.08);
|
||||||
// background: rgba(255, 255, 255, 0.25);
|
// background: rgba(255, 255, 255, 0.25);
|
||||||
|
// background-color: #536272;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -334,7 +351,7 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
// border: 0.5px solid rgba(255, 255, 255, 0.08);
|
// border: 0.5px solid rgba(255, 255, 255, 0.08);
|
||||||
background: rgba(255, 255, 255, 0.25);
|
// background: rgba(255, 255, 255, 0.25);
|
||||||
|
|
||||||
&-image {
|
&-image {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
@@ -399,7 +416,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-detail {
|
&-venue {
|
||||||
padding: 24px 15px 0;
|
padding: 24px 15px 0;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
|
|
||||||
@@ -408,7 +425,7 @@
|
|||||||
height: 31px;
|
height: 31px;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: flex-start;
|
justify-content: flex-start;
|
||||||
gap: 4px;
|
gap: 8px;
|
||||||
padding-bottom: 6px;
|
padding-bottom: 6px;
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
@@ -419,9 +436,15 @@
|
|||||||
line-height: 24px;
|
line-height: 24px;
|
||||||
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
border-bottom: 1px solid rgba(255, 255, 255, 0.1);
|
||||||
|
|
||||||
&-notice-icon {
|
.venue-reserve-status {
|
||||||
width: 14px;
|
display: inline-flex;
|
||||||
height: 14px;
|
justify-content: flex-start;
|
||||||
|
align-items: center;
|
||||||
|
gap: 4px;
|
||||||
|
.venue-reserve-screenshot {
|
||||||
|
width: 16px;
|
||||||
|
height: 16px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -461,6 +484,51 @@
|
|||||||
line-height: 24px; /* 160% */
|
line-height: 24px; /* 160% */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.venue-screenshot-title {
|
||||||
|
display: flex;
|
||||||
|
padding: 18px 20px 10px 20px;
|
||||||
|
align-items: center;
|
||||||
|
align-self: stretch;
|
||||||
|
font-family: "PingFang SC";
|
||||||
|
font-size: 16px;
|
||||||
|
font-style: normal;
|
||||||
|
font-weight: 500;
|
||||||
|
line-height: 24px; /* 150% */
|
||||||
|
letter-spacing: -0.23px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.venue-screenshot-scroll-view {
|
||||||
|
max-height: calc(100vh - 260px);
|
||||||
|
overflow-y: auto;
|
||||||
|
padding-bottom: 40px;
|
||||||
|
|
||||||
|
.venue-screenshot-image-list {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0 16px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
gap: 10px 10px;
|
||||||
|
|
||||||
|
.venue-screenshot-image-item {
|
||||||
|
aspect-ratio: 1/1;
|
||||||
|
border-radius: 9px;
|
||||||
|
border: 1px solid rgba(0, 0, 0, 0.12);
|
||||||
|
box-sizing: border-box;
|
||||||
|
background: rgba(0, 0, 0, 0.06);
|
||||||
|
margin: 0;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
.venue-screenshot-image-item-image {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
border-radius: 9px;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&-gameplay-requirements {
|
&-gameplay-requirements {
|
||||||
@@ -591,7 +659,7 @@
|
|||||||
.participants-list-item {
|
.participants-list-item {
|
||||||
display: flex;
|
display: flex;
|
||||||
width: 108px;
|
width: 108px;
|
||||||
padding: 16px 12px 10px 12px;
|
padding: 16px 4px 10px 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
flex-direction: column;
|
flex-direction: column;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
@@ -608,6 +676,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
&-name {
|
&-name {
|
||||||
|
width: 100%;
|
||||||
color: rgba(255, 255, 255, 0.85);
|
color: rgba(255, 255, 255, 0.85);
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-feature-settings: 'liga' off, 'clig' off;
|
font-feature-settings: 'liga' off, 'clig' off;
|
||||||
@@ -616,6 +685,9 @@
|
|||||||
font-style: normal;
|
font-style: normal;
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
line-height: 24px; /* 184.615% */
|
line-height: 24px; /* 184.615% */
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
&-level {
|
&-level {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React, { useState, useRef, useImperativeHandle, forwardRef } from 'react'
|
import React, { useState, useRef, useImperativeHandle, forwardRef } from 'react'
|
||||||
import { View, Text, Image, Map, ScrollView } from '@tarojs/components'
|
import { View, Text, Image, Map, ScrollView } from '@tarojs/components'
|
||||||
import { Avatar, Popover } from '@nutui/nutui-react-taro'
|
import { Avatar, Popover, ImagePreview } from '@nutui/nutui-react-taro'
|
||||||
import Taro, { useRouter, useShareAppMessage, useShareTimeline, useDidShow } from '@tarojs/taro'
|
import Taro, { useRouter, useShareAppMessage, useShareTimeline, useDidShow } from '@tarojs/taro'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import 'dayjs/locale/zh-cn'
|
import 'dayjs/locale/zh-cn'
|
||||||
@@ -86,7 +86,6 @@ function StickyButton(props) {
|
|||||||
const { publisher_id, match_status, price } = detail || {}
|
const { publisher_id, match_status, price } = detail || {}
|
||||||
|
|
||||||
const role = Number(publisher_id) === id ? 'ownner' : 'visitor'
|
const role = Number(publisher_id) === id ? 'ownner' : 'visitor'
|
||||||
console.log(match_status, role)
|
|
||||||
return (
|
return (
|
||||||
<View className="sticky-bottom-bar">
|
<View className="sticky-bottom-bar">
|
||||||
<View className="sticky-bottom-bar-share-and-comment">
|
<View className="sticky-bottom-bar-share-and-comment">
|
||||||
@@ -214,117 +213,196 @@ function GameInfo(props) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
function Index() {
|
// 场馆信息
|
||||||
// 使用Zustand store
|
function VenueInfo(props) {
|
||||||
// const userStats = useUserStats()
|
const { detail } = props
|
||||||
// const { incrementRequestCount, resetUserStats } = useUserActions()
|
const [visible, setVisible] = useState(false)
|
||||||
|
const { venue_description, venue_description_tag = [], venue_image_list = [] } = detail
|
||||||
|
|
||||||
const [current, setCurrent] = useState(0)
|
function showScreenShot() {
|
||||||
// const [textColor, setTextColor] = useState<string []>([])
|
setVisible(true)
|
||||||
const [detail, setDetail] = useState<any>(null)
|
|
||||||
const { params } = useRouter()
|
|
||||||
const [currentLocation, setCurrentLocation] = useState<[number, number]>([0, 0])
|
|
||||||
const { id, autoShare, from } = params
|
|
||||||
const { fetchUserInfo, updateUserInfo } = useUserActions()
|
|
||||||
|
|
||||||
console.group('params')
|
|
||||||
console.log(params)
|
|
||||||
console.groupEnd()
|
|
||||||
|
|
||||||
// 本地状态管理
|
|
||||||
const [loading, setLoading] = useState(false)
|
|
||||||
const sharePopupRef = useRef<any>(null)
|
|
||||||
|
|
||||||
// 页面加载时获取数据
|
|
||||||
// useEffect(() => {
|
|
||||||
// fetchDetail()
|
|
||||||
// calcBgMainColors()
|
|
||||||
// }, [])
|
|
||||||
|
|
||||||
useDidShow(async () => {
|
|
||||||
await updateLocation()
|
|
||||||
await fetchUserInfo()
|
|
||||||
await fetchDetail()
|
|
||||||
// calcBgMainColors()
|
|
||||||
})
|
|
||||||
|
|
||||||
const updateLocation = async () => {
|
|
||||||
try {
|
|
||||||
const location = await getCurrentLocation()
|
|
||||||
setCurrentLocation([location.latitude, location.longitude])
|
|
||||||
await updateUserInfo({ latitude: location.latitude, longitude: location.longitude })
|
|
||||||
console.log('用户位置更新成功')
|
|
||||||
} catch (error) {
|
|
||||||
console.error('用户位置更新失败', error)
|
|
||||||
}
|
}
|
||||||
|
function onClose() {
|
||||||
|
setVisible(false)
|
||||||
}
|
}
|
||||||
|
|
||||||
const fetchDetail = async () => {
|
function previewImage(current_url) {
|
||||||
const res = await DetailService.getDetail(243/* Number(id) */)
|
Taro.previewImage({
|
||||||
if (res.code === 0) {
|
current: current_url,
|
||||||
console.log(res.data)
|
urls: venue_image_list.map(c => c.url),
|
||||||
setDetail(res.data)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// const calcBgMainColors = async () => {
|
|
||||||
// const textcolors: string[] = []
|
|
||||||
// // for (const index in images) {
|
|
||||||
// // const { textColor } = await getTextColorOnImage(images[index])
|
|
||||||
// // textcolors[index] = textColor
|
|
||||||
// // }
|
|
||||||
// if (detail?.image_list?.length > 0) {
|
|
||||||
// const { textColor } = await getTextColorOnImage(detail.image_list[0])
|
|
||||||
// textcolors[0] = textColor
|
|
||||||
// }
|
|
||||||
// setColors(textcolors)
|
|
||||||
// }
|
|
||||||
|
|
||||||
function handleShare() {
|
|
||||||
sharePopupRef.current.show()
|
|
||||||
}
|
|
||||||
|
|
||||||
const handleJoinGame = () => {
|
|
||||||
Taro.navigateTo({
|
|
||||||
url: `/pages/orderCheck/index?gameId=${243/* id */}`,
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
return (
|
||||||
|
<View className='detail-page-content-venue'>
|
||||||
|
{/* venue detail title and venue ordered status */}
|
||||||
|
<View className='venue-detail-title'>
|
||||||
|
<Text>场馆详情</Text>
|
||||||
|
{venue_image_list?.length > 0 ?
|
||||||
|
<>
|
||||||
|
<Text>·</Text>
|
||||||
|
<View className="venue-reserve-status" onClick={showScreenShot}>
|
||||||
|
<Text>已订场</Text>
|
||||||
|
<Image className="venue-reserve-screenshot" src={img.ICON_DETAIL_ARROW_RIGHT} />
|
||||||
|
</View>
|
||||||
|
</>
|
||||||
|
:
|
||||||
|
''
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
{/* venue detail content */}
|
||||||
|
<View className='venue-detail-content'>
|
||||||
|
{/* venue detail tags */}
|
||||||
|
<View className='venue-detail-content-tags'>
|
||||||
|
{insertDotInTags(venue_description_tag).map((tag, index) => (
|
||||||
|
<View key={index} className='venue-detail-content-tags-tag'>
|
||||||
|
<Text>{tag}</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
{/* venue remarks */}
|
||||||
|
<View className='venue-detail-content-remarks'>
|
||||||
|
<Text>{venue_description}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
<CommonPopup
|
||||||
|
visible={visible}
|
||||||
|
onClose={onClose}
|
||||||
|
round
|
||||||
|
hideFooter
|
||||||
|
position='bottom'
|
||||||
|
zIndex={1001}
|
||||||
|
>
|
||||||
|
<View className="venue-screenshot-title">预定截图</View>
|
||||||
|
<ScrollView
|
||||||
|
scrollY
|
||||||
|
className="venue-screenshot-scroll-view"
|
||||||
|
>
|
||||||
|
<View className="venue-screenshot-image-list">
|
||||||
|
{venue_image_list.map(item => {
|
||||||
|
return (
|
||||||
|
<View className="venue-screenshot-image-item" onClick={previewImage.bind(null, item.url)}>
|
||||||
|
<Image className="venue-screenshot-image-item-image" src={item.url} />
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</CommonPopup>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const tags = [{
|
function genNTRPRequirementText(min, max) {
|
||||||
name: '🕙 急招',
|
if (min && max) {
|
||||||
icon: '',
|
return `${min} - ${max} 之间`
|
||||||
}, {
|
} else if (max) {
|
||||||
name: '🔥 本周热门',
|
return `${max} 以上`
|
||||||
icon: '',
|
}
|
||||||
}, {
|
return '没有要求'
|
||||||
name: '🎉 新活动',
|
}
|
||||||
icon: '',
|
// 玩法要求
|
||||||
}, {
|
function GamePlayAndRequirement(props) {
|
||||||
name: '官方组织',
|
const { detail: { skill_level_min, skill_level_max, play_type, game_type } } = props
|
||||||
icon: '',
|
|
||||||
}]
|
|
||||||
|
|
||||||
const detailTags = ['室内', '硬地', '2号场', '有停车场', '有淋浴间', '有更衣室']
|
const requirements = [
|
||||||
|
{
|
||||||
const { title, longitude, latitude } = detail || {}
|
|
||||||
|
|
||||||
console.log(longitude, latitude, 2222)
|
|
||||||
|
|
||||||
const requirements = [{
|
|
||||||
title: 'NTRP水平要求',
|
title: 'NTRP水平要求',
|
||||||
desc: '2.0 - 4.5 之间',
|
desc: genNTRPRequirementText(skill_level_min, skill_level_max),
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
title: '活动玩法',
|
title: '活动玩法',
|
||||||
desc: '双打',
|
desc: play_type || '-',
|
||||||
}, {
|
},
|
||||||
|
{
|
||||||
title: '人员构成',
|
title: '人员构成',
|
||||||
desc: '个人球局 · 组织者参与活动',
|
desc: game_type || '-',
|
||||||
}]
|
}
|
||||||
|
]
|
||||||
|
return (
|
||||||
|
<View className='detail-page-content-gameplay-requirements'>
|
||||||
|
{/* title */}
|
||||||
|
<View className="gameplay-requirements-title">
|
||||||
|
<Text>玩法要求</Text>
|
||||||
|
</View>
|
||||||
|
{/* requirements */}
|
||||||
|
<View className='gameplay-requirements'>
|
||||||
|
{requirements.map((item, index) => (
|
||||||
|
<View key={index} className='gameplay-requirements-item'>
|
||||||
|
<Text className='gameplay-requirements-item-title'>{item.title}</Text>
|
||||||
|
<Text className='gameplay-requirements-item-desc'>{item.desc}</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const participants = detail?.participants || []
|
// 参与者
|
||||||
|
function Participants(props) {
|
||||||
|
const { detail = {} } = props
|
||||||
|
const participants = detail.participants || []
|
||||||
|
const organizer_id = Number(detail.publisher_id)
|
||||||
|
return (
|
||||||
|
<View className='detail-page-content-participants'>
|
||||||
|
<View className='participants-title'>
|
||||||
|
<Text>参与者</Text>
|
||||||
|
<Text>·</Text>
|
||||||
|
<Text>剩余空位 3</Text>
|
||||||
|
</View>
|
||||||
|
<View className='participants-list'>
|
||||||
|
{/* application */}
|
||||||
|
<View className='participants-list-application' onClick={() => { Taro.showToast({ title: 'To be continued', icon: 'none' }) }}>
|
||||||
|
<Image className='participants-list-application-icon' src={img.ICON_DETAIL_APPLICATION_ADD} />
|
||||||
|
<Text className='participants-list-application-text'>申请加入</Text>
|
||||||
|
</View>
|
||||||
|
{/* participants list */}
|
||||||
|
<ScrollView className='participants-list-scroll' scrollX>
|
||||||
|
<View className='participants-list-scroll-content' style={{ width: `${participants.length * 103 + (participants.length - 1) * 8}px` }}>
|
||||||
|
{participants.map((participant) => {
|
||||||
|
const { user: { avatar_url, nickname, level, id: participant_user_id } } = participant
|
||||||
|
const role = participant_user_id === organizer_id ? '组织者' : '参与者'
|
||||||
|
return (
|
||||||
|
<View key={participant.id} className='participants-list-item'>
|
||||||
|
<Avatar className='participants-list-item-avatar' src={avatar_url} />
|
||||||
|
<Text className='participants-list-item-name'>{nickname || '未知'}</Text>
|
||||||
|
<Text className='participants-list-item-level'>{level || '未知'}</Text>
|
||||||
|
<Text className='participants-list-item-role'>{role}</Text>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})}
|
||||||
|
</View>
|
||||||
|
</ScrollView>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
const supplementalNotesTags = ['仅限男生', '装备自备', '其他']
|
function SupplementalNotes(props) {
|
||||||
|
const { detail: { description, description_tag = [] } } = props
|
||||||
|
return (
|
||||||
|
<View className='detail-page-content-supplemental-notes'>
|
||||||
|
<View className='supplemental-notes-title'>
|
||||||
|
<Text>补充说明</Text>
|
||||||
|
</View>
|
||||||
|
<View className='supplemental-notes-content'>
|
||||||
|
{/* supplemental notes tags */}
|
||||||
|
<View className='supplemental-notes-content-tags'>
|
||||||
|
{insertDotInTags(description_tag).map((tag, index) => (
|
||||||
|
<View key={index} className='supplemental-notes-content-tags-tag'>
|
||||||
|
<Text>{tag}</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
{/* supplemental notes content */}
|
||||||
|
<View className='supplemental-notes-content-text'>
|
||||||
|
<Text>{description}</Text>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function OrganizerInfo(props) {
|
||||||
const recommendGames = [
|
const recommendGames = [
|
||||||
{
|
{
|
||||||
title: '黄浦日场对拉',
|
title: '黄浦日场对拉',
|
||||||
@@ -366,200 +444,7 @@ function Index() {
|
|||||||
playType: '双打',
|
playType: '双打',
|
||||||
},
|
},
|
||||||
]
|
]
|
||||||
|
|
||||||
function handleBack() {
|
|
||||||
const pages = Taro.getCurrentPages()
|
|
||||||
if (pages.length <= 1) {
|
|
||||||
Taro.redirectTo({
|
|
||||||
url: '/pages/list/index',
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
Taro.navigateBack()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
console.log('detail', detail)
|
|
||||||
return (
|
return (
|
||||||
<View className='detail-page'>
|
|
||||||
{/* custom navbar */}
|
|
||||||
<view className="custom-navbar">
|
|
||||||
<View className='detail-navigator'>
|
|
||||||
<View className='detail-navigator-back' onClick={handleBack}>
|
|
||||||
<Image className='detail-navigator-back-icon' src={img.ICON_ARROW_LEFT} />
|
|
||||||
</View>
|
|
||||||
<View className='detail-navigator-icon'>
|
|
||||||
<Image className='detail-navigator-logo-icon' src={img.ICON_LOGO_GO} />
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</view>
|
|
||||||
<View className='detail-page-bg' style={detail?.image_list?.[0] ? { backgroundImage: `url(${detail?.image_list?.[0]})` } : {}} />
|
|
||||||
<View className='detail-page-bg-text' />
|
|
||||||
{/* swiper */}
|
|
||||||
<View className="detail-swiper-container">
|
|
||||||
<View className="detail-swiper-scroll-container">
|
|
||||||
{
|
|
||||||
detail?.image_list?.length > 0 && detail?.image_list.map((item, index) => {
|
|
||||||
return (
|
|
||||||
<View className='detail-swiper-item' key={index}>
|
|
||||||
<Image
|
|
||||||
src={item}
|
|
||||||
mode="aspectFill"
|
|
||||||
className='detail-swiper-item-image'
|
|
||||||
/>
|
|
||||||
</View>
|
|
||||||
)
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* <Swiper
|
|
||||||
className='detail-swiper'
|
|
||||||
indicatorDots={false}
|
|
||||||
circular
|
|
||||||
nextMargin="20px"
|
|
||||||
onChange={(e) => { setCurrent(e.detail.current) }}
|
|
||||||
>
|
|
||||||
{images.map((imageUrl, index) => (
|
|
||||||
<SwiperItem
|
|
||||||
key={index}
|
|
||||||
className='detail-swiper-item'
|
|
||||||
>
|
|
||||||
<Image
|
|
||||||
src={imageUrl}
|
|
||||||
mode="aspectFill"
|
|
||||||
className='detail-swiper-item-image'
|
|
||||||
style={{
|
|
||||||
transform: index !== current ? 'scale(0.8) translateX(-12%)' : 'scale(0.95)', // 前后图缩小
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</SwiperItem>
|
|
||||||
))}
|
|
||||||
</Swiper> */}
|
|
||||||
{/* content */}
|
|
||||||
<View className='detail-page-content'>
|
|
||||||
{/* avatar and tags */}
|
|
||||||
<View className='detail-page-content-avatar-tags'>
|
|
||||||
<View className='detail-page-content-avatar-tags-avatar'>
|
|
||||||
{/* network image mock */}
|
|
||||||
<Image className='detail-page-content-avatar-tags-avatar-image' src="https://img.yzcdn.cn/vant/cat.jpeg" />
|
|
||||||
</View>
|
|
||||||
<View className='detail-page-content-avatar-tags-tags'>
|
|
||||||
{tags.map((tag, index) => (
|
|
||||||
<View key={index} className='detail-page-content-avatar-tags-tags-tag'>
|
|
||||||
{tag.icon && <Image src={tag.icon} />}
|
|
||||||
<Text>{tag.name}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* title */}
|
|
||||||
<View className='detail-page-content-title'>
|
|
||||||
<Text className='detail-page-content-title-text'>{title}</Text>
|
|
||||||
</View>
|
|
||||||
{/* Date and Place and weather */}
|
|
||||||
<GameInfo detail={detail} currentLocation={currentLocation} />
|
|
||||||
{/* detail */}
|
|
||||||
<View className='detail-page-content-detail'>
|
|
||||||
{/* venue detail title and venue ordered status */}
|
|
||||||
<View className='venue-detail-title'>
|
|
||||||
<Text>场馆详情</Text>
|
|
||||||
<Text>·</Text>
|
|
||||||
<Text>已订场</Text>
|
|
||||||
<Popover
|
|
||||||
title="场地预定截图"
|
|
||||||
description={<View>
|
|
||||||
<Image src="https://img.yzcdn.cn/vant/cat.jpeg" />
|
|
||||||
</View>}
|
|
||||||
location='top'
|
|
||||||
visible={false}
|
|
||||||
>
|
|
||||||
<Image className='venue-detail-title-notice-icon' src={img.ICON_DETAIL_NOTICE} />
|
|
||||||
</Popover>
|
|
||||||
</View>
|
|
||||||
{/* venue detail content */}
|
|
||||||
<View className='venue-detail-content'>
|
|
||||||
{/* venue detail tags */}
|
|
||||||
<View className='venue-detail-content-tags'>
|
|
||||||
{insertDotInTags(detailTags).map((tag, index) => (
|
|
||||||
<View key={index} className='venue-detail-content-tags-tag'>
|
|
||||||
<Text>{tag}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
{/* venue remarks */}
|
|
||||||
<View className='venue-detail-content-remarks'>
|
|
||||||
<Text>其他这是用户在场地补充描述里自己写的东西啦啦啦啦啦啦啦啦啦啦啦啦</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* gameplay requirements */}
|
|
||||||
<View className='detail-page-content-gameplay-requirements'>
|
|
||||||
{/* title */}
|
|
||||||
<View className="gameplay-requirements-title">
|
|
||||||
<Text>玩法要求</Text>
|
|
||||||
</View>
|
|
||||||
{/* requirements */}
|
|
||||||
<View className='gameplay-requirements'>
|
|
||||||
{requirements.map((item, index) => (
|
|
||||||
<View key={index} className='gameplay-requirements-item'>
|
|
||||||
<Text className='gameplay-requirements-item-title'>{item.title}</Text>
|
|
||||||
<Text className='gameplay-requirements-item-desc'>{item.desc}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* participants */}
|
|
||||||
<View className='detail-page-content-participants'>
|
|
||||||
<View className='participants-title'>
|
|
||||||
<Text>参与者</Text>
|
|
||||||
<Text>·</Text>
|
|
||||||
<Text>剩余空位 3</Text>
|
|
||||||
</View>
|
|
||||||
<View className='participants-list'>
|
|
||||||
{/* application */}
|
|
||||||
<View className='participants-list-application' onClick={() => { Taro.showToast({ title: 'To be continued', icon: 'none' }) }}>
|
|
||||||
<Image className='participants-list-application-icon' src={img.ICON_DETAIL_APPLICATION_ADD} />
|
|
||||||
<Text className='participants-list-application-text'>申请加入</Text>
|
|
||||||
</View>
|
|
||||||
{/* participants list */}
|
|
||||||
<ScrollView className='participants-list-scroll' scrollX>
|
|
||||||
<View className='participants-list-scroll-content' style={{ width: `${participants.length * 103 + (participants.length - 1) * 8}px` }}>
|
|
||||||
{participants.map((participant) => (
|
|
||||||
<View key={participant.id} className='participants-list-item'>
|
|
||||||
{/* <Avatar className='participants-list-item-avatar' src={participant.user.avatar_url} /> */}
|
|
||||||
{/* network image mock random */}
|
|
||||||
<Avatar className='participants-list-item-avatar' src={`https://picsum.photos/800/600?random=${participant.id}`} />
|
|
||||||
<Text className='participants-list-item-name'>{participant.user.nickname || '未知'}</Text>
|
|
||||||
<Text className='participants-list-item-level'>{participant.level || '未知'}</Text>
|
|
||||||
<Text className='participants-list-item-role'>{participant.role || '参与者'}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
</ScrollView>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* supplemental notes */}
|
|
||||||
<View className='detail-page-content-supplemental-notes'>
|
|
||||||
<View className='supplemental-notes-title'>
|
|
||||||
<Text>补充说明</Text>
|
|
||||||
</View>
|
|
||||||
<View className='supplemental-notes-content'>
|
|
||||||
{/* supplemental notes tags */}
|
|
||||||
<View className='supplemental-notes-content-tags'>
|
|
||||||
{insertDotInTags(supplementalNotesTags).map((tag, index) => (
|
|
||||||
<View key={index} className='supplemental-notes-content-tags-tag'>
|
|
||||||
<Text>{tag}</Text>
|
|
||||||
</View>
|
|
||||||
))}
|
|
||||||
</View>
|
|
||||||
{/* supplemental notes content */}
|
|
||||||
<View className='supplemental-notes-content-text'>
|
|
||||||
<Text>其他这是用户在补充说明里自己写的东西啦啦啦啦啦啦啦啦啦啦啦啦其他这是用户在补充说明里自己写的东西啦啦啦啦啦啦啦啦啦啦啦啦</Text>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
</View>
|
|
||||||
{/* organizer and recommend games by organizer */}
|
|
||||||
<View className='detail-page-content-organizer-recommend-games'>
|
<View className='detail-page-content-organizer-recommend-games'>
|
||||||
{/* orgnizer title */}
|
{/* orgnizer title */}
|
||||||
<View className='organizer-title'>
|
<View className='organizer-title'>
|
||||||
@@ -635,6 +520,145 @@ function Index() {
|
|||||||
</ScrollView>
|
</ScrollView>
|
||||||
</View>
|
</View>
|
||||||
</View>
|
</View>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function Index() {
|
||||||
|
const [detail, setDetail] = useState<any>({})
|
||||||
|
const { params } = useRouter()
|
||||||
|
const [currentLocation, setCurrentLocation] = useState<[number, number]>([0, 0])
|
||||||
|
const { id, from } = params
|
||||||
|
const { fetchUserInfo, updateUserInfo } = useUserActions()
|
||||||
|
|
||||||
|
const sharePopupRef = useRef<any>(null)
|
||||||
|
|
||||||
|
useDidShow(async () => {
|
||||||
|
await updateLocation()
|
||||||
|
await fetchUserInfo()
|
||||||
|
await fetchDetail()
|
||||||
|
})
|
||||||
|
|
||||||
|
const updateLocation = async () => {
|
||||||
|
try {
|
||||||
|
const location = await getCurrentLocation()
|
||||||
|
setCurrentLocation([location.latitude, location.longitude])
|
||||||
|
await updateUserInfo({ latitude: location.latitude, longitude: location.longitude })
|
||||||
|
} catch (error) {
|
||||||
|
console.error('用户位置更新失败', error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const fetchDetail = async () => {
|
||||||
|
const res = await DetailService.getDetail(243/* Number(id) */)
|
||||||
|
if (res.code === 0) {
|
||||||
|
setDetail(res.data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleShare() {
|
||||||
|
sharePopupRef.current.show()
|
||||||
|
}
|
||||||
|
|
||||||
|
const handleJoinGame = () => {
|
||||||
|
Taro.navigateTo({
|
||||||
|
url: `/pages/orderCheck/index?gameId=${243/* id */}`,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
const tags = [{
|
||||||
|
name: '🕙 急招',
|
||||||
|
icon: '',
|
||||||
|
}, {
|
||||||
|
name: '🔥 本周热门',
|
||||||
|
icon: '',
|
||||||
|
}, {
|
||||||
|
name: '🎉 新活动',
|
||||||
|
icon: '',
|
||||||
|
}, {
|
||||||
|
name: '官方组织',
|
||||||
|
icon: '',
|
||||||
|
}]
|
||||||
|
|
||||||
|
function handleBack() {
|
||||||
|
const pages = Taro.getCurrentPages()
|
||||||
|
if (pages.length <= 1) {
|
||||||
|
Taro.redirectTo({
|
||||||
|
url: '/pages/list/index',
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
Taro.navigateBack()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
console.log('detail', detail)
|
||||||
|
const backgroundImage = detail?.image_list?.[0] ? { backgroundImage: `url(${detail?.image_list?.[0]})` } : {}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<View className='detail-page'>
|
||||||
|
{/* custom navbar */}
|
||||||
|
<view className="custom-navbar">
|
||||||
|
<View className='detail-navigator'>
|
||||||
|
<View className='detail-navigator-back' onClick={handleBack}>
|
||||||
|
<Image className='detail-navigator-back-icon' src={img.ICON_ARROW_LEFT} />
|
||||||
|
</View>
|
||||||
|
<View className='detail-navigator-icon'>
|
||||||
|
<Image className='detail-navigator-logo-icon' src={img.ICON_LOGO_GO} />
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
</view>
|
||||||
|
<View className='detail-page-bg' style={backgroundImage} />
|
||||||
|
{/* swiper */}
|
||||||
|
<View className="detail-swiper-container">
|
||||||
|
<View className="detail-swiper-scroll-container">
|
||||||
|
{
|
||||||
|
detail?.image_list?.length > 0 && detail?.image_list.map((item, index) => {
|
||||||
|
return (
|
||||||
|
<View className='detail-swiper-item' key={index}>
|
||||||
|
<Image
|
||||||
|
src={item}
|
||||||
|
mode="aspectFill"
|
||||||
|
className='detail-swiper-item-image'
|
||||||
|
/>
|
||||||
|
</View>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{/* content */}
|
||||||
|
<View className='detail-page-content'>
|
||||||
|
{/* avatar and tags */}
|
||||||
|
<View className='detail-page-content-avatar-tags'>
|
||||||
|
<View className='detail-page-content-avatar-tags-avatar'>
|
||||||
|
{/* network image mock */}
|
||||||
|
<Image className='detail-page-content-avatar-tags-avatar-image' src="https://img.yzcdn.cn/vant/cat.jpeg" />
|
||||||
|
</View>
|
||||||
|
<View className='detail-page-content-avatar-tags-tags'>
|
||||||
|
{tags.map((tag, index) => (
|
||||||
|
<View key={index} className='detail-page-content-avatar-tags-tags-tag'>
|
||||||
|
{tag.icon && <Image src={tag.icon} />}
|
||||||
|
<Text>{tag.name}</Text>
|
||||||
|
</View>
|
||||||
|
))}
|
||||||
|
</View>
|
||||||
|
</View>
|
||||||
|
{/* title */}
|
||||||
|
<View className='detail-page-content-title'>
|
||||||
|
<Text className='detail-page-content-title-text'>{detail.title}</Text>
|
||||||
|
</View>
|
||||||
|
{/* Date and Place and weather */}
|
||||||
|
<GameInfo detail={detail} currentLocation={currentLocation} />
|
||||||
|
{/* detail */}
|
||||||
|
<VenueInfo detail={detail} />
|
||||||
|
{/* gameplay requirements */}
|
||||||
|
<GamePlayAndRequirement detail={detail} />
|
||||||
|
{/* participants */}
|
||||||
|
<Participants detail={detail} />
|
||||||
|
{/* supplemental notes */}
|
||||||
|
<SupplementalNotes detail={detail} />
|
||||||
|
{/* organizer and recommend games by organizer */}
|
||||||
|
<OrganizerInfo detail={detail} />
|
||||||
{/* sticky bottom action bar */}
|
{/* sticky bottom action bar */}
|
||||||
<StickyButton handleShare={handleShare} handleJoinGame={handleJoinGame} detail={detail} />
|
<StickyButton handleShare={handleShare} handleJoinGame={handleJoinGame} detail={detail} />
|
||||||
{/* share popup */}
|
{/* share popup */}
|
||||||
|
|||||||
@@ -45,7 +45,6 @@ const LoginPage: React.FC = () => {
|
|||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (redirect) {
|
if (redirect) {
|
||||||
console.log('redirect:', decodeURIComponent(redirect))
|
|
||||||
Taro.redirectTo({ url: decodeURIComponent(redirect) });
|
Taro.redirectTo({ url: decodeURIComponent(redirect) });
|
||||||
} else {
|
} else {
|
||||||
Taro.redirectTo({ url: '/pages/list/index' });
|
Taro.redirectTo({ url: '/pages/list/index' });
|
||||||
|
|||||||
@@ -211,12 +211,13 @@ class HttpService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
console.log(this.buildHeaders(config), 1111);
|
const reqHeader = this.buildHeaders(config)
|
||||||
|
this.log('info', 'HTTP REQ HEADER: ', reqHeader)
|
||||||
const requestConfig = {
|
const requestConfig = {
|
||||||
url: fullUrl,
|
url: fullUrl,
|
||||||
method: method,
|
method: method,
|
||||||
data: method !== 'GET' ? data : undefined,
|
data: method !== 'GET' ? data : undefined,
|
||||||
header: this.buildHeaders(config),
|
header: reqHeader,
|
||||||
timeout: this.timeout
|
timeout: this.timeout
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,6 @@ export const useUser = create<UserState>()((set) => ({
|
|||||||
},
|
},
|
||||||
updateUserInfo: async(userInfo: Partial<UserInfoType>) => {
|
updateUserInfo: async(userInfo: Partial<UserInfoType>) => {
|
||||||
const res = await updateUserProfile(userInfo)
|
const res = await updateUserProfile(userInfo)
|
||||||
console.log(res)
|
|
||||||
set({ user: res.data })
|
set({ user: res.data })
|
||||||
}
|
}
|
||||||
}))
|
}))
|
||||||
|
|||||||
Reference in New Issue
Block a user