|
After Width: | Height: | Size: 28 KiB |
|
After Width: | Height: | Size: 3.2 KiB |
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 130 KiB |
|
After Width: | Height: | Size: 4.8 KiB |
|
After Width: | Height: | Size: 4.6 KiB |
|
After Width: | Height: | Size: 101 KiB |
@ -0,0 +1,519 @@ |
|||||||
|
/** |
||||||
|
* 门店详情页面样式 |
||||||
|
*/ |
||||||
|
.store_detail_page { |
||||||
|
min-height: 100vh; |
||||||
|
background-color: #121212; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
// 自定义透明导航栏 |
||||||
|
.custom_nav_bar { |
||||||
|
position: fixed; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
right: 0; |
||||||
|
z-index: 100; |
||||||
|
background-color: transparent; |
||||||
|
|
||||||
|
.nav_content { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
padding: 0 30px; |
||||||
|
|
||||||
|
.nav_buttons { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
background-color: rgba(0, 0, 0, 0.3); |
||||||
|
border-radius: 32px; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
.nav_btn { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
width: 66px; |
||||||
|
height: 64px; |
||||||
|
|
||||||
|
.nav_icon { |
||||||
|
width: 36px; |
||||||
|
height: 36px; |
||||||
|
color: #FFFFFF; |
||||||
|
|
||||||
|
&.back_icon { |
||||||
|
transform: rotate(180deg); |
||||||
|
} |
||||||
|
|
||||||
|
&.home_icon { |
||||||
|
width: 36px; |
||||||
|
height: 36px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.nav_divider { |
||||||
|
width: 1px; |
||||||
|
height: 36px; |
||||||
|
background-color: rgba(255, 255, 255, 0.3); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 轮播图区域 |
||||||
|
.swiper_container { |
||||||
|
width: 100%; |
||||||
|
height: 465px; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
.swiper { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
} |
||||||
|
|
||||||
|
.swiper_image { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.swiper_indicator { |
||||||
|
position: absolute; |
||||||
|
bottom: 40px; |
||||||
|
left: 50%; |
||||||
|
transform: translateX(-50%); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 内容区域 |
||||||
|
.content_area { |
||||||
|
position: relative; |
||||||
|
margin-top: -20px; |
||||||
|
background-color: #121212; |
||||||
|
border-top-left-radius: 25px; |
||||||
|
border-top-right-radius: 25px; |
||||||
|
padding: 30px; |
||||||
|
padding-bottom: 50px; |
||||||
|
|
||||||
|
// 门店信息 |
||||||
|
.store_info_section { |
||||||
|
margin-bottom: 33px; |
||||||
|
|
||||||
|
.store_header { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
|
||||||
|
.store_name { |
||||||
|
font-size: 42px; |
||||||
|
color: #FFFFFF; |
||||||
|
font-weight: 500; |
||||||
|
} |
||||||
|
|
||||||
|
.store_actions { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
gap: 30px; |
||||||
|
|
||||||
|
.action_icon { |
||||||
|
width: 33px; |
||||||
|
height: 33px; |
||||||
|
|
||||||
|
&.phone, |
||||||
|
&.share { |
||||||
|
width: 33px; |
||||||
|
height: 33px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.store_location { |
||||||
|
display: flex; |
||||||
|
align-items: flex-start; |
||||||
|
justify-content: space-between; |
||||||
|
padding: 30px 0; |
||||||
|
|
||||||
|
.location_left { |
||||||
|
display: flex; |
||||||
|
align-items: flex-start; |
||||||
|
gap: 10px; |
||||||
|
flex: 1; |
||||||
|
|
||||||
|
.location_icon { |
||||||
|
width: 16px; |
||||||
|
height: 20px; |
||||||
|
flex-shrink: 0; |
||||||
|
margin-top: 5px; |
||||||
|
} |
||||||
|
|
||||||
|
.location_text { |
||||||
|
font-size: 25px; |
||||||
|
color: #E5E5E5; |
||||||
|
line-height: 1.5; |
||||||
|
flex: 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.distance_text { |
||||||
|
font-size: 25px; |
||||||
|
color: #E5E5E5; |
||||||
|
flex-shrink: 0; |
||||||
|
margin-left: 20px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
.store_price { |
||||||
|
display: flex; |
||||||
|
gap: 30px; |
||||||
|
|
||||||
|
.price_text { |
||||||
|
font-size: 25px; |
||||||
|
color: #B8B8B8; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// VIP 横幅 |
||||||
|
.vip_banner { |
||||||
|
width: 690px; |
||||||
|
height: 83px; |
||||||
|
position: relative; |
||||||
|
margin-bottom: 30px; |
||||||
|
|
||||||
|
.vip_bg { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
border-radius: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.vip_btn { |
||||||
|
position: absolute; |
||||||
|
right: 30px; |
||||||
|
top: 50%; |
||||||
|
transform: translateY(-50%); |
||||||
|
width: 158px; |
||||||
|
height: 58px; |
||||||
|
background: #614929; |
||||||
|
border-radius: 29px; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
.vip_btn_text { |
||||||
|
font-size: 25px; |
||||||
|
color: #E0C699; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Tab 导航 |
||||||
|
.tab_container { |
||||||
|
display: flex; |
||||||
|
justify-content: space-around; |
||||||
|
padding: 20px 0; |
||||||
|
margin-bottom: 30px; |
||||||
|
|
||||||
|
.tab_item { |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
.tab_count{ |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
gap: 5px; |
||||||
|
margin-bottom: 10px; |
||||||
|
.count_label { |
||||||
|
font-size: 26px; |
||||||
|
color: #FFFFFF; |
||||||
|
} |
||||||
|
|
||||||
|
.count_value { |
||||||
|
font-size: 26px; |
||||||
|
color: #01CA68; |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
.tab_name { |
||||||
|
font-size: 36px; |
||||||
|
color: #FFFFFF; |
||||||
|
} |
||||||
|
|
||||||
|
.tab_indicator { |
||||||
|
width: 29px; |
||||||
|
height: 8px; |
||||||
|
background: linear-gradient(-30deg, #0099E6, #33FF99); |
||||||
|
border-radius: 4px; |
||||||
|
margin-top: 10px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 台球和棋牌区域 |
||||||
|
.tables_section { |
||||||
|
padding: 30px; |
||||||
|
background: #202029; |
||||||
|
border-radius: 13px; |
||||||
|
|
||||||
|
// 分类区块 |
||||||
|
.category_block { |
||||||
|
margin-bottom: 30px; |
||||||
|
} |
||||||
|
|
||||||
|
// 分类头部 |
||||||
|
.category_header { |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: space-between; |
||||||
|
margin-bottom: 20px; |
||||||
|
|
||||||
|
.category_name { |
||||||
|
font-size: 33px; |
||||||
|
color: #FFFFFF; |
||||||
|
font-weight: 500; |
||||||
|
} |
||||||
|
|
||||||
|
.category_price { |
||||||
|
display: flex; |
||||||
|
gap: 20px; |
||||||
|
|
||||||
|
.vip_price { |
||||||
|
font-size: 23px; |
||||||
|
color: #F5CFA9; |
||||||
|
} |
||||||
|
|
||||||
|
.original_price, |
||||||
|
.time_range, |
||||||
|
.price_info { |
||||||
|
font-size: 23px; |
||||||
|
color: #999999; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 台球桌网格 |
||||||
|
.tables_grid { |
||||||
|
display: grid; |
||||||
|
gap: 20px; |
||||||
|
|
||||||
|
&.billiard_grid { |
||||||
|
grid-template-columns: repeat(2, 1fr); |
||||||
|
} |
||||||
|
|
||||||
|
&.chess_grid { |
||||||
|
grid-template-columns: repeat(2, 1fr); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 台球桌卡片 |
||||||
|
.table_card { |
||||||
|
position: relative; |
||||||
|
border-radius: 12px; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
&.billiard_card { |
||||||
|
width: 100%; |
||||||
|
height: 204px; |
||||||
|
} |
||||||
|
|
||||||
|
&.chess_card { |
||||||
|
width: 100%; |
||||||
|
height: 300px; |
||||||
|
} |
||||||
|
|
||||||
|
.table_bg { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
// 蒙版 |
||||||
|
.table_mask { |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
background-color: rgba(0, 0, 0, 0.4); |
||||||
|
z-index: 1; |
||||||
|
} |
||||||
|
|
||||||
|
// 状态标签(棋牌) |
||||||
|
.status_tag { |
||||||
|
position: absolute; |
||||||
|
top: 15px; |
||||||
|
left: 15px; |
||||||
|
padding: 5px 12px; |
||||||
|
border-radius: 4px; |
||||||
|
z-index: 2; |
||||||
|
|
||||||
|
&.available { |
||||||
|
background-color: #03C175; |
||||||
|
} |
||||||
|
|
||||||
|
&.using { |
||||||
|
background-color: #FF4D4F; |
||||||
|
} |
||||||
|
|
||||||
|
.tag_text { |
||||||
|
font-size: 21px; |
||||||
|
color: #FFFFFF; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 内容区域 |
||||||
|
.table_content { |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
z-index: 2; |
||||||
|
|
||||||
|
.table_name { |
||||||
|
font-size: 33px; |
||||||
|
color: #FFFFFF; |
||||||
|
font-weight: bold; |
||||||
|
margin-bottom: 15px; |
||||||
|
text-align: center; |
||||||
|
} |
||||||
|
|
||||||
|
.table_buttons { |
||||||
|
display: flex; |
||||||
|
background-color: #00B05C; |
||||||
|
border-radius: 33px; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
.table_btn { |
||||||
|
font-size: 27px; |
||||||
|
color: #FFFFFF; |
||||||
|
padding: 15px 30px; |
||||||
|
background-color: transparent; |
||||||
|
position: relative; |
||||||
|
|
||||||
|
// 中间分隔线 |
||||||
|
&:not(:last-child)::after { |
||||||
|
content: ''; |
||||||
|
position: absolute; |
||||||
|
right: 0; |
||||||
|
top: 50%; |
||||||
|
transform: translateY(-50%); |
||||||
|
width: 1px; |
||||||
|
height: 60%; |
||||||
|
background-color: rgba(255, 255, 255, 0.3); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 单个按钮样式 |
||||||
|
.table_btn_single { |
||||||
|
font-size: 27px; |
||||||
|
color: #FFFFFF; |
||||||
|
padding: 15px 36px; |
||||||
|
border-radius: 33px; |
||||||
|
background-color: #00B05C; |
||||||
|
} |
||||||
|
|
||||||
|
.table_status { |
||||||
|
font-size: 25px; |
||||||
|
color: #FFFFFF; |
||||||
|
text-align: center; |
||||||
|
white-space: pre-line; |
||||||
|
line-height: 1.6; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 棋牌区域 |
||||||
|
.chess_section { |
||||||
|
margin-top: 40px; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 存杆柜区域 |
||||||
|
.storage_section { |
||||||
|
margin-top: 40px; |
||||||
|
|
||||||
|
.section_title { |
||||||
|
font-size: 33px; |
||||||
|
color: #FFFFFF; |
||||||
|
font-weight: 500; |
||||||
|
margin-bottom: 20px; |
||||||
|
display: block; |
||||||
|
} |
||||||
|
|
||||||
|
.storage_card { |
||||||
|
width: 100%; |
||||||
|
height: 255px; |
||||||
|
position: relative; |
||||||
|
border-radius: 12px; |
||||||
|
overflow: hidden; |
||||||
|
|
||||||
|
.storage_bg { |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
} |
||||||
|
|
||||||
|
.storage_content { |
||||||
|
position: absolute; |
||||||
|
top: 0; |
||||||
|
left: 0; |
||||||
|
width: 100%; |
||||||
|
height: 100%; |
||||||
|
padding: 30px; |
||||||
|
display: flex; |
||||||
|
flex-direction: column; |
||||||
|
justify-content: flex-start; |
||||||
|
z-index: 1; |
||||||
|
|
||||||
|
.storage_status { |
||||||
|
font-size: 29px; |
||||||
|
color: #FFFFFF; |
||||||
|
margin-bottom: 10px; |
||||||
|
} |
||||||
|
|
||||||
|
.storage_price { |
||||||
|
font-size: 25px; |
||||||
|
color: #03C175; |
||||||
|
margin-bottom: 20px; |
||||||
|
} |
||||||
|
|
||||||
|
.storage_btn { |
||||||
|
width: 120px; |
||||||
|
height: 50px; |
||||||
|
background-color: #21212A; |
||||||
|
border-radius: 25px; |
||||||
|
display: flex; |
||||||
|
align-items: center; |
||||||
|
justify-content: center; |
||||||
|
|
||||||
|
.btn_text { |
||||||
|
font-size: 27px; |
||||||
|
color: #03C175; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 底部提示 |
||||||
|
.end_tip { |
||||||
|
display: block; |
||||||
|
text-align: center; |
||||||
|
font-size: 25px; |
||||||
|
color: #666666; |
||||||
|
margin-top: 40px; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,472 @@ |
|||||||
|
/** |
||||||
|
* 门店详情页面 |
||||||
|
*/ |
||||||
|
import { View, Text, Image } from '@tarojs/components' |
||||||
|
import Taro, { useLoad } from '@tarojs/taro' |
||||||
|
import { useState, useEffect } from 'react' |
||||||
|
import { Swiper } from '@taroify/core' |
||||||
|
import { Arrow, HomeOutlined } from '@taroify/icons' |
||||||
|
import './index.scss' |
||||||
|
|
||||||
|
// 页面配置 - 隐藏导航栏
|
||||||
|
definePageConfig({ |
||||||
|
navigationStyle: 'custom', |
||||||
|
navigationBarTitleText: '' |
||||||
|
}) |
||||||
|
|
||||||
|
// 图片资源
|
||||||
|
import phoneIcon from '../images/phone.png' |
||||||
|
import locationIcon from '../images/locationicon.png' |
||||||
|
import shareIcon from '../images/share.png' |
||||||
|
import payVipBg from '../images/payVip.png' |
||||||
|
import billiardTabBg from '../images/billiardtab.png' |
||||||
|
import paiTabBg from '../images/paitab.png' |
||||||
|
import storeBoxBg from '../images/storeBox.png' |
||||||
|
import swBG from '../../assets/big/swBG.png' |
||||||
|
|
||||||
|
// 台球桌状态类型
|
||||||
|
type TableStatus = 'available' | 'using' | 'waiting' | 'reserved' |
||||||
|
|
||||||
|
// 台球桌数据接口
|
||||||
|
interface BilliardTable { |
||||||
|
id: string |
||||||
|
name: string |
||||||
|
status: TableStatus |
||||||
|
waitTime?: string |
||||||
|
buttons: Array<{ |
||||||
|
type: 'start' | 'reserve' |
||||||
|
text: string |
||||||
|
}> |
||||||
|
} |
||||||
|
|
||||||
|
// 台球桌分类数据
|
||||||
|
interface BilliardCategory { |
||||||
|
name: string |
||||||
|
vipPrice: string |
||||||
|
originalPrice: string |
||||||
|
tables: BilliardTable[] |
||||||
|
} |
||||||
|
|
||||||
|
// 棋牌桌数据接口
|
||||||
|
interface ChessTable { |
||||||
|
id: string |
||||||
|
name: string |
||||||
|
status: TableStatus |
||||||
|
statusText?: string |
||||||
|
buttonText?: string |
||||||
|
waitTime?: string |
||||||
|
} |
||||||
|
|
||||||
|
// 存杆柜数据接口
|
||||||
|
interface StorageCabinet { |
||||||
|
id: string |
||||||
|
status: 'available' | 'rented' |
||||||
|
price: string |
||||||
|
} |
||||||
|
|
||||||
|
const StoreDetail = () => { |
||||||
|
const [activeTab, setActiveTab] = useState(0) // 0: 中式台球, 1: 棋牌, 2: 存杆柜
|
||||||
|
const [statusBarHeight, setStatusBarHeight] = useState(20) // 状态栏高度
|
||||||
|
const [navBarHeight, setNavBarHeight] = useState(44) // 导航栏内容高度
|
||||||
|
|
||||||
|
// 获取系统信息设置导航栏高度
|
||||||
|
useEffect(() => { |
||||||
|
const systemInfo = Taro.getSystemInfoSync() |
||||||
|
setStatusBarHeight(systemInfo.statusBarHeight || 20) |
||||||
|
// 微信小程序胶囊按钮信息
|
||||||
|
if (process.env.TARO_ENV === 'weapp') { |
||||||
|
const menuButtonInfo = Taro.getMenuButtonBoundingClientRect() |
||||||
|
const navHeight = (menuButtonInfo.top - (systemInfo.statusBarHeight || 0)) * 2 + menuButtonInfo.height |
||||||
|
setNavBarHeight(navHeight) |
||||||
|
} |
||||||
|
}, []) |
||||||
|
|
||||||
|
// 返回上一页
|
||||||
|
const handleBack = () => { |
||||||
|
const pages = Taro.getCurrentPages() |
||||||
|
if (pages.length > 1) { |
||||||
|
Taro.navigateBack() |
||||||
|
} else { |
||||||
|
Taro.switchTab({ url: '/pages/index/index' }) |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// 返回首页
|
||||||
|
const handleGoHome = () => { |
||||||
|
Taro.switchTab({ url: '/pages/index/index' }) |
||||||
|
} |
||||||
|
|
||||||
|
// 门店信息
|
||||||
|
const storeInfo = { |
||||||
|
name: '北京黑八大师联盟球厅店', |
||||||
|
address: '北京市XXX区XXX街道XXX路XXXXXX大厦101', |
||||||
|
distance: '10.05km', |
||||||
|
billiardPrice: '¥10.00起', |
||||||
|
chessPrice: '¥20.00起' |
||||||
|
} |
||||||
|
|
||||||
|
// Tab 数据
|
||||||
|
const tabs = [ |
||||||
|
{ name: '中式台球', idleCount: 5 }, |
||||||
|
{ name: '棋牌', idleCount: 1 }, |
||||||
|
{ name: '存杆柜', idleCount: 0 } |
||||||
|
] |
||||||
|
|
||||||
|
// 台球桌分类数据
|
||||||
|
const [billiardCategories] = useState<BilliardCategory[]>([ |
||||||
|
{ |
||||||
|
name: '独牙&来力.山岩', |
||||||
|
vipPrice: '¥8.00/小时', |
||||||
|
originalPrice: '¥10.00/小时', |
||||||
|
tables: [ |
||||||
|
{ id: '1', name: '独牙01', status: 'available', buttons: [{ type: 'start', text: '立即开台' }] }, |
||||||
|
{ id: '2', name: '独牙02', status: 'waiting', waitTime: '00 时 15 分', buttons: [] }, |
||||||
|
{ id: '3', name: '来力黑金刚03', status: 'available', buttons: [{ type: 'start', text: '立即开台' }] }, |
||||||
|
{ id: '4', name: '来力黑金刚04', status: 'using', buttons: [] } |
||||||
|
] |
||||||
|
}, |
||||||
|
{ |
||||||
|
name: '乔氏赛台', |
||||||
|
vipPrice: '¥16.00/小时', |
||||||
|
originalPrice: '¥20.00/小时', |
||||||
|
tables: [ |
||||||
|
{ id: '5', name: '乔氏01', status: 'available', buttons: [{ type: 'start', text: '立即开台' }] }, |
||||||
|
{ id: '6', name: '乔氏02', status: 'available', buttons: [{ type: 'reserve', text: '预定' }, { type: 'start', text: '立即开台' }] }, |
||||||
|
{ id: '7', name: '乔氏03', status: 'available', buttons: [{ type: 'start', text: '立即开台' }] } |
||||||
|
] |
||||||
|
} |
||||||
|
]) |
||||||
|
|
||||||
|
// 棋牌数据
|
||||||
|
const [chessTables] = useState<ChessTable[]>([ |
||||||
|
{ id: '1', name: 'Q01号', status: 'available', buttonText: '立即开台' }, |
||||||
|
{ id: '2', name: 'Q02号', status: 'using', statusText: '预计 16:00 结束' }, |
||||||
|
{ id: '3', name: 'Q03号', status: 'waiting', statusText: '预计等待:', waitTime: '00 时 15 分' }, |
||||||
|
{ id: '4', name: 'Q04号', status: 'reserved', buttonText: '预约开台' } |
||||||
|
]) |
||||||
|
|
||||||
|
// 棋牌价格信息
|
||||||
|
const chessInfo = { |
||||||
|
timeRange: '00:00-24:00', |
||||||
|
price: '¥60.00/小时' |
||||||
|
} |
||||||
|
|
||||||
|
// 存杆柜数据
|
||||||
|
const [storageCabinet] = useState<StorageCabinet>({ |
||||||
|
id: '1', |
||||||
|
status: 'available', |
||||||
|
price: '1元/天' |
||||||
|
}) |
||||||
|
|
||||||
|
useLoad(() => { |
||||||
|
console.log('门店详情页面加载') |
||||||
|
}) |
||||||
|
|
||||||
|
// 拨打电话
|
||||||
|
const handlePhoneCall = () => { |
||||||
|
Taro.makePhoneCall({ |
||||||
|
phoneNumber: '100-666-XXXX', |
||||||
|
}).catch((err) => { |
||||||
|
console.error('拨打电话失败:', err) |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 分享
|
||||||
|
const handleShare = () => { |
||||||
|
Taro.showToast({ |
||||||
|
title: '分享功能开发中', |
||||||
|
icon: 'none' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 开通VIP
|
||||||
|
const handleOpenVip = () => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: '/pagesUser/vipBenefits/index' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// Tab 点击,滚动到对应位置
|
||||||
|
const handleTabClick = (index: number) => { |
||||||
|
setActiveTab(index) |
||||||
|
// 获取对应区域的 ID
|
||||||
|
const sectionIds = ['billiard-section', 'chess-section', 'storage-section'] |
||||||
|
const query = Taro.createSelectorQuery() |
||||||
|
query.select(`#${sectionIds[index]}`).boundingClientRect() |
||||||
|
query.select('#scroll-content').scrollOffset() |
||||||
|
query.exec((res) => { |
||||||
|
if (res[0] && res[1]) { |
||||||
|
const targetTop = res[0].top + res[1].scrollTop - 150 // 减去 tab 高度
|
||||||
|
Taro.pageScrollTo({ |
||||||
|
scrollTop: targetTop, |
||||||
|
duration: 300 |
||||||
|
}) |
||||||
|
} |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 进入预定页面
|
||||||
|
const handleReserve = (tableId: string) => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: '/pageStore/reservation/index?tableId=' + tableId |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 进入开台页面
|
||||||
|
const handleStartTable = (tableId: string) => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: '/pageScan/startTable/index?tableId=' + tableId |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 进入预约开台页面
|
||||||
|
const handleAppointmentStart = (tableId: string) => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: '/pageStore/appointmentStart/index?tableId=' + tableId |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 进入存杆柜租赁页面
|
||||||
|
const handleCabinetRental = () => { |
||||||
|
Taro.navigateTo({ |
||||||
|
url: '/pagesOrder/cabinetRental/index' |
||||||
|
}) |
||||||
|
} |
||||||
|
|
||||||
|
// 获取台球桌状态文本
|
||||||
|
const getBilliardStatusText = (table: BilliardTable) => { |
||||||
|
if (table.status === 'using') return '使用中' |
||||||
|
if (table.status === 'waiting') return `预计等待:\n${table.waitTime}` |
||||||
|
return '' |
||||||
|
} |
||||||
|
|
||||||
|
// 获取棋牌状态标签
|
||||||
|
const getChessStatusTag = (status: TableStatus) => { |
||||||
|
if (status === 'available') return { text: '空闲中', class: 'available' } |
||||||
|
if (status === 'using') return { text: '使用中', class: 'using' } |
||||||
|
if (status === 'waiting') return { text: '使用中', class: 'using' } |
||||||
|
if (status === 'reserved') return { text: '空闲中', class: 'available' } |
||||||
|
return { text: '', class: '' } |
||||||
|
} |
||||||
|
|
||||||
|
return ( |
||||||
|
<View className="store_detail_page"> |
||||||
|
{/* 自定义透明导航栏 */} |
||||||
|
<View |
||||||
|
className="custom_nav_bar" |
||||||
|
style={{ paddingTop: `${statusBarHeight}px`, height: `${statusBarHeight + navBarHeight}px` }} |
||||||
|
> |
||||||
|
<View className="nav_content" style={{ height: `${navBarHeight}px` }}> |
||||||
|
<View className="nav_buttons"> |
||||||
|
<View className="nav_btn" onClick={handleBack}> |
||||||
|
<Arrow className="nav_icon back_icon" /> |
||||||
|
</View> |
||||||
|
{/* <View className="nav_divider" /> |
||||||
|
<View className="nav_btn" onClick={handleGoHome}> |
||||||
|
<HomeOutlined className="nav_icon home_icon" /> |
||||||
|
</View> */} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 轮播图区域 */} |
||||||
|
<View className="swiper_container"> |
||||||
|
<Swiper |
||||||
|
className="swiper" |
||||||
|
autoplay={3000} |
||||||
|
lazyRender |
||||||
|
> |
||||||
|
<Swiper.Indicator className="swiper_indicator" /> |
||||||
|
<Swiper.Item> |
||||||
|
<Image |
||||||
|
className="swiper_image" |
||||||
|
src={swBG} |
||||||
|
mode="aspectFill" |
||||||
|
/> |
||||||
|
</Swiper.Item> |
||||||
|
<Swiper.Item> |
||||||
|
<Image |
||||||
|
className="swiper_image" |
||||||
|
src={swBG} |
||||||
|
mode="aspectFill" |
||||||
|
/> |
||||||
|
</Swiper.Item> |
||||||
|
</Swiper> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 内容区域 */} |
||||||
|
<View className="content_area" id="scroll-content"> |
||||||
|
{/* 门店信息 */} |
||||||
|
<View className="store_info_section"> |
||||||
|
<View className="store_header"> |
||||||
|
<Text className="store_name">{storeInfo.name}</Text> |
||||||
|
<View className="store_actions"> |
||||||
|
<Image className="action_icon phone" src={phoneIcon} mode="aspectFit" onClick={handlePhoneCall} /> |
||||||
|
<Image className="action_icon share" src={shareIcon} mode="aspectFit" onClick={handleShare} /> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className="store_location"> |
||||||
|
<View className="location_left"> |
||||||
|
<Image className="location_icon" src={locationIcon} mode="aspectFit" /> |
||||||
|
<Text className="location_text">{storeInfo.address}</Text> |
||||||
|
</View> |
||||||
|
<Text className="distance_text">距离{storeInfo.distance}</Text> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className="store_price"> |
||||||
|
<Text className="price_text">台球 {storeInfo.billiardPrice}</Text> |
||||||
|
<Text className="price_text">棋牌 {storeInfo.chessPrice}</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* VIP 开通横幅 */} |
||||||
|
<View className="vip_banner" onClick={handleOpenVip}> |
||||||
|
<Image className="vip_bg" src={payVipBg} mode="aspectFill" /> |
||||||
|
<View className="vip_btn"> |
||||||
|
<Text className="vip_btn_text">立即开通</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* Tab 导航 */} |
||||||
|
<View className="tab_container"> |
||||||
|
{tabs.map((tab, index) => ( |
||||||
|
<View |
||||||
|
key={index} |
||||||
|
className={`tab_item ${activeTab === index ? 'active' : ''}`} |
||||||
|
onClick={() => handleTabClick(index)} |
||||||
|
> |
||||||
|
<View className="tab_count"> |
||||||
|
<Text className="count_label">空闲</Text> |
||||||
|
<Text className="count_value">{tab.idleCount}</Text> |
||||||
|
</View> |
||||||
|
<Text className="tab_name">{tab.name}</Text> |
||||||
|
{activeTab === index && <View className="tab_indicator" />} |
||||||
|
</View> |
||||||
|
))} |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 台球和棋牌区域 */} |
||||||
|
<View className="tables_section"> |
||||||
|
{/* 台球区域 */} |
||||||
|
<View id="billiard-section" className="billiard_section"> |
||||||
|
{billiardCategories.map((category, catIndex) => ( |
||||||
|
<View key={catIndex} className="category_block"> |
||||||
|
<View className="category_header"> |
||||||
|
<Text className="category_name">{category.name}</Text> |
||||||
|
<View className="category_price"> |
||||||
|
<Text className="vip_price">VIP: {category.vipPrice}</Text> |
||||||
|
<Text className="original_price">原价: {category.originalPrice}</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className="tables_grid billiard_grid"> |
||||||
|
{category.tables.map((table) => ( |
||||||
|
<View |
||||||
|
key={table.id} |
||||||
|
className={`table_card billiard_card ${table.status !== 'available' ? 'disabled' : ''}`} |
||||||
|
> |
||||||
|
<Image className="table_bg" src={billiardTabBg} mode="aspectFill" /> |
||||||
|
{table.status !== 'available' && <View className="table_mask" />} |
||||||
|
<View className="table_content"> |
||||||
|
<Text className="table_name">{table.name}</Text> |
||||||
|
{table.status === 'available' && table.buttons.length > 0 ? ( |
||||||
|
table.buttons.length === 1 ? ( |
||||||
|
// 单个按钮
|
||||||
|
<Text |
||||||
|
className="table_btn_single" |
||||||
|
onClick={() => table.buttons[0].type === 'reserve' ? handleReserve(table.id) : handleStartTable(table.id)} |
||||||
|
> |
||||||
|
{table.buttons[0].text} |
||||||
|
</Text> |
||||||
|
) : ( |
||||||
|
// 按钮组
|
||||||
|
<View className="table_buttons"> |
||||||
|
{table.buttons.map((btn, btnIndex) => ( |
||||||
|
<Text |
||||||
|
key={btnIndex} |
||||||
|
className="table_btn" |
||||||
|
onClick={() => btn.type === 'reserve' ? handleReserve(table.id) : handleStartTable(table.id)} |
||||||
|
> |
||||||
|
{btn.text} |
||||||
|
</Text> |
||||||
|
))} |
||||||
|
</View> |
||||||
|
) |
||||||
|
) : ( |
||||||
|
<Text className="table_status">{getBilliardStatusText(table)}</Text> |
||||||
|
)} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
))} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
))} |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 棋牌区域 */} |
||||||
|
<View id="chess-section" className="chess_section"> |
||||||
|
<View className="category_header"> |
||||||
|
<Text className="category_name">棋牌</Text> |
||||||
|
<View className="category_price"> |
||||||
|
<Text className="time_range">{chessInfo.timeRange}</Text> |
||||||
|
<Text className="price_info">价格: {chessInfo.price}</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className="tables_grid chess_grid"> |
||||||
|
{chessTables.map((table) => ( |
||||||
|
<View |
||||||
|
key={table.id} |
||||||
|
className={`table_card chess_card ${table.status === 'using' || table.status === 'waiting' ? 'disabled' : ''}`} |
||||||
|
> |
||||||
|
<Image className="table_bg" src={paiTabBg} mode="aspectFill" /> |
||||||
|
{(table.status === 'using' || table.status === 'waiting') && <View className="table_mask" />} |
||||||
|
|
||||||
|
{/* 状态标签 */} |
||||||
|
<View className={`status_tag ${getChessStatusTag(table.status).class}`}> |
||||||
|
<Text className="tag_text">{getChessStatusTag(table.status).text}</Text> |
||||||
|
</View> |
||||||
|
|
||||||
|
<View className="table_content"> |
||||||
|
<Text className="table_name">{table.name}</Text> |
||||||
|
{table.status === 'available' ? ( |
||||||
|
<Text className="table_btn_single" onClick={() => handleStartTable(table.id)}>{table.buttonText}</Text> |
||||||
|
) : table.status === 'reserved' ? ( |
||||||
|
<Text className="table_btn_single" onClick={() => handleAppointmentStart(table.id)}>{table.buttonText}</Text> |
||||||
|
) : ( |
||||||
|
<Text className="table_status"> |
||||||
|
{table.statusText} |
||||||
|
{table.status === 'waiting' && `\n${table.waitTime}`} |
||||||
|
</Text> |
||||||
|
)} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
))} |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 存杆柜区域 */} |
||||||
|
<View id="storage-section" className="storage_section"> |
||||||
|
<Text className="section_title">存杆柜</Text> |
||||||
|
<View className="storage_card" onClick={handleCabinetRental}> |
||||||
|
<Image className="storage_bg" src={storeBoxBg} mode="aspectFill" /> |
||||||
|
<View className="storage_content"> |
||||||
|
<Text className="storage_status">暂未租赁/租赁中</Text> |
||||||
|
<Text className="storage_price">{storageCabinet.price}</Text> |
||||||
|
<View className="storage_btn"> |
||||||
|
<Text className="btn_text">租赁</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
|
||||||
|
{/* 底部提示 */} |
||||||
|
<Text className="end_tip">到底了~</Text> |
||||||
|
</View> |
||||||
|
</View> |
||||||
|
) |
||||||
|
} |
||||||
|
|
||||||
|
export default StoreDetail |
||||||