台球开关台小程序
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 

267 lines
8.1 KiB

/**
* 定时开台页面
*/
import { View, Text, Image } from '@tarojs/components'
import Taro, { useLoad, useRouter } from '@tarojs/taro'
import { useState } from 'react'
import { observer } from 'mobx-react'
import { timedStart, invokeWechatPay, getTablePrice, PayType } from '../../api/startDevice'
import { userStore, tableStore } from '../../store'
import './index.scss'
// 使用本地图片资源
const phoneIcon = require('../startTable/images/phone.png')
// 时长选项(小时)
const durationOptions = [
{ id: 1, label: '1小时', value: 1 },
{ id: 2, label: '2小时', value: 2 },
{ id: 3, label: '3小时', value: 3 },
{ id: 4, label: '4小时', value: 4 },
{ id: 5, label: '5小时', value: 5 },
{ id: 6, label: '6小时', value: 6 },
{ id: 7, label: '7小时', value: 7 },
{ id: 8, label: '8小时', value: 8 },
]
const TimedStart = observer(() => {
const router = useRouter()
const [selectedDuration, setSelectedDuration] = useState(1) // 选中的时长
const [paymentMethod] = useState('微信支付') // 支付方式
const [loading, setLoading] = useState(false) // 加载状态
const [pricePerHour, setPricePerHour] = useState(0) // 每小时价格(从接口获取)
// 从路由参数获取设备信息,如果没有则从 store 获取
const grpSn = tableStore.getGrpSn(router.params.grpSn)
useLoad(() => {
console.log('定时开台页面加载, 设备编码:', grpSn)
// 保存设备编码到 store
if (grpSn) {
tableStore.setCurrentGrpSn(grpSn)
}
// 获取该用户对应的台球桌价格
const openId = userStore.userInfo?.wxOpenId || Taro.getStorageSync('openId')
if (openId && grpSn) {
getTablePrice(openId, grpSn)
.then((res) => {
if (res.data) {
setPricePerHour(res.data)
}
})
.catch((err) => {
console.error('获取价格失败:', err)
})
}
})
// 拨打电话
const handlePhoneCall = () => {
Taro.makePhoneCall({
phoneNumber: '100-666-XXXX',
}).catch((err) => {
console.error('拨打电话失败:', err)
})
}
// 选择时长
const handleSelectDuration = (value: number) => {
setSelectedDuration(value)
}
// 选择支付方式
const handleSelectPayment = () => {
Taro.showToast({
title: '暂时只支持微信支付',
icon: 'none',
duration: 2000
})
}
// 根据实际价格计算支付金额
const calculateAmount = () => {
if (!pricePerHour) return '0.00'
return (selectedDuration * pricePerHour).toFixed(2)
}
// 立即开台
const handleConfirmStart = async () => {
if (loading) return
// 获取用户 openId
const openId = userStore.userInfo?.wxOpenId || Taro.getStorageSync('openId')
if (!openId) {
Taro.showToast({
title: '请先登录',
icon: 'none',
duration: 2000
})
return
}
if (!grpSn) {
Taro.showToast({
title: '设备信息异常,请重新扫码',
icon: 'none',
duration: 2000
})
return
}
setLoading(true)
try {
const amount = parseFloat(calculateAmount())
console.log('定时开台,时长:', selectedDuration, '小时,金额:', amount, '设备编码:', grpSn)
// 调用定时开台接口
const result = await timedStart(grpSn, openId, selectedDuration, amount, PayType.WechatPay)
console.log('开台接口返回:', result)
// 保存操作记录ID到 store
if (result.data.consumptionId) {
tableStore.setCurrentOperationId(result.data.consumptionId)
}
// 判断是否需要支付
if (result.data.paymentResponseDto?.payParameters) {
// 调起微信支付
try {
await invokeWechatPay(result.data.paymentResponseDto.payParameters)
// 支付成功
Taro.showToast({
title: '开台成功',
icon: 'success',
duration: 2000
})
// 跳转到关台页面
setTimeout(() => {
Taro.redirectTo({
url: `/pageScan/closeTable/index?grpSn=${grpSn}&operationId=${result.data.consumptionId}`
})
}, 2000)
} catch (payError: any) {
console.log('支付错误:', payError)
// 用户取消支付或支付失败
if (payError.errMsg?.includes('cancel')) {
Taro.showToast({
title: '已取消支付',
icon: 'none',
duration: 2000
})
} else {
Taro.showToast({
title: payError.errMsg || '支付失败',
icon: 'none',
duration: 2000
})
}
}
} else {
// 无需支付
Taro.showToast({
title: '开台成功',
icon: 'success',
duration: 2000
})
setTimeout(() => {
Taro.redirectTo({
url: `/pageScan/closeTable/index?grpSn=${grpSn}&operationId=${result.data.consumptionId}`
})
}, 2000)
}
} catch (error: any) {
console.error('开台失败:', error)
// 错误提示由 request 拦截器处理
} finally {
setLoading(false)
}
}
return (
<View className="timed-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">¥{pricePerHour > 0 ? pricePerHour.toFixed(2) : '--'}</Text>
<Text className="price-label">/</Text>
</View>
</View>
{/* 价格时段 */}
<View className="time-period">
<Text>00:00-24:00</Text>
</View>
</View>
{/* 温馨提示 */}
<Text className="warm-tip">退</Text>
{/* 开台时长选择 */}
<View className="duration-card">
<Text className="card-title"></Text>
{/* 时长选项 */}
<View className="duration-options">
{durationOptions.map((option) => (
<View
key={option.id}
className={`duration-btn ${selectedDuration === option.value ? 'active' : ''}`}
onClick={() => handleSelectDuration(option.value)}
>
<Text className="duration-text">{option.label}</Text>
</View>
))}
</View>
</View>
{/* 支付方式 */}
<View className="payment-cell" onClick={handleSelectPayment}>
<Text className="payment-label"></Text>
<View className="payment-right">
<Text className="payment-value">{paymentMethod}</Text>
<Text className="arrow-icon"></Text>
</View>
</View>
</View>
{/* 底部固定区域 */}
<View className="footer-bar">
<View className="payment-info">
<Text className="payment-label"></Text>
<Text className="payment-symbol"></Text>
<Text className="payment-amount">{calculateAmount()}</Text>
</View>
<View className={`confirm-btn ${loading ? 'disabled' : ''}`} onClick={handleConfirmStart}>
<Text className="confirm-text">{loading ? '处理中...' : '立即开台'}</Text>
</View>
</View>
</View>
)
})
export default TimedStart