Browse Source

历史优惠劵,卡券使用,预定页面

master
DU 5 months ago
parent
commit
826a7e6c6f
  1. 3
      src/app.config.ts
  2. 292
      src/pageScan/couponUse/index.scss
  3. 236
      src/pageScan/couponUse/index.tsx
  4. 62
      src/pageScan/myCoupons/index.scss
  5. 56
      src/pageScan/myCoupons/index.tsx
  6. 0
      src/pageScan/useCoupon/index.tsx
  7. 295
      src/pageStore/reservation/index.scss
  8. 158
      src/pageStore/reservation/index.tsx
  9. 12
      src/pages/scan/index.tsx
  10. 167
      src/pagesUser/historyCoupons/index.scss
  11. 203
      src/pagesUser/historyCoupons/index.tsx

3
src/app.config.ts

@ -14,6 +14,7 @@ export default defineAppConfig({
name: 'store-package', name: 'store-package',
pages: [ pages: [
'mapStore/index', // 地图找店页面 'mapStore/index', // 地图找店页面
'reservation/index', // 预定页面
] ]
}, },
{ {
@ -27,6 +28,7 @@ export default defineAppConfig({
'goodsCons/index', // 商品消费 'goodsCons/index', // 商品消费
'goodsOrderDetail/index', // 商品消费详情 (已支付,未支付) 'goodsOrderDetail/index', // 商品消费详情 (已支付,未支付)
'goodsRefundResult/index', // 商品退款结果(成功,失败) 'goodsRefundResult/index', // 商品退款结果(成功,失败)
'historyCoupons/index', // 历史优惠券
'helpCenter/index', // 帮助中心 'helpCenter/index', // 帮助中心
'agreement/index', // 协议 'agreement/index', // 协议
'editProfile/index', // 编辑资料 'editProfile/index', // 编辑资料
@ -43,6 +45,7 @@ export default defineAppConfig({
'timedStart/index', // 定时开台页面 'timedStart/index', // 定时开台页面
'couponStart/index', // 团购券开台页面 'couponStart/index', // 团购券开台页面
'myCoupons/index', // 我的卡券(持有卡券) 'myCoupons/index', // 我的卡券(持有卡券)
'couponUse/index', // 卡券使用页面
'closeTable/index', // 关台页面 'closeTable/index', // 关台页面
'renewFee/index', // 续费页面 'renewFee/index', // 续费页面
'turnOffRestart/index', // 关灯重开页面 'turnOffRestart/index', // 关灯重开页面

292
src/pageScan/couponUse/index.scss

@ -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;
}
}
}

236
src/pageScan/couponUse/index.tsx

@ -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

62
src/pageScan/myCoupons/index.scss

@ -86,6 +86,7 @@
display: flex; display: flex;
padding: 30px; padding: 30px;
gap: 20px; gap: 20px;
align-items: center;
// 左侧时长和券类型 // 左侧时长和券类型
.coupon_left { .coupon_left {
@ -123,8 +124,8 @@
} }
} }
// 右侧信息区域 // 中间信息区域
.coupon_right { .coupon_center {
flex: 1; flex: 1;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -133,24 +134,11 @@
// 标题行 // 标题行
.title_row { .title_row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
.coupon_title { .coupon_title {
flex: 1;
font-size: 29px; font-size: 29px;
color: #FFFFFF; color: #FFFFFF;
font-weight: 500; font-weight: 500;
line-height: 1.4; line-height: 1.4;
min-width: 0;
}
.coupon_price {
font-size: 25px;
color: #FFFFFF;
flex-shrink: 0;
} }
} }
@ -166,6 +154,43 @@
white-space: pre-line; white-space: pre-line;
} }
} }
// 右侧按钮区域
.coupon_action {
flex-shrink: 0;
.action_btn {
min-width: 120px;
height: 60px;
border-radius: 30px;
display: flex;
align-items: center;
justify-content: center;
.btn_text {
font-size: 25px;
font-weight: 500;
}
// 去使用按钮 - 橙色
&.use_btn {
background-color: #FF6B00;
.btn_text {
color: #FFFFFF;
}
}
// 购买按钮 - 可以用不同颜色
&.buy_btn {
background-color: #FF6B00;
.btn_text {
color: #FFFFFF;
}
}
}
}
} }
// 详情区域 // 详情区域
@ -173,7 +198,12 @@
padding: 0 30px 30px; padding: 0 30px 30px;
border-top: 1px dashed #3A3A3A; border-top: 1px dashed #3A3A3A;
padding-top: 20px; padding-top: 20px;
.detail_text {
flex: 1;
font-size: 23px;
color: #999999;
line-height: 1.8;
}
.detail_row { .detail_row {
display: flex; display: flex;
align-items: center; align-items: center;

56
src/pageScan/myCoupons/index.tsx

@ -26,6 +26,7 @@ interface Coupon {
details: string[] details: string[]
expanded: boolean expanded: boolean
price?: string // 价格(活动券可能有) price?: string // 价格(活动券可能有)
buttonType?: 'use' | 'buy' // 按钮类型:去使用 | 购买
} }
const MyCoupons = () => { const MyCoupons = () => {
@ -43,6 +44,7 @@ const MyCoupons = () => {
description: '', description: '',
details: ['不限时段,全天可用'], details: ['不限时段,全天可用'],
expanded: false, expanded: false,
buttonType: 'use'
}, },
{ {
id: 2, id: 2,
@ -54,7 +56,8 @@ const MyCoupons = () => {
description: '需要交押金,超时扣押金', description: '需要交押金,超时扣押金',
details: ['不限时段,全天可用', '适用类型:中八', '适用门店:北京球场风云店'], details: ['不限时段,全天可用', '适用类型:中八', '适用门店:北京球场风云店'],
expanded: false, expanded: false,
price: '¥9.9' price: '¥9.9',
buttonType: 'use'
}, },
{ {
id: 3, id: 3,
@ -66,7 +69,8 @@ const MyCoupons = () => {
description: '', description: '',
details: ['不限时段,全天可用', '适用类型:棋牌室', '适用门店:北京黑八大师联盟球厅店'], details: ['不限时段,全天可用', '适用类型:棋牌室', '适用门店:北京黑八大师联盟球厅店'],
expanded: false, expanded: false,
price: '¥59.9' price: '¥59.9',
buttonType: 'buy'
}, },
]) ])
@ -113,12 +117,28 @@ const MyCoupons = () => {
// 跳转到历史优惠券 // 跳转到历史优惠券
const handleGoHistoryCoupons = () => { const handleGoHistoryCoupons = () => {
console.log('历史优惠券') console.log('历史优惠券')
Taro.showToast({ Taro.navigateTo({
title: '跳转历史优惠券', url: '/pagesUser/historyCoupons/index'
icon: 'none'
}) })
} }
// 点击卡券按钮
const handleCouponAction = (coupon: Coupon) => {
if (coupon.buttonType === 'use') {
console.log('去使用', coupon.id)
// 跳转到卡券使用页面
Taro.navigateTo({
url: `/pageScan/couponUse/index?couponId=${coupon.id}`
})
} else if (coupon.buttonType === 'buy') {
console.log('购买', coupon.id)
Taro.showToast({
title: '跳转购买页面',
icon: 'none'
})
}
}
return ( return (
<View className="my_coupons_page"> <View className="my_coupons_page">
{/* 券类型选项卡 */} {/* 券类型选项卡 */}
@ -153,14 +173,11 @@ const MyCoupons = () => {
<Text className="coupon_type">{coupon.couponType}</Text> <Text className="coupon_type">{coupon.couponType}</Text>
</View> </View>
{/* 右侧:信息区域 */} {/* 中间:信息区域 */}
<View className="coupon_right"> <View className="coupon_center">
{/* 标题行:标题 + 价格或使用按钮 */} {/* 标题行 */}
<View className="title_row"> <View className="title_row">
<Text className="coupon_title">{coupon.title}</Text> <Text className="coupon_title">{coupon.title}</Text>
{coupon.price && (
<Text className="coupon_price">{coupon.price}</Text>
)}
</View> </View>
{/* 有效期 */} {/* 有效期 */}
@ -169,6 +186,23 @@ const MyCoupons = () => {
{/* 描述 */} {/* 描述 */}
{coupon.description && <Text className="coupon_desc">{coupon.description}</Text>} {coupon.description && <Text className="coupon_desc">{coupon.description}</Text>}
</View> </View>
{/* 右侧:按钮区域 */}
{coupon.buttonType && (
<View className="coupon_action">
<View
className={`action_btn ${coupon.buttonType === 'use' ? 'use_btn' : 'buy_btn'}`}
onClick={(e) => {
e.stopPropagation()
handleCouponAction(coupon)
}}
>
<Text className="btn_text">
{coupon.buttonType === 'use' ? '去使用' : '购买'}
</Text>
</View>
</View>
)}
</View> </View>
{/* 详情区域 */} {/* 详情区域 */}

0
src/pageScan/useCoupon/index.tsx

295
src/pageStore/reservation/index.scss

@ -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;
}
}
}
}

158
src/pageStore/reservation/index.tsx

@ -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">116.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

12
src/pages/scan/index.tsx

@ -72,14 +72,24 @@ const ScanIndex = observer(() => {
}) })
} }
// 预定
const handleReservation = () => {
Taro.navigateTo({
url: '/pageStore/reservation/index'
})
}
return ( return (
<View className="scan-page"> <View className="scan-page">
<View className="header"> <View className="header">
<Text className="title"></Text> <Text className="title"></Text>
</View> </View>
<View className="content"> <View className="content">
<Button className="scan-btn" onClick={handleScan}> {/* <Button className="scan-btn" onClick={handleScan}>
</Button> */}
<Button className="start-table-btn" onClick={handleReservation}>
</Button> </Button>
<Button className="start-table-btn" onClick={handleStartTable}> <Button className="start-table-btn" onClick={handleStartTable}>

167
src/pagesUser/historyCoupons/index.scss

@ -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); // 展开时向上
}
}
}
}
}
}

203
src/pagesUser/historyCoupons/index.tsx

@ -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…
Cancel
Save