Browse Source

团购卷开台

master
DU 6 months ago
parent
commit
0bf21e7133
  1. 1
      src/app.config.ts
  2. BIN
      src/pageScan/couponStart/images/scanIconIn.png
  3. 5
      src/pageScan/couponStart/index.config.ts
  4. 449
      src/pageScan/couponStart/index.scss
  5. 307
      src/pageScan/couponStart/index.tsx
  6. 8
      src/pageScan/startTable/index.tsx

1
src/app.config.ts

@ -37,6 +37,7 @@ export default defineAppConfig({ @@ -37,6 +37,7 @@ export default defineAppConfig({
'startTable/index', // 开台页面
'selfStart/index', // 自助开台页面
'timedStart/index', // 定时开台页面
'couponStart/index', // 团购券开台页面
]
}
],

BIN
src/pageScan/couponStart/images/scanIconIn.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

5
src/pageScan/couponStart/index.config.ts

@ -0,0 +1,5 @@ @@ -0,0 +1,5 @@
export default definePageConfig({
navigationBarTitleText: '团购券开台',
navigationBarBackgroundColor: '#121212',
navigationBarTextStyle: 'white',
})

449
src/pageScan/couponStart/index.scss

@ -0,0 +1,449 @@ @@ -0,0 +1,449 @@
/**
* 团购券开台页面样式
*/
.coupon-start-page {
min-height: 100vh;
background-color: #121212;
padding-bottom: 130px; // 为底部固定区域留空间
// 内容区域
.content-area {
padding: 30px 30px 0;
// 台球桌信息卡片
.table-card {
background-image: url('../startTable/images/startBiliardCardBg.png');
background-size: cover;
background-position: center;
border-radius: 12px;
padding: 24px;
margin-bottom: 40px;
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: 20px;
margin-bottom: 24px;
.price-item {
display: flex;
align-items: baseline;
gap: 4px;
.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: #FFFFFF;
}
}
// 使用说明
.instruction-box {
background-color: #21212A;
border-radius: 13px;
padding: 23px;
margin-bottom: 30px;
.instruction-item {
display: flex;
align-items: center;
margin-bottom: 15px;
&:last-of-type {
margin-bottom: 10px;
}
.number-circle {
width: 32px;
height: 32px;
// background-color: #FFFFFF;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
margin-right: 12px;
flex-shrink: 0;
.number {
font-size: 20px;
color: #fff;
}
}
.instruction-text {
font-size: 25px;
color: #999999;
}
}
.instruction-note {
display: block;
font-size: 25px;
color: #999999;
margin-top: 0;
padding-left: 44px;
}
}
// 券码输入框
.code-input-box {
height: 90px;
background-color: #2A2A2A;
border-radius: 8px;
padding: 0 30px;
display: flex;
align-items: center;
justify-content: space-between;
margin-bottom: 30px;
.code-input {
flex: 1;
font-size: 29px;
color: #FFFFFF;
}
.code-placeholder {
color: #666666;
}
.scan-icon {
width: 41px;
height: 41px;
flex-shrink: 0;
}
}
// 券类型选项卡
.coupon-tabs {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 30px;
.tabs-left {
display: flex;
gap: 40px;
.tab-item {
position: relative;
padding-bottom: 10px;
.tab-text {
font-size: 29px;
color: #999999;
}
&.active {
.tab-text {
color: #FFFFFF;
}
.tab-indicator {
position: absolute;
bottom: 0;
left: 0;
right: 0;
height: 6px;
background-color: #01CA68;
border-radius: 3px;
}
}
}
}
.tabs-right {
display: flex;
align-items: center;
gap: 8px;
.total-text {
font-size: 25px;
color: #999999;
}
.arrow-text {
font-size: 32px;
color: #999999;
}
}
}
// 券列表
.coupon-list {
.coupon-item {
position: relative;
background-color: #2A2A2A;
border-radius: 12px;
margin-bottom: 20px;
overflow: hidden;
// 左上角标签
.coupon-tag {
position: absolute;
top: 0;
left: 0;
background-color: transparent;
border: 2px solid #FF6B00;
border-top: none;
border-left: none;
color: #FF6B00;
font-size: 22px;
padding: 4px 12px;
border-bottom-right-radius: 12px;
z-index: 1;
}
// 券主体
.coupon-main {
display: flex;
padding: 30px;
gap: 20px;
// 左侧时长和券类型
.coupon-left {
display: flex;
flex-direction: column;
align-items: center;
width: 150px;
flex-shrink: 0;
padding-top: 40px; // 为左上角标签留空间
.coupon-duration-wrapper {
display: flex;
align-items: baseline;
gap: 4px;
margin-bottom: 12px;
.coupon-duration {
font-size: 50px;
color: #FF6B00;
font-weight: bold;
line-height: 1;
}
.coupon-unit {
font-size: 25px;
color: #FF6B00;
line-height: 1;
}
}
.coupon-type {
font-size: 29px;
color: #999999;
line-height: 1.2;
}
}
// 右侧信息区域
.coupon-right {
flex: 1;
display: flex;
flex-direction: column;
gap: 8px;
min-width: 0;
// 标题行标题 + 选择按钮
.title-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
.coupon-title {
flex: 1;
font-size: 29px;
color: #FFFFFF;
font-weight: 500;
line-height: 1.4;
min-width: 0;
}
.select-btn {
width: 44px;
height: 44px;
border: 2px solid #666666;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
&.selected {
background-color: #01CA68;
border-color: #01CA68;
.check-icon {
font-size: 28px;
color: #FFFFFF;
font-weight: bold;
}
}
}
}
.coupon-expire {
font-size: 23px;
color: #999999;
}
.coupon-desc {
font-size: 23px;
color: #FF6B00;
line-height: 1.5;
white-space: pre-line;
}
}
}
// 详情区域
.coupon-details-section {
padding: 0 30px 30px;
border-top: 1px dashed #3A3A3A;
padding-top: 20px;
.detail-row {
display: flex;
align-items: center;
justify-content: space-between;
gap: 12px;
margin-bottom: 8px;
.detail-text {
flex: 1;
font-size: 23px;
color: #999999;
line-height: 1.8;
}
.toggle-text {
font-size: 20px;
color: #999999;
flex-shrink: 0;
white-space: nowrap;
}
}
.detail-text {
display: block;
font-size: 23px;
color: #999999;
line-height: 1.8;
margin-bottom: 8px;
&:last-child {
margin-bottom: 0;
}
}
}
}
}
// 底部提示
.end-tip {
display: block;
text-align: center;
font-size: 25px;
color: #666666;
padding: 40px 0 60px;
}
}
// 底部固定按钮
.footer-bar {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 20px 30px;
padding-bottom: calc(20px + env(safe-area-inset-bottom));
background-color: #121212;
box-shadow: 0px -2px 10px rgba(0, 0, 0, 0.3);
.exchange-btn {
width: 100%;
height: 90px;
background-color: #01CA68;
border-radius: 50px;
display: flex;
align-items: center;
justify-content: center;
.exchange-text {
font-size: 33px;
color: #FFFFFF;
font-weight: bold;
}
}
}
}

307
src/pageScan/couponStart/index.tsx

@ -0,0 +1,307 @@ @@ -0,0 +1,307 @@
/**
*
*/
import { View, Text, Image, Input } from '@tarojs/components'
import Taro, { useLoad } from '@tarojs/taro'
import { useState } from 'react'
import './index.scss'
// 使用本地图片资源
const phoneIcon = require('../startTable/images/phone.png')
const scanIcon = require('./images/scanIconIn.png')
// 券类型枚举
enum CouponType {
THIRD_PARTY = 'third_party',
ACTIVITY = 'activity',
}
// 券数据接口
interface Coupon {
id: number
type: string // '团八' | '黑八'
duration: string
couponType: string // '活动抵时券' | '抵时券'
title: string
expireDate: string
description: string
details: string[]
expanded: boolean
}
const CouponStart = () => {
const [couponCode, setCouponCode] = useState('') // 券码
const [selectedCouponType, setSelectedCouponType] = useState<CouponType>(CouponType.THIRD_PARTY)
const [selectedCouponId, setSelectedCouponId] = useState<number>(1) // 选中的券ID
// 券列表数据
const [coupons, setCoupons] = useState<Coupon[]>([
{
id: 1,
type: '团八',
duration: '20',
couponType: '活动抵时券',
title: '20分钟通用券(体验券)',
expireDate: '2025-10-01 16:21',
description: '需要交押金,超时扣押金\n单笔满40分钟可减免20分钟',
details: ['不限时段,全天可用', '适用类型:中八', '每桌只单限用1张'],
expanded: false,
},
{
id: 2,
type: '黑八',
duration: '180',
couponType: '抵时券',
title: '自助中式台球3小时59.9元体验券',
expireDate: '2025-11-01 09:00',
description: '',
details: ['不限时段,全天可用'],
expanded: false,
},
])
useLoad(() => {
console.log('团购券开台页面加载')
})
// 拨打电话
const handlePhoneCall = () => {
Taro.makePhoneCall({
phoneNumber: '100-666-XXXX',
}).catch((err) => {
console.error('拨打电话失败:', err)
})
}
// 扫描券码
const handleScanCode = () => {
Taro.scanCode({
scanType: ['qrCode', 'barCode'],
}).then((res) => {
setCouponCode(res.result)
}).catch((err) => {
console.error('扫码失败:', err)
})
}
// 切换券类型
const handleSwitchType = (type: CouponType) => {
setSelectedCouponType(type)
}
// 选择券
const handleSelectCoupon = (id: number) => {
setSelectedCouponId(id)
}
// 展开/收起券详情
const handleToggleExpand = (id: number) => {
setCoupons(prev => prev.map(coupon =>
coupon.id === id ? { ...coupon, expanded: !coupon.expanded } : coupon
))
}
// 兑换开台
const handleExchange = () => {
if (!selectedCouponId) {
Taro.showToast({
title: '请选择一张券',
icon: 'none',
duration: 2000
})
return
}
console.log('兑换开台,选中券ID:', selectedCouponId)
Taro.showToast({
title: '功能开发中',
icon: 'none',
duration: 2000
})
}
return (
<View className="coupon-start-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>[].-A03/3</Text>
</View>
{/* 价格信息 */}
<View className="price-info">
<View className="price-item">
<Text className="price-value">¥28.80</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 ¥20.00</Text>
</View>
</View>
{/* 价格时段 */}
<View className="time-period">
<Text>00:00-24:00</Text>
</View>
</View>
{/* 使用说明 */}
<View className="instruction-box">
<View className="instruction-item">
<View className="number-circle">
<Text className="number"></Text>
</View>
<Text className="instruction-text"></Text>
</View>
<View className="instruction-item">
<View className="number-circle">
<Text className="number"></Text>
</View>
<Text className="instruction-text"></Text>
</View>
<View className="instruction-item">
<View className="number-circle">
<Text className="number"></Text>
</View>
<Text className="instruction-text">[]</Text>
</View>
<Text className="instruction-note"></Text>
</View>
{/* 券码输入框 */}
<View className="code-input-box">
<Input
className="code-input"
placeholder="请输入券码"
placeholderClass="code-placeholder"
value={couponCode}
onInput={(e) => setCouponCode(e.detail.value)}
/>
<Image
className="scan-icon"
src={scanIcon}
mode="aspectFit"
onClick={handleScanCode}
/>
</View>
{/* 券类型选项卡 */}
<View className="coupon-tabs">
<View className="tabs-left">
<View
className={`tab-item ${selectedCouponType === CouponType.THIRD_PARTY ? 'active' : ''}`}
onClick={() => handleSwitchType(CouponType.THIRD_PARTY)}
>
<Text className="tab-text"></Text>
{selectedCouponType === CouponType.THIRD_PARTY && <View className="tab-indicator" />}
</View>
<View
className={`tab-item ${selectedCouponType === CouponType.ACTIVITY ? 'active' : ''}`}
onClick={() => handleSwitchType(CouponType.ACTIVITY)}
>
<Text className="tab-text"></Text>
{selectedCouponType === CouponType.ACTIVITY && <View className="tab-indicator" />}
</View>
</View>
<View className="tabs-right">
<Text className="total-text">{coupons.length}</Text>
<Text className="arrow-text"></Text>
</View>
</View>
{/* 券列表 */}
<View className="coupon-list">
{coupons.map((coupon) => (
<View key={coupon.id} className="coupon-item">
{/* 左上角标签 */}
<View className="coupon-tag">{coupon.type}</View>
<View className="coupon-main" onClick={() => handleSelectCoupon(coupon.id)}>
{/* 左侧:时长和券类型 */}
<View className="coupon-left">
<View className="coupon-duration-wrapper">
<Text className="coupon-duration">{coupon.duration}</Text>
<Text className="coupon-unit"></Text>
</View>
<Text className="coupon-type">{coupon.couponType}</Text>
</View>
{/* 右侧:信息区域 */}
<View className="coupon-right">
{/* 标题行:标题 + 选择按钮 */}
<View className="title-row">
<Text className="coupon-title">{coupon.title}</Text>
<View
className={`select-btn ${selectedCouponId === coupon.id ? 'selected' : ''}`}
onClick={(e) => {
e.stopPropagation()
handleSelectCoupon(coupon.id)
}}
>
{selectedCouponId === coupon.id && <Text className="check-icon"></Text>}
</View>
</View>
{/* 有效期 */}
<Text className="coupon-expire">{coupon.expireDate}</Text>
{/* 描述 */}
{coupon.description && <Text className="coupon-desc">{coupon.description}</Text>}
</View>
</View>
{/* 详情区域 */}
<View className="coupon-details-section">
{/* 第一条详情 + 展开/收起按钮 */}
{coupon.details.length > 0 && (
<View className="detail-row">
<Text className="detail-text">{coupon.details[0]}</Text>
<Text
className="toggle-text"
onClick={() => handleToggleExpand(coupon.id)}
>
{coupon.expanded ? '∧' : '∨'}
</Text>
</View>
)}
{/* 展开时显示其余详情 */}
{coupon.expanded && coupon.details.slice(1).map((detail, index) => (
<Text key={index} className="detail-text">{detail}</Text>
))}
</View>
</View>
))}
</View>
{/* 底部提示 */}
<Text className="end-tip">~</Text>
</View>
{/* 底部固定按钮 */}
<View className="footer-bar">
<View className="exchange-btn" onClick={handleExchange}>
<Text className="exchange-text"></Text>
</View>
</View>
</View>
)
}
export default CouponStart

8
src/pageScan/startTable/index.tsx

@ -66,6 +66,14 @@ const StartTable = () => { @@ -66,6 +66,14 @@ const StartTable = () => {
return
}
// 如果是团购券开台,跳转到团购券开台页面
if (method.id === 4) {
Taro.navigateTo({
url: '/pageScan/couponStart/index'
})
return
}
// 其他方式暂时提示功能开发中
Taro.showToast({
title: '功能开发中',

Loading…
Cancel
Save