11 changed files with 1456 additions and 28 deletions
@ -0,0 +1,292 @@
@@ -0,0 +1,292 @@
|
||||
/** |
||||
* 卡券使用页面样式 |
||||
*/ |
||||
.coupon_use_page { |
||||
min-height: 100vh; |
||||
background-color: #121212; |
||||
padding-bottom: 180px; |
||||
|
||||
// 卡券信息区域 |
||||
.coupon_info_section { |
||||
padding: 30px; |
||||
background-color: #121212; |
||||
|
||||
.coupon_header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: flex-start; |
||||
|
||||
.coupon_title_area { |
||||
flex: 1; |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 12px; |
||||
padding-right: 30px; |
||||
|
||||
.coupon_title { |
||||
font-size: 33px; |
||||
color: #FEFEFE; |
||||
font-weight: 500; |
||||
line-height: 1.4; |
||||
} |
||||
|
||||
.coupon_valid { |
||||
font-size: 25px; |
||||
color: #A8A8A8; |
||||
line-height: 1.4; |
||||
} |
||||
|
||||
.coupon_method { |
||||
font-size: 25px; |
||||
color: #A8A8A8; |
||||
line-height: 1.4; |
||||
} |
||||
} |
||||
|
||||
.coupon_duration_area { |
||||
flex-shrink: 0; |
||||
display: flex; |
||||
align-items: baseline; |
||||
|
||||
.duration_value { |
||||
font-size: 60px; |
||||
color: #A8A8A8; |
||||
font-weight: bold; |
||||
line-height: 1; |
||||
} |
||||
|
||||
.duration_unit { |
||||
font-size: 25px; |
||||
color: #A8A8A8; |
||||
margin-left: 4px; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 选择门店区域 |
||||
.store_select_section { |
||||
padding: 30px; |
||||
padding-top: 0; |
||||
|
||||
.section_title_row { |
||||
display: flex; |
||||
align-items: center; |
||||
margin-bottom: 15px; |
||||
|
||||
.section_title { |
||||
font-size: 31px; |
||||
color: #FFFFFF; |
||||
font-weight: 500; |
||||
} |
||||
|
||||
.partial_tip { |
||||
font-size: 25px; |
||||
color: #A8A8A8; |
||||
margin-left: 10px; |
||||
} |
||||
} |
||||
|
||||
.selected_store { |
||||
font-size: 27px; |
||||
color: #A8A8A8; |
||||
margin-bottom: 25px; |
||||
display: block; |
||||
} |
||||
|
||||
// 搜索栏 |
||||
.search_row { |
||||
display: flex; |
||||
align-items: center; |
||||
background-color: #21212A; |
||||
border: 1PX solid #444444; |
||||
border-radius: 8px; |
||||
height: 80px; |
||||
overflow: hidden; |
||||
|
||||
.city_dropdown { |
||||
flex-shrink: 0; |
||||
width: 160px; |
||||
height: 100%; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
border-right: 1PX solid #444444; |
||||
padding: 0 15px; |
||||
gap: 8px; |
||||
|
||||
.city_text { |
||||
font-size: 27px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.city_arrow { |
||||
font-size: 20px; |
||||
color: #FFFFFF; |
||||
transform: rotate(90deg); |
||||
} |
||||
} |
||||
|
||||
.search_input { |
||||
flex: 1; |
||||
display: flex; |
||||
align-items: center; |
||||
padding: 0 20px; |
||||
height: 100%; |
||||
|
||||
.search_field { |
||||
flex: 1; |
||||
font-size: 27px; |
||||
color: #FFFFFF; |
||||
background-color: #21212A; |
||||
} |
||||
|
||||
.search_placeholder { |
||||
color: #999999; |
||||
} |
||||
|
||||
.search_icon { |
||||
flex-shrink: 0; |
||||
font-size: 36px; |
||||
color: #FFFFFF; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 城市选择弹窗 |
||||
.city_picker { |
||||
background-color: #21212A; |
||||
padding: 30px; |
||||
padding-bottom: calc(30px + env(safe-area-inset-bottom)); |
||||
|
||||
.picker_header { |
||||
text-align: center; |
||||
margin-bottom: 30px; |
||||
|
||||
.picker_title { |
||||
font-size: 33px; |
||||
color: #FFFFFF; |
||||
font-weight: 500; |
||||
} |
||||
} |
||||
|
||||
.picker_options { |
||||
.picker_option { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
padding: 30px 20px; |
||||
border-bottom: 1PX solid #2A2A2A; |
||||
|
||||
&:last-child { |
||||
border-bottom: none; |
||||
} |
||||
|
||||
&.selected { |
||||
.option_text { |
||||
color: #03C175; |
||||
} |
||||
} |
||||
|
||||
.option_text { |
||||
font-size: 29px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.check_icon { |
||||
font-size: 29px; |
||||
color: #03C175; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 门店列表 |
||||
.store_list { |
||||
padding: 0 30px; |
||||
|
||||
.store_card { |
||||
background-color: #21212A; |
||||
border-radius: 12px; |
||||
padding: 30px; |
||||
margin-bottom: 20px; |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: flex-start; |
||||
position: relative; |
||||
overflow: hidden; |
||||
transition: all 0.2s ease; |
||||
border: 1px solid #21212A; |
||||
// 选中状态 - 边框 |
||||
&.selected { |
||||
border: 1px solid #03C175; |
||||
} |
||||
|
||||
.store_info { |
||||
flex: 1; |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 12px; |
||||
padding-right: 20px; |
||||
|
||||
.store_name { |
||||
font-size: 30px; |
||||
color: #FFFFFF; |
||||
font-weight: 500; |
||||
line-height: 1.4; |
||||
} |
||||
|
||||
.store_address { |
||||
font-size: 25px; |
||||
color: #E5E5E5; |
||||
line-height: 1.5; |
||||
} |
||||
} |
||||
|
||||
.store_distance { |
||||
flex-shrink: 0; |
||||
|
||||
.distance_text { |
||||
font-size: 25px; |
||||
color: #E5E5E5; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 到底提示 |
||||
.end_tip { |
||||
display: block; |
||||
text-align: center; |
||||
font-size: 25px; |
||||
color: #999999; |
||||
margin: 40px 0; |
||||
} |
||||
|
||||
// 页脚 |
||||
.footer { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
background-color: #121212; |
||||
padding: 20px 30px; |
||||
padding-bottom: calc(20px + env(safe-area-inset-bottom)); |
||||
border-top: 1PX solid #2A2A2A; |
||||
|
||||
.use_btn { |
||||
width: 100%; |
||||
height: 88px; |
||||
background-color: #03C175; |
||||
border-radius: 44px; |
||||
border: none; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
font-size: 31px; |
||||
color: #FFFFFF; |
||||
font-weight: 500; |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,236 @@
@@ -0,0 +1,236 @@
|
||||
/** |
||||
* 卡券使用页面 |
||||
*/ |
||||
import { View, Text, Input } from '@tarojs/components' |
||||
import Taro, { useLoad, useRouter } from '@tarojs/taro' |
||||
import { useState } from 'react' |
||||
import { Popup, Button } from '@taroify/core' |
||||
import { Arrow, Search as SearchIcon } from '@taroify/icons' |
||||
import './index.scss' |
||||
|
||||
// 门店数据接口
|
||||
interface Store { |
||||
id: number |
||||
name: string |
||||
address: string |
||||
distance: string |
||||
} |
||||
|
||||
// 城市选项
|
||||
const cityOptions = [ |
||||
{ title: '选城市', value: 'all' }, |
||||
{ title: '北京', value: 'beijing' }, |
||||
{ title: '上海', value: 'shanghai' }, |
||||
{ title: '广州', value: 'guangzhou' }, |
||||
{ title: '深圳', value: 'shenzhen' }, |
||||
] |
||||
|
||||
const CouponUse = () => { |
||||
const router = useRouter() |
||||
const { couponId } = router.params |
||||
|
||||
// 卡券信息(从路由参数或上一页面传递,实际应根据couponId获取)
|
||||
const [couponInfo] = useState({ |
||||
title: '豪华自助台球厅20分钟通用券(体验券)', |
||||
duration: '20', |
||||
validPeriod: '2025.10.01 - 2025.10.07(有效7天)', |
||||
useMethod: '自动抵扣,单次使用', |
||||
partialUsable: true, // 部分门店不可用
|
||||
}) |
||||
|
||||
// 城市选择
|
||||
const [selectedCity, setSelectedCity] = useState('all') |
||||
const [showCityPicker, setShowCityPicker] = useState(false) |
||||
|
||||
// 搜索关键词
|
||||
const [searchValue, setSearchValue] = useState('') |
||||
|
||||
// 已选门店
|
||||
const [selectedStoreId, setSelectedStoreId] = useState<number | null>(1) |
||||
|
||||
// 门店列表(模拟数据)
|
||||
const [storeList] = useState<Store[]>([ |
||||
{ |
||||
id: 1, |
||||
name: '北京黑八大师联盟球厅店', |
||||
address: '北京市XXX区XXX街道XXXXXXXXXXXXXXXXXXXXXXX路19号606', |
||||
distance: '0.05km' |
||||
}, |
||||
{ |
||||
id: 2, |
||||
name: '北京晶彩桌球世界店', |
||||
address: '北京市XXX区XXX街道XXX路19号606', |
||||
distance: '0.1km' |
||||
}, |
||||
{ |
||||
id: 3, |
||||
name: '北京球坛风云店', |
||||
address: '北京市XXX区XXXXXXXXXXX街道XXX路19号606', |
||||
distance: '0.2km' |
||||
}, |
||||
]) |
||||
|
||||
useLoad(() => { |
||||
console.log('卡券使用页面加载') |
||||
Taro.setNavigationBarTitle({ title: '' }) |
||||
}) |
||||
|
||||
// 获取已选门店名称
|
||||
const getSelectedStoreName = () => { |
||||
const store = storeList.find(s => s.id === selectedStoreId) |
||||
return store ? store.name : '' |
||||
} |
||||
|
||||
// 选择门店
|
||||
const handleSelectStore = (storeId: number) => { |
||||
setSelectedStoreId(storeId) |
||||
} |
||||
|
||||
// 搜索
|
||||
const handleSearch = () => { |
||||
console.log('搜索', searchValue) |
||||
Taro.showToast({ |
||||
title: `搜索: ${searchValue}`, |
||||
icon: 'none' |
||||
}) |
||||
} |
||||
|
||||
// 获取当前城市名称
|
||||
const getCityName = () => { |
||||
const city = cityOptions.find(c => c.value === selectedCity) |
||||
return city ? city.title : '选城市' |
||||
} |
||||
|
||||
// 选择城市
|
||||
const handleSelectCity = (value: string) => { |
||||
setSelectedCity(value) |
||||
setShowCityPicker(false) |
||||
} |
||||
|
||||
// 去使用
|
||||
const handleUse = () => { |
||||
if (!selectedStoreId) { |
||||
Taro.showToast({ |
||||
title: '请选择门店', |
||||
icon: 'none' |
||||
}) |
||||
return |
||||
} |
||||
console.log('使用卡券', selectedStoreId) |
||||
Taro.showToast({ |
||||
title: '卡券使用成功', |
||||
icon: 'success' |
||||
}) |
||||
} |
||||
|
||||
return ( |
||||
<View className="coupon_use_page"> |
||||
{/* 卡券信息区域 */} |
||||
<View className="coupon_info_section"> |
||||
<View className="coupon_header"> |
||||
<View className="coupon_title_area"> |
||||
<Text className="coupon_title">{couponInfo.title}</Text> |
||||
<Text className="coupon_valid">有效期限:{couponInfo.validPeriod}</Text> |
||||
<Text className="coupon_method">使用方法:{couponInfo.useMethod}</Text> |
||||
</View> |
||||
<View className="coupon_duration_area"> |
||||
<Text className="duration_value">{couponInfo.duration}</Text> |
||||
<Text className="duration_unit">分钟</Text> |
||||
</View> |
||||
</View> |
||||
</View> |
||||
|
||||
<div style={{height: '1rpx', width:'100%', backgroundColor: '#45454C', margin: '0 24rpx'}}></div> |
||||
|
||||
{/* 选择门店区域 */} |
||||
<View className="store_select_section"> |
||||
<View className="section_title_row"> |
||||
<Text className="section_title">选择门店</Text> |
||||
{couponInfo.partialUsable && ( |
||||
<Text className="partial_tip">(部分门店不可用)</Text> |
||||
)} |
||||
</View> |
||||
<Text className="selected_store">已选门店:{getSelectedStoreName()}</Text> |
||||
|
||||
{/* 搜索栏 */} |
||||
<View className="search_row"> |
||||
<View className="city_dropdown" onClick={() => setShowCityPicker(true)}> |
||||
<Text className="city_text">{getCityName()}</Text> |
||||
<Arrow className="city_arrow" /> |
||||
</View> |
||||
<View className="search_input"> |
||||
<Input |
||||
className="search_field" |
||||
value={searchValue} |
||||
placeholder="搜索门店名称/地址" |
||||
placeholderClass="search_placeholder" |
||||
onInput={(e) => setSearchValue(e.detail.value)} |
||||
onConfirm={handleSearch} |
||||
/> |
||||
<SearchIcon className="search_icon" onClick={handleSearch} /> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 城市选择弹窗 */} |
||||
<Popup |
||||
open={showCityPicker} |
||||
placement="bottom" |
||||
rounded |
||||
onClose={() => setShowCityPicker(false)} |
||||
> |
||||
<View className="city_picker"> |
||||
<View className="picker_header"> |
||||
<Text className="picker_title">选择城市</Text> |
||||
</View> |
||||
<View className="picker_options"> |
||||
{cityOptions.map((city) => ( |
||||
<View |
||||
key={city.value} |
||||
className={`picker_option ${selectedCity === city.value ? 'selected' : ''}`} |
||||
onClick={() => handleSelectCity(city.value)} |
||||
> |
||||
<Text className="option_text">{city.title}</Text> |
||||
{selectedCity === city.value && <Text className="check_icon">✓</Text>} |
||||
</View> |
||||
))} |
||||
</View> |
||||
</View> |
||||
</Popup> |
||||
</View> |
||||
|
||||
{/* 门店列表 */} |
||||
<View className="store_list"> |
||||
{storeList.map((store) => ( |
||||
<View |
||||
key={store.id} |
||||
className={`store_card ${selectedStoreId === store.id ? 'selected' : ''}`} |
||||
onClick={() => handleSelectStore(store.id)} |
||||
> |
||||
<View className="store_info"> |
||||
<Text className="store_name">{store.name}</Text> |
||||
<Text className="store_address">{store.address}</Text> |
||||
</View> |
||||
<View className="store_distance"> |
||||
<Text className="distance_text">距离{store.distance}</Text> |
||||
</View> |
||||
</View> |
||||
))} |
||||
</View> |
||||
|
||||
{/* 到底提示 */} |
||||
<Text className="end_tip">到底了~</Text> |
||||
|
||||
{/* 页脚按钮 */} |
||||
<View className="footer"> |
||||
<Button |
||||
className="use_btn" |
||||
onClick={handleUse} |
||||
> |
||||
去使用 |
||||
</Button> |
||||
</View> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default CouponUse |
||||
@ -0,0 +1,295 @@
@@ -0,0 +1,295 @@
|
||||
/** |
||||
* 预定页面样式 |
||||
*/ |
||||
.reservation_page { |
||||
min-height: 100vh; |
||||
background-color: #121212; |
||||
padding-bottom: 130px; // 为底部固定区域留空间 |
||||
|
||||
// 内容区域 |
||||
.content_area { |
||||
padding: 30px 30px 0; |
||||
|
||||
// 台球桌信息卡片 |
||||
.table_card { |
||||
background-image: url('../../pageScan/startTable/images/startBiliardCardBg.png'); |
||||
background-size: cover; |
||||
background-position: center; |
||||
border-radius: 12px; |
||||
padding: 24px; |
||||
margin-bottom: 30px; |
||||
display: flex; |
||||
flex-direction: column; |
||||
justify-content: space-between; |
||||
|
||||
// 顶部:店名和电话 |
||||
.card_header { |
||||
display: flex; |
||||
justify-content: space-between; |
||||
align-items: center; |
||||
margin-bottom: 20px; |
||||
|
||||
.store_name { |
||||
font-size: 25px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.phone_box { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 8px; |
||||
|
||||
.phone_icon { |
||||
width: 29px; |
||||
height: 29px; |
||||
} |
||||
|
||||
.phone_text { |
||||
font-size: 25px; |
||||
color: #FFFFFF; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 台球桌标题 |
||||
.table_title { |
||||
font-weight: bold; |
||||
font-size: 42px; |
||||
color: #FFFFFF; |
||||
line-height: 1.4; |
||||
margin: 24px 0 26px; |
||||
} |
||||
|
||||
// 价格信息 |
||||
.price_info { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 10px; |
||||
margin-bottom: 24px; |
||||
|
||||
.price_item { |
||||
display: flex; |
||||
align-items: baseline; |
||||
gap: 2px; |
||||
|
||||
.price_label { |
||||
font-size: 25px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.price_value { |
||||
font-size: 22px; |
||||
color: #FFFFFF; |
||||
font-weight: bold; |
||||
// 文字渐变色 |
||||
background: linear-gradient(0deg, #F6AE54 0%, #FBE49E 50%, #F6AE54 100%); |
||||
-webkit-background-clip: text; |
||||
-webkit-text-fill-color: transparent; |
||||
} |
||||
} |
||||
|
||||
.vip_price { |
||||
background: linear-gradient(90deg, #333333 0%, #000000 100%); |
||||
border-radius: 8px; |
||||
padding: 7px 9px; |
||||
|
||||
.vip_text { |
||||
font-size: 22px; |
||||
color: #FFFFFF; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 价格时段 |
||||
.time_period { |
||||
font-size: 25px; |
||||
color: #fFF; |
||||
} |
||||
} |
||||
|
||||
// 费用信息卡片 |
||||
.fee_card { |
||||
background-color: #21212A; |
||||
border-radius: 13px; |
||||
padding: 30px; |
||||
margin-bottom: 30px; |
||||
|
||||
// 费用行 |
||||
.fee_row { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
.fee_label { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
|
||||
.fee_value { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
} |
||||
|
||||
// 分割线 |
||||
.divider { |
||||
height: 1PX; |
||||
background-color: #3A3D42; |
||||
margin: 30px 0; |
||||
} |
||||
|
||||
// 收费标准行 |
||||
.fee_standard_row { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
.fee_label { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
|
||||
.fee_right { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 10px; |
||||
|
||||
.fee_value { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
|
||||
.arrow_icon { |
||||
font-size: 28px; |
||||
color: #E6E6E6; |
||||
transition: transform 0.3s ease; |
||||
transform: rotate(90deg); // 默认向下 |
||||
|
||||
&.expanded { |
||||
transform: rotate(-90deg); // 展开时向上 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 收费标准详情 |
||||
.fee_detail { |
||||
margin-top: 20px; |
||||
padding: 20px; |
||||
background-color: #2A2A35; |
||||
border-radius: 8px; |
||||
|
||||
.detail_text { |
||||
display: block; |
||||
font-size: 25px; |
||||
color: #999999; |
||||
line-height: 1.6; |
||||
margin-bottom: 12px; |
||||
} |
||||
|
||||
.detail_item { |
||||
display: block; |
||||
font-size: 25px; |
||||
color: #999999; |
||||
line-height: 1.8; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 支付方式单元格 |
||||
.payment_cell { |
||||
height: 100px; |
||||
background-color: #21212A; |
||||
margin-bottom: 30px; |
||||
border-radius: 13px; |
||||
padding: 0 30px; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
.payment_label { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
|
||||
.payment_right { |
||||
display: flex; |
||||
align-items: center; |
||||
gap: 8px; |
||||
|
||||
.payment_value { |
||||
font-size: 31px; |
||||
color: #E6E6E6; |
||||
} |
||||
|
||||
.payment_arrow { |
||||
font-size: 28px; |
||||
color: #E6E6E6; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 温馨提示 |
||||
.tips_section { |
||||
padding: 0 10px; |
||||
|
||||
.tips_text { |
||||
display: block; |
||||
font-size: 25px; |
||||
color: #666666; |
||||
line-height: 1.8; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 底部固定区域 |
||||
.footer_bar { |
||||
position: fixed; |
||||
bottom: 0; |
||||
left: 0; |
||||
right: 0; |
||||
height: 130px; |
||||
background-color: #1A1A1A; |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
padding: 0 30px; |
||||
box-shadow: 0px -2px 10px rgba(0, 0, 0, 0.3); |
||||
|
||||
// 支付信息 |
||||
.payment_info { |
||||
display: flex; |
||||
align-items: baseline; |
||||
gap: 8px; |
||||
|
||||
.payment_label { |
||||
font-size: 28px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.payment_symbol { |
||||
font-size: 28px; |
||||
color: #FFFFFF; |
||||
} |
||||
|
||||
.payment_amount { |
||||
font-size: 45px; |
||||
color: #FFFFFF; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
|
||||
// 立即预定按钮 |
||||
.confirm_btn { |
||||
background-color: #01CA68; |
||||
border-radius: 50px; |
||||
padding: 20px 60px; |
||||
|
||||
.confirm_text { |
||||
font-size: 31px; |
||||
color: #FFFFFF; |
||||
font-weight: bold; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,158 @@
@@ -0,0 +1,158 @@
|
||||
/** |
||||
* 预定页面 |
||||
*/ |
||||
import { View, Text, Image } from '@tarojs/components' |
||||
import Taro, { useLoad } from '@tarojs/taro' |
||||
import { useState } from 'react' |
||||
import { Arrow } from '@taroify/icons' |
||||
import './index.scss' |
||||
|
||||
// 使用本地图片资源
|
||||
const phoneIcon = require('../../pageScan/startTable/images/phone.png') |
||||
|
||||
const Reservation = () => { |
||||
const [paymentMethod] = useState('微信支付') // 支付方式
|
||||
const [showFeeDetail, setShowFeeDetail] = useState(true) // 是否展示收费标准详情
|
||||
|
||||
useLoad(() => { |
||||
console.log('预定页面加载') |
||||
}) |
||||
|
||||
// 拨打电话
|
||||
const handlePhoneCall = () => { |
||||
Taro.makePhoneCall({ |
||||
phoneNumber: '100-666-XXXX', |
||||
}).catch((err) => { |
||||
console.error('拨打电话失败:', err) |
||||
}) |
||||
} |
||||
|
||||
// 选择支付方式
|
||||
const handleSelectPayment = () => { |
||||
Taro.showToast({ |
||||
title: '暂时只支持微信支付', |
||||
icon: 'none', |
||||
duration: 2000 |
||||
}) |
||||
} |
||||
|
||||
// 切换收费标准展开/收起
|
||||
const toggleFeeDetail = () => { |
||||
setShowFeeDetail(!showFeeDetail) |
||||
} |
||||
|
||||
// 立即预定
|
||||
const handleConfirmReservation = () => { |
||||
console.log('立即预定') |
||||
Taro.showToast({ |
||||
title: '功能开发中', |
||||
icon: 'none', |
||||
duration: 2000 |
||||
}) |
||||
} |
||||
|
||||
return ( |
||||
<View className="reservation_page"> |
||||
{/* 内容区域 */} |
||||
<View className="content_area"> |
||||
{/* 台球桌信息卡片 */} |
||||
<View className="table_card"> |
||||
{/* 顶部:店名和电话 */} |
||||
<View className="card_header"> |
||||
<Text className="store_name">北京黑八大师联盟球厅店</Text> |
||||
<View className="phone_box" onClick={handlePhoneCall}> |
||||
<Image className="phone_icon" src={phoneIcon} mode="aspectFit" /> |
||||
<Text className="phone_text">联系店长</Text> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 台球桌标题 */} |
||||
<View className="table_title"> |
||||
<Text>[台球]来力黑金刚03</Text> |
||||
</View> |
||||
|
||||
{/* 价格信息 */} |
||||
<View className="price_info"> |
||||
<View className="price_item"> |
||||
<Text className="price_value">¥60.00</Text> |
||||
<Text className="price_label">/小时,</Text> |
||||
</View> |
||||
<View className="price_item"> |
||||
<Text className="price_label">押金</Text> |
||||
<Text className="price_value">¥100.00</Text> |
||||
</View> |
||||
<View className="vip_price"> |
||||
<Text className="vip_text">VIP ¥50.00</Text> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 价格时段 */} |
||||
<View className="time_period"> |
||||
<Text>价格时段:00:00-24:00</Text> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 费用信息卡片 */} |
||||
<View className="fee_card"> |
||||
{/* 预定金 */} |
||||
<View className="fee_row"> |
||||
<Text className="fee_label">预定金</Text> |
||||
<Text className="fee_value">30元</Text> |
||||
</View> |
||||
|
||||
{/* 分割线 */} |
||||
<View className="divider" /> |
||||
|
||||
{/* 收费标准 */} |
||||
<View className="fee_standard_row" onClick={toggleFeeDetail}> |
||||
<Text className="fee_label">收费标准</Text> |
||||
<View className="fee_right"> |
||||
<Text className="fee_value">80元/小时</Text> |
||||
<Arrow className={`arrow_icon ${showFeeDetail ? 'expanded' : ''}`} /> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 收费标准详情 */} |
||||
{showFeeDetail && ( |
||||
<View className="fee_detail"> |
||||
<Text className="detail_text">1分钟以内不计费,超过1分钟按6.67元/5分钟计费</Text> |
||||
<Text className="detail_item">• 00:00-11:00 原价90元/小时,折扣价80元/小时</Text> |
||||
<Text className="detail_item">• 11:00-24:00 原价100元/小时,折扣价90元/小时</Text> |
||||
</View> |
||||
)} |
||||
</View> |
||||
|
||||
{/* 支付方式 */} |
||||
<View className="payment_cell" onClick={handleSelectPayment}> |
||||
<Text className="payment_label">支付方式</Text> |
||||
<View className="payment_right"> |
||||
<Text className="payment_value">{paymentMethod}</Text> |
||||
<Arrow className="payment_arrow" /> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 温馨提示 */} |
||||
<View className="tips_section"> |
||||
<Text className="tips_text">温馨提示:(预定桌台时间:10分钟)</Text> |
||||
<Text className="tips_text">1. 预定桌台成功后,3分钟内取消可退回预定金,3分钟后无法取消;</Text> |
||||
<Text className="tips_text">2. 预定10分钟内开台成功,预定金原路退回;</Text> |
||||
<Text className="tips_text">3. 未在预定时间内开台,则扣除预定金(预定金自动充值至账户余额)。</Text> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 底部固定区域 */} |
||||
<View className="footer_bar"> |
||||
<View className="payment_info"> |
||||
<Text className="payment_label">需支付</Text> |
||||
<Text className="payment_symbol">¥</Text> |
||||
<Text className="payment_amount">30.00</Text> |
||||
</View> |
||||
<View className="confirm_btn" onClick={handleConfirmReservation}> |
||||
<Text className="confirm_text">立即预定</Text> |
||||
</View> |
||||
</View> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default Reservation |
||||
@ -0,0 +1,167 @@
@@ -0,0 +1,167 @@
|
||||
/** |
||||
* 历史优惠券页面样式 |
||||
*/ |
||||
.history_coupons_page { |
||||
min-height: 100vh; |
||||
background-color: #F2F3F5; |
||||
|
||||
// Tab 容器 |
||||
.tab_container { |
||||
background-color: #FFFFFF; |
||||
|
||||
:global { |
||||
// Tab 导航容器 |
||||
.taroify-tabs__nav { |
||||
background-color: #FFFFFF !important; |
||||
} |
||||
|
||||
// 未选中 Tab |
||||
.taroify-tabs__tab { |
||||
font-size: 33px !important; |
||||
color: #8B8B8B !important; |
||||
} |
||||
|
||||
// 选中 Tab |
||||
.taroify-tabs__tab--active { |
||||
color: #03C175 !important; |
||||
} |
||||
|
||||
// 选中指示线 |
||||
.taroify-tabs__line { |
||||
background-color: #03C175 !important; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 内容区域 |
||||
.content_area { |
||||
padding: 30px; |
||||
} |
||||
|
||||
// 优惠券列表 |
||||
.coupon_list { |
||||
// 优惠券卡片 |
||||
.coupon_card { |
||||
background-color: #FFFFFF; |
||||
border-radius: 12px; |
||||
padding: 30px; |
||||
margin-bottom: 30px; |
||||
|
||||
&:last-child { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
// 标题行 |
||||
.card_header { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: space-between; |
||||
|
||||
.coupon_name { |
||||
flex: 1; |
||||
font-size: 33px; |
||||
color: #1A1A1A; |
||||
font-weight: 500; |
||||
padding-right: 20px; |
||||
} |
||||
|
||||
.status_tag { |
||||
flex-shrink: 0; |
||||
padding: 8px 20px; |
||||
border-radius: 25px; |
||||
border: 1px solid; |
||||
|
||||
&.used { |
||||
border-color: #03C175; |
||||
|
||||
.status_text { |
||||
color: #03C175; |
||||
} |
||||
} |
||||
|
||||
&.expired { |
||||
border-color: #8B8B8B; |
||||
|
||||
.status_text { |
||||
color: #8B8B8B; |
||||
} |
||||
} |
||||
|
||||
.status_text { |
||||
font-size: 25px; |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 分割线 |
||||
.divider { |
||||
height: 1PX; |
||||
border-bottom: 1PX dashed #D3D8DE; |
||||
margin: 30px 0; |
||||
} |
||||
|
||||
// 信息区块 |
||||
.section { |
||||
margin-bottom: 25px; |
||||
|
||||
&:last-of-type { |
||||
margin-bottom: 0; |
||||
} |
||||
|
||||
.section_title { |
||||
font-size: 29px; |
||||
color: #1A1A1A; |
||||
font-weight: 500; |
||||
margin-bottom: 20px; |
||||
display: block; |
||||
} |
||||
|
||||
.info_list { |
||||
display: flex; |
||||
flex-direction: column; |
||||
gap: 16px; |
||||
|
||||
.info_row { |
||||
display: flex; |
||||
align-items: flex-start; |
||||
|
||||
.info_label { |
||||
width: 140px; |
||||
font-size: 28px; |
||||
color: #333333; |
||||
flex-shrink: 0; |
||||
} |
||||
|
||||
.info_value { |
||||
flex: 1; |
||||
margin-left: 30px; |
||||
font-size: 28px; |
||||
color: #595959; |
||||
text-align: left; |
||||
word-break: break-all; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
// 展开/收起按钮 |
||||
.expand_btn { |
||||
display: flex; |
||||
align-items: center; |
||||
justify-content: center; |
||||
padding-top: 20px; |
||||
|
||||
.expand_icon { |
||||
font-size: 28px; |
||||
color: #999999; |
||||
transition: transform 0.3s ease; |
||||
transform: rotate(90deg); // 默认向下 |
||||
|
||||
&.expanded { |
||||
transform: rotate(-90deg); // 展开时向上 |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,203 @@
@@ -0,0 +1,203 @@
|
||||
/** |
||||
* 历史优惠券页面 |
||||
*/ |
||||
import { View, Text } from '@tarojs/components' |
||||
import { useState } from 'react' |
||||
import Taro, { useLoad } from '@tarojs/taro' |
||||
import { Tabs } from '@taroify/core' |
||||
import { Arrow } from '@taroify/icons' |
||||
import EmptyData from '@/components/EmptyData' |
||||
import './index.scss' |
||||
|
||||
// 优惠券数据接口
|
||||
interface CouponItem { |
||||
id: string |
||||
name: string // 券名称
|
||||
status: 'used' | 'expired' // 状态:已使用、已过期
|
||||
// 基础信息
|
||||
couponName: string // 卡券名称
|
||||
couponNo: string // 卡券编号
|
||||
couponType: string // 卡券类型
|
||||
deductDuration: string // 抵扣时长
|
||||
validDays: string // 有效期
|
||||
// 使用信息
|
||||
useTime?: string // 使用时间
|
||||
useStore?: string // 使用门店
|
||||
useStatus: string // 使用状态
|
||||
} |
||||
|
||||
const HistoryCoupons = () => { |
||||
const [activeTab, setActiveTab] = useState(0) // 0: 全部, 1: 已使用, 2: 已过期
|
||||
const [expandedIds, setExpandedIds] = useState<string[]>([]) // 展开的卡片ID列表
|
||||
|
||||
// 模拟优惠券数据
|
||||
const [coupons] = useState<CouponItem[]>([ |
||||
{ |
||||
id: '1', |
||||
name: '满40分钟减20分钟(体验券)', |
||||
status: 'expired', |
||||
couponName: '满40分钟减20分钟(体验券)', |
||||
couponNo: '35693280569032705793', |
||||
couponType: '抵时券', |
||||
deductDuration: '20分钟', |
||||
validDays: '7天', |
||||
useTime: '-', |
||||
useStore: '-', |
||||
useStatus: '已过期' |
||||
}, |
||||
{ |
||||
id: '2', |
||||
name: '自助台球厅3小时59.9元体验券', |
||||
status: 'used', |
||||
couponName: '自助台球厅3小时59.9元体验券', |
||||
couponNo: '90327057933569328056', |
||||
couponType: '抵时券', |
||||
deductDuration: '180分钟', |
||||
validDays: '7天', |
||||
useTime: '2025-01-01 23:00:00', |
||||
useStore: '北京黑八大师联盟球厅店', |
||||
useStatus: '已使用' |
||||
}, |
||||
{ |
||||
id: '3', |
||||
name: '台球2小时29.9元体验券', |
||||
status: 'used', |
||||
couponName: '台球2小时29.9元体验券', |
||||
couponNo: '90327028056579335693', |
||||
couponType: '抵时券', |
||||
deductDuration: '120分钟', |
||||
validDays: '7天', |
||||
useTime: '2025-01-02 15:30:00', |
||||
useStore: '北京晶彩桌球世界店', |
||||
useStatus: '已使用' |
||||
} |
||||
]) |
||||
|
||||
useLoad(() => { |
||||
console.log('历史优惠券页面加载') |
||||
}) |
||||
|
||||
// 切换展开/收起
|
||||
const toggleExpand = (id: string) => { |
||||
setExpandedIds(prev => { |
||||
if (prev.includes(id)) { |
||||
return prev.filter(item => item !== id) |
||||
} |
||||
return [...prev, id] |
||||
}) |
||||
} |
||||
|
||||
// 判断是否展开
|
||||
const isExpanded = (id: string) => { |
||||
return expandedIds.includes(id) |
||||
} |
||||
|
||||
// 根据 tab 过滤数据
|
||||
const getFilteredCoupons = () => { |
||||
if (activeTab === 0) return coupons // 全部
|
||||
if (activeTab === 1) return coupons.filter(c => c.status === 'used') // 已使用
|
||||
if (activeTab === 2) return coupons.filter(c => c.status === 'expired') // 已过期
|
||||
return coupons |
||||
} |
||||
|
||||
// 渲染优惠券卡片
|
||||
const renderCouponCard = (coupon: CouponItem) => { |
||||
const expanded = isExpanded(coupon.id) |
||||
|
||||
return ( |
||||
<View key={coupon.id} className="coupon_card"> |
||||
{/* 标题行 */} |
||||
<View className="card_header"> |
||||
<Text className="coupon_name">{coupon.name}</Text> |
||||
<View className={`status_tag ${coupon.status}`}> |
||||
<Text className="status_text">{coupon.status === 'used' ? '已使用' : '已过期'}</Text> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 分割线 */} |
||||
<View className="divider" /> |
||||
|
||||
{/* 基础信息 */} |
||||
<View className="section"> |
||||
<Text className="section_title">基础信息</Text> |
||||
<View className="info_list"> |
||||
<View className="info_row"> |
||||
<Text className="info_label">卡券名称</Text> |
||||
<Text className="info_value">{coupon.couponName}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">卡券编号</Text> |
||||
<Text className="info_value">{coupon.couponNo}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">卡券类型</Text> |
||||
<Text className="info_value">{coupon.couponType}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">抵扣时长</Text> |
||||
<Text className="info_value">{coupon.deductDuration}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">有效期</Text> |
||||
<Text className="info_value">{coupon.validDays}</Text> |
||||
</View> |
||||
</View> |
||||
</View> |
||||
|
||||
{/* 展开后显示使用信息 */} |
||||
{expanded && ( |
||||
<View className="section"> |
||||
<Text className="section_title">使用信息</Text> |
||||
<View className="info_list"> |
||||
<View className="info_row"> |
||||
<Text className="info_label">使用时间</Text> |
||||
<Text className="info_value">{coupon.useTime}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">使用门店</Text> |
||||
<Text className="info_value">{coupon.useStore}</Text> |
||||
</View> |
||||
<View className="info_row"> |
||||
<Text className="info_label">使用状态</Text> |
||||
<Text className="info_value">{coupon.useStatus}</Text> |
||||
</View> |
||||
</View> |
||||
</View> |
||||
)} |
||||
|
||||
{/* 展开/收起按钮 */} |
||||
<View className="expand_btn" onClick={() => toggleExpand(coupon.id)}> |
||||
<Arrow className={`expand_icon ${expanded ? 'expanded' : ''}`} /> |
||||
</View> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
const filteredCoupons = getFilteredCoupons() |
||||
|
||||
return ( |
||||
<View className="history_coupons_page"> |
||||
{/* Tab 导航 */} |
||||
<View className="tab_container"> |
||||
<Tabs value={activeTab} onChange={setActiveTab}> |
||||
<Tabs.TabPane title="全部" /> |
||||
<Tabs.TabPane title="已使用" /> |
||||
<Tabs.TabPane title="已过期" /> |
||||
</Tabs> |
||||
</View> |
||||
|
||||
{/* 内容区域 */} |
||||
<View className="content_area"> |
||||
{filteredCoupons.length === 0 ? ( |
||||
<EmptyData /> |
||||
) : ( |
||||
<View className="coupon_list"> |
||||
{filteredCoupons.map(coupon => renderCouponCard(coupon))} |
||||
</View> |
||||
)} |
||||
</View> |
||||
</View> |
||||
) |
||||
} |
||||
|
||||
export default HistoryCoupons |
||||
Loading…
Reference in new issue