feat(ticket): 添加门票功能
This commit is contained in:
parent
54bf731dcc
commit
6f456ba7bc
|
@ -5,14 +5,7 @@
|
||||||
* @Date: 2022-05-24 14:43:45
|
* @Date: 2022-05-24 14:43:45
|
||||||
*/
|
*/
|
||||||
import { getToken, removeToken } from '@/config/auth.js'
|
import { getToken, removeToken } from '@/config/auth.js'
|
||||||
|
|
||||||
module.exports = vm => {
|
module.exports = vm => {
|
||||||
// 检查uni.$u.http是否可用
|
|
||||||
if (!uni || !uni.$u || !uni.$u.http) {
|
|
||||||
console.warn('uni.$u.http is not available, request configuration skipped')
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
// 初始化请求配置
|
// 初始化请求配置
|
||||||
uni.$u.http.setConfig(config => {
|
uni.$u.http.setConfig(config => {
|
||||||
// config.baseURL = 'https://p1.hzs413.com/inter-api';
|
// config.baseURL = 'https://p1.hzs413.com/inter-api';
|
||||||
|
@ -20,7 +13,7 @@ module.exports = vm => {
|
||||||
|
|
||||||
//#ifdef DEV_SERVER
|
//#ifdef DEV_SERVER
|
||||||
console.log('DEV_SERVER')
|
console.log('DEV_SERVER')
|
||||||
config.baseURL = '/prod-api'
|
config.baseURL = 'http://localhost:8080'
|
||||||
//#endif
|
//#endif
|
||||||
|
|
||||||
//#ifdef QA_SERVER
|
//#ifdef QA_SERVER
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* @Descripttion: 门票活动相关API
|
||||||
|
* @version: 1.0.0
|
||||||
|
* @Author: Assistant
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
*/
|
||||||
|
|
||||||
|
const http = uni.$u.http
|
||||||
|
|
||||||
|
// 查询门票活动列表
|
||||||
|
export const getTicketActivityList = params =>
|
||||||
|
http.get('/sale/api/ticket/query-ac', { params })
|
||||||
|
|
||||||
|
// 查询我的门票
|
||||||
|
export const getMyTicketList = params =>
|
||||||
|
http.get('/sale/api/ticket/query', { params })
|
||||||
|
|
||||||
|
// 购买门票(暂时定义,等待后端提供具体接口)
|
||||||
|
export const buyTicket = data => http.post('/sale/api/ticket/pay-ticket', data)
|
||||||
|
|
||||||
|
// 获取门票详情
|
||||||
|
export const getTicketDetail = params =>
|
||||||
|
http.get('/sale/api/ticket/detail', { params })
|
35
pages.json
35
pages.json
|
@ -827,6 +827,41 @@
|
||||||
"navigationBarTitleText": "新增业绩",
|
"navigationBarTitleText": "新增业绩",
|
||||||
"enablePullDownRefresh": false
|
"enablePullDownRefresh": false
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/ticket/index",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "门票活动",
|
||||||
|
"navigationBarBackgroundColor": "#fff",
|
||||||
|
"navigationBarHidden": true,
|
||||||
|
"navigationStyle": "custom",
|
||||||
|
"enablePullDownRefresh": true
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/ticket/buy",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "自助购票",
|
||||||
|
"navigationBarBackgroundColor": "#fff",
|
||||||
|
"navigationBarHidden": true,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/ticket/detail",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "我的门票",
|
||||||
|
"navigationBarBackgroundColor": "#fff",
|
||||||
|
"navigationBarHidden": true,
|
||||||
|
"navigationStyle": "custom"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "pages/test-ticket",
|
||||||
|
"style": {
|
||||||
|
"navigationBarTitleText": "门票模块测试",
|
||||||
|
"navigationBarBackgroundColor": "#fff"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"tabBar": {
|
"tabBar": {
|
||||||
|
|
|
@ -0,0 +1,95 @@
|
||||||
|
<!--
|
||||||
|
* @Descripttion: 门票模块测试页面
|
||||||
|
* @version: 1.0.0
|
||||||
|
* @Author: Assistant
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view class="test-container">
|
||||||
|
<view class="header">
|
||||||
|
<text class="title">门票模块测试</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="button-list">
|
||||||
|
<button class="test-btn" @click="goToTicketList">进入门票活动</button>
|
||||||
|
|
||||||
|
<button class="test-btn" @click="goToBuyTicket">测试购票页面</button>
|
||||||
|
|
||||||
|
<button class="test-btn" @click="goToTicketDetail">测试门票详情</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="info">
|
||||||
|
<text class="info-text">点击按钮测试相应功能模块</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
export default {
|
||||||
|
methods: {
|
||||||
|
// 进入门票活动列表
|
||||||
|
goToTicketList() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/ticket/index',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 测试购票页面
|
||||||
|
goToBuyTicket() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/ticket/buy?activityId=12&activityName=测试活动&price=0.03',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 测试门票详情
|
||||||
|
goToTicketDetail() {
|
||||||
|
uni.navigateTo({
|
||||||
|
url: '/pages/ticket/detail?ticketId=201',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.test-container {
|
||||||
|
padding: 20px;
|
||||||
|
background: #f8f8f8;
|
||||||
|
min-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header {
|
||||||
|
text-align: center;
|
||||||
|
margin-bottom: 40px;
|
||||||
|
|
||||||
|
.title {
|
||||||
|
font-size: 24px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.button-list {
|
||||||
|
.test-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 50px;
|
||||||
|
background: #005bac;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 25px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.info {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 40px;
|
||||||
|
|
||||||
|
.info-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,851 @@
|
||||||
|
<!--
|
||||||
|
* @Descripttion: 自助购票页面
|
||||||
|
* @version: 1.0.0
|
||||||
|
* @Author: Assistant
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view class="buy-ticket-container">
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<view class="custom-navbar">
|
||||||
|
<view class="navbar-content">
|
||||||
|
<view class="back-btn" @click="goBack">
|
||||||
|
<u-icon name="arrow-left" size="20" color="#333"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="navbar-title">自助购票</view>
|
||||||
|
<view class="placeholder"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<view class="content-area">
|
||||||
|
<!-- 提示信息 -->
|
||||||
|
<view class="tip-banner">
|
||||||
|
<view class="tip-icon">
|
||||||
|
<u-icon name="info-circle" size="16" color="#f56c6c"></u-icon>
|
||||||
|
</view>
|
||||||
|
<text class="tip-text">自助购票请填写以下信息:</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 购票人信息列表 -->
|
||||||
|
<view class="buyer-list">
|
||||||
|
<view
|
||||||
|
class="buyer-item"
|
||||||
|
v-for="(buyer, index) in buyerList"
|
||||||
|
:key="index"
|
||||||
|
>
|
||||||
|
<view class="buyer-header">
|
||||||
|
<text class="buyer-title">购票人信息{{ index + 1 }}</text>
|
||||||
|
<view
|
||||||
|
class="delete-btn"
|
||||||
|
v-if="buyerList.length > 1"
|
||||||
|
@click="removeBuyer(index)"
|
||||||
|
>
|
||||||
|
<u-icon name="trash" size="16" color="#999"></u-icon>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="form-section">
|
||||||
|
<!-- 姓名 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>姓名</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.name"
|
||||||
|
placeholder="请输入"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 联系方式 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>联系方式</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.phone"
|
||||||
|
placeholder="请输入"
|
||||||
|
type="number"
|
||||||
|
maxlength="11"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 证件号码 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>证件号码</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.idCard"
|
||||||
|
placeholder="请输入"
|
||||||
|
maxlength="18"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 性别 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>性别</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<picker
|
||||||
|
:value="buyer.sexIndex"
|
||||||
|
:range="sexOptions"
|
||||||
|
@change="onSexChange($event, index)"
|
||||||
|
>
|
||||||
|
<view class="picker-input">
|
||||||
|
<text
|
||||||
|
class="picker-text"
|
||||||
|
:class="{ placeholder: buyer.sexIndex === -1 }"
|
||||||
|
>
|
||||||
|
{{
|
||||||
|
buyer.sexIndex !== -1
|
||||||
|
? sexOptions[buyer.sexIndex]
|
||||||
|
: '请选择'
|
||||||
|
}}
|
||||||
|
</text>
|
||||||
|
<u-icon name="arrow-down" size="12" color="#999"></u-icon>
|
||||||
|
</view>
|
||||||
|
</picker>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 服装尺寸 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>服装尺寸</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.clothSize"
|
||||||
|
placeholder="请输入"
|
||||||
|
maxlength="10"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 同住人 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label">
|
||||||
|
<text>同住人</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.cohabitant"
|
||||||
|
placeholder="请输入"
|
||||||
|
maxlength="20"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 紧急联系方式 -->
|
||||||
|
<view class="form-item">
|
||||||
|
<view class="label required">
|
||||||
|
<text>紧急联系方式</text>
|
||||||
|
</view>
|
||||||
|
<view class="input-wrapper">
|
||||||
|
<input
|
||||||
|
class="form-input"
|
||||||
|
v-model="buyer.emergencyPhone"
|
||||||
|
placeholder="请输入"
|
||||||
|
type="number"
|
||||||
|
maxlength="11"
|
||||||
|
/>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 添加购票人按钮 -->
|
||||||
|
<view class="add-buyer-btn" @click="addBuyer">
|
||||||
|
<u-icon name="plus" size="16" color="#666"></u-icon>
|
||||||
|
<text class="add-text">继续添加购票人</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 提交按钮 -->
|
||||||
|
<view class="submit-wrapper">
|
||||||
|
<button
|
||||||
|
class="submit-btn"
|
||||||
|
:class="{ disabled: submitting }"
|
||||||
|
:disabled="submitting"
|
||||||
|
@click="handleSubmit"
|
||||||
|
>
|
||||||
|
{{ submitting ? '提交中...' : '提交' }}
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 支付密码弹窗 -->
|
||||||
|
<u-popup
|
||||||
|
:show="showPayPwdModal"
|
||||||
|
mode="center"
|
||||||
|
border-radius="16"
|
||||||
|
width="320px"
|
||||||
|
height="auto"
|
||||||
|
>
|
||||||
|
<view class="pay-pwd-modal">
|
||||||
|
<view class="modal-header">
|
||||||
|
<view class="header-icon">
|
||||||
|
<u-icon name="lock" size="24" color="#005bac"></u-icon>
|
||||||
|
</view>
|
||||||
|
<text class="modal-title">输入支付密码</text>
|
||||||
|
<text class="modal-subtitle">请输入您的支付密码以完成购票</text>
|
||||||
|
</view>
|
||||||
|
<view class="modal-body">
|
||||||
|
<view class="pwd-input-wrapper">
|
||||||
|
<input
|
||||||
|
class="pwd-input"
|
||||||
|
v-model="payPassword"
|
||||||
|
placeholder="请输入支付密码"
|
||||||
|
type="password"
|
||||||
|
maxlength="20"
|
||||||
|
@input="onPayPwdInput"
|
||||||
|
@focus="onPwdFocus"
|
||||||
|
@blur="onPwdBlur"
|
||||||
|
/>
|
||||||
|
<view
|
||||||
|
class="input-border"
|
||||||
|
:class="{ focused: pwdInputFocused }"
|
||||||
|
></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
<view class="modal-footer">
|
||||||
|
<view class="btn-group">
|
||||||
|
<button class="modal-btn cancel-btn" @click="closePayPwdModal">
|
||||||
|
取消
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="modal-btn confirm-btn"
|
||||||
|
:class="{ disabled: !isPayPwdValid }"
|
||||||
|
:disabled="!isPayPwdValid"
|
||||||
|
@click="confirmPayPwd"
|
||||||
|
>
|
||||||
|
确认支付
|
||||||
|
</button>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</u-popup>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { buyTicket } from '@/config/ticket.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
activityId: '',
|
||||||
|
activityName: '',
|
||||||
|
price: '',
|
||||||
|
buyerList: [
|
||||||
|
{
|
||||||
|
name: 'aa',
|
||||||
|
phone: '13333333333',
|
||||||
|
idCard: '123123',
|
||||||
|
sexIndex: 1,
|
||||||
|
sex: 1,
|
||||||
|
clothSize: '175/92A',
|
||||||
|
cohabitant: '13333333333',
|
||||||
|
emergencyPhone: '13333333333',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
sexOptions: ['男', '女'],
|
||||||
|
submitting: false,
|
||||||
|
showPayPwdModal: false,
|
||||||
|
payPassword: '',
|
||||||
|
pwdInputFocused: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
// 支付密码是否有效(非空且为纯数字)
|
||||||
|
isPayPwdValid() {
|
||||||
|
return this.payPassword.length > 0 && /^\d+$/.test(this.payPassword)
|
||||||
|
},
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
if (options.activityId) {
|
||||||
|
this.activityId = options.activityId
|
||||||
|
}
|
||||||
|
if (options.activityName) {
|
||||||
|
this.activityName = decodeURIComponent(options.activityName)
|
||||||
|
}
|
||||||
|
if (options.price) {
|
||||||
|
this.price = options.price
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 返回上一页
|
||||||
|
goBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 性别选择变化
|
||||||
|
onSexChange(e, index) {
|
||||||
|
const sexIndex = e.detail.value
|
||||||
|
this.buyerList[index].sexIndex = sexIndex
|
||||||
|
this.buyerList[index].sex = sexIndex == 0 ? 1 : 2 // 1-男,2-女
|
||||||
|
},
|
||||||
|
|
||||||
|
// 添加购票人
|
||||||
|
addBuyer() {
|
||||||
|
this.buyerList.push({
|
||||||
|
name: '',
|
||||||
|
phone: '',
|
||||||
|
idCard: '',
|
||||||
|
sexIndex: -1,
|
||||||
|
sex: '',
|
||||||
|
clothSize: '',
|
||||||
|
cohabitant: '',
|
||||||
|
emergencyPhone: '',
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 删除购票人
|
||||||
|
removeBuyer(index) {
|
||||||
|
uni.showModal({
|
||||||
|
title: '提示',
|
||||||
|
content: '确定删除该购票人信息吗?',
|
||||||
|
success: res => {
|
||||||
|
if (res.confirm) {
|
||||||
|
this.buyerList.splice(index, 1)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
})
|
||||||
|
},
|
||||||
|
|
||||||
|
// 验证表单
|
||||||
|
validateForm() {
|
||||||
|
for (let i = 0; i < this.buyerList.length; i++) {
|
||||||
|
const buyer = this.buyerList[i]
|
||||||
|
|
||||||
|
if (!buyer.name.trim()) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的姓名不能为空`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buyer.phone.trim()) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的联系方式不能为空`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^1[3-9]\d{9}$/.test(buyer.phone)) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的联系方式格式不正确`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buyer.idCard.trim()) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的证件号码不能为空`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (buyer.sexIndex === -1 || !buyer.sex) {
|
||||||
|
uni.$u.toast(`请选择购票人${i + 1}的性别`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buyer.clothSize.trim()) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的服装尺寸不能为空`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!buyer.emergencyPhone.trim()) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的紧急联系方式不能为空`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!/^1[3-9]\d{9}$/.test(buyer.emergencyPhone)) {
|
||||||
|
uni.$u.toast(`购票人${i + 1}的紧急联系方式格式不正确`)
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 处理提交按钮点击
|
||||||
|
handleSubmit() {
|
||||||
|
if (!this.validateForm()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
console.log('支付弹窗?')
|
||||||
|
// 显示支付密码弹窗
|
||||||
|
this.showPayPwdModal = true
|
||||||
|
this.payPassword = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
// 关闭支付密码弹窗
|
||||||
|
closePayPwdModal() {
|
||||||
|
this.showPayPwdModal = false
|
||||||
|
this.payPassword = ''
|
||||||
|
},
|
||||||
|
|
||||||
|
// 支付密码输入处理
|
||||||
|
onPayPwdInput(e) {
|
||||||
|
// 只允许输入数字
|
||||||
|
this.payPassword = e.detail.value.replace(/[^\d]/g, '')
|
||||||
|
},
|
||||||
|
|
||||||
|
// 密码输入框获得焦点
|
||||||
|
onPwdFocus() {
|
||||||
|
this.pwdInputFocused = true
|
||||||
|
},
|
||||||
|
|
||||||
|
// 密码输入框失去焦点
|
||||||
|
onPwdBlur() {
|
||||||
|
this.pwdInputFocused = false
|
||||||
|
},
|
||||||
|
|
||||||
|
// 确认支付密码
|
||||||
|
confirmPayPwd() {
|
||||||
|
if (!this.isPayPwdValid) {
|
||||||
|
uni.$u.toast('请输入正确的支付密码')
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.showPayPwdModal = false
|
||||||
|
this.submitOrder()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 提交订单
|
||||||
|
async submitOrder() {
|
||||||
|
if (!this.validateForm()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.submitting = true
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 构造提交数据
|
||||||
|
const orderData = {
|
||||||
|
payPwd: this.payPassword,
|
||||||
|
pkTicket: this.activityId,
|
||||||
|
ticketParamList: this.buyerList.map(buyer => ({
|
||||||
|
buyName: buyer.name,
|
||||||
|
phone: buyer.phone,
|
||||||
|
idCard: buyer.idCard,
|
||||||
|
sex: buyer.sex,
|
||||||
|
clothSize: buyer.clothSize,
|
||||||
|
cohabitant: buyer.cohabitant || '',
|
||||||
|
emergencyPhone: buyer.emergencyPhone,
|
||||||
|
})),
|
||||||
|
}
|
||||||
|
|
||||||
|
const res = await buyTicket(orderData)
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
uni.showToast({
|
||||||
|
title: '购票成功',
|
||||||
|
icon: 'success',
|
||||||
|
duration: 2000,
|
||||||
|
})
|
||||||
|
|
||||||
|
setTimeout(() => {
|
||||||
|
// 返回门票列表页面,并切换到我的门票tab
|
||||||
|
uni.navigateBack({
|
||||||
|
delta: 1,
|
||||||
|
})
|
||||||
|
}, 2000)
|
||||||
|
} else {
|
||||||
|
uni.$u.toast(res.msg || '购票失败,请重试')
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('购票失败:', error)
|
||||||
|
uni.$u.toast('购票失败,请重试')
|
||||||
|
} finally {
|
||||||
|
this.submitting = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.buy-ticket-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
background: #fff;
|
||||||
|
padding-top: var(--status-bar-height);
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.navbar-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-area {
|
||||||
|
margin-top: calc(var(--status-bar-height) + 44px);
|
||||||
|
padding: 16px;
|
||||||
|
padding-bottom: 100px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-banner {
|
||||||
|
background: #fff5f5;
|
||||||
|
border: 1px solid #ffebee;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
.tip-icon {
|
||||||
|
margin-right: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tip-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #f56c6c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.buyer-list {
|
||||||
|
.buyer-item {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.buyer-header {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
|
||||||
|
.buyer-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.delete-btn {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #f8f8f8;
|
||||||
|
border-radius: 16px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-section {
|
||||||
|
padding: 16px;
|
||||||
|
|
||||||
|
.form-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.label {
|
||||||
|
width: 100px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&.required::before {
|
||||||
|
content: '*';
|
||||||
|
color: #f56c6c;
|
||||||
|
position: absolute;
|
||||||
|
left: -10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-wrapper {
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
.form-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
background: #f8f8f8;
|
||||||
|
border-radius: 8px;
|
||||||
|
border: none;
|
||||||
|
padding: 0 16px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
box-sizing: border-box;
|
||||||
|
&::placeholder {
|
||||||
|
color: #c0c0c0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.picker-input {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: space-between;
|
||||||
|
width: 100%;
|
||||||
|
height: 44px;
|
||||||
|
background: #f8f8f8;
|
||||||
|
box-sizing: border-box;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
.picker-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #333;
|
||||||
|
|
||||||
|
&.placeholder {
|
||||||
|
color: #c0c0c0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.add-buyer-btn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
padding: 16px;
|
||||||
|
margin-bottom: 24px;
|
||||||
|
border: 2px dashed #e0e0e0;
|
||||||
|
|
||||||
|
.add-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-left: 8px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.submit-wrapper {
|
||||||
|
position: fixed;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #fff;
|
||||||
|
padding: 16px;
|
||||||
|
border-top: 1px solid #eee;
|
||||||
|
|
||||||
|
.submit-btn {
|
||||||
|
width: 100%;
|
||||||
|
height: 48px;
|
||||||
|
background: #005bac;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 24px;
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background: #ccc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* 支付密码弹窗样式 */
|
||||||
|
.pay-pwd-modal {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 16rpx;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.12);
|
||||||
|
|
||||||
|
.modal-header {
|
||||||
|
padding: 40rpx 40rpx 20rpx;
|
||||||
|
text-align: center;
|
||||||
|
background: linear-gradient(135deg, #f8f9fa 0%, #ffffff 100%);
|
||||||
|
|
||||||
|
.header-icon {
|
||||||
|
width: 48px;
|
||||||
|
height: 48px;
|
||||||
|
background: rgba(0, 91, 172, 0.1);
|
||||||
|
border-radius: 24px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
margin: 0 auto 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-subtitle {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
display: block;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-body {
|
||||||
|
padding: 24rpx;
|
||||||
|
|
||||||
|
.pwd-input-wrapper {
|
||||||
|
position: relative;
|
||||||
|
margin-bottom: 16rpx;
|
||||||
|
|
||||||
|
.pwd-input {
|
||||||
|
width: 100%;
|
||||||
|
height: 80rpx;
|
||||||
|
background: #f8f9fa;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
border: none;
|
||||||
|
padding: 0 20rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
color: #333;
|
||||||
|
text-align: center;
|
||||||
|
letter-spacing: 4rpx;
|
||||||
|
box-sizing: border-box;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&::placeholder {
|
||||||
|
color: #c0c0c0;
|
||||||
|
letter-spacing: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
&:focus {
|
||||||
|
background: #fff;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.input-border {
|
||||||
|
position: absolute;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
border: 2px solid transparent;
|
||||||
|
border-radius: 12px;
|
||||||
|
pointer-events: none;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.focused {
|
||||||
|
border-color: #005bac;
|
||||||
|
box-shadow: 0 0 0 4px rgba(0, 91, 172, 0.1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pwd-strength {
|
||||||
|
.strength-dots {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 8px;
|
||||||
|
|
||||||
|
.dot {
|
||||||
|
width: 8px;
|
||||||
|
height: 8px;
|
||||||
|
border-radius: 4px;
|
||||||
|
background: #e9ecef;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
|
||||||
|
&.active {
|
||||||
|
background: #005bac;
|
||||||
|
transform: scale(1.2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.modal-footer {
|
||||||
|
padding: 0 24px 24px;
|
||||||
|
|
||||||
|
.btn-group {
|
||||||
|
display: flex;
|
||||||
|
gap: 12px;
|
||||||
|
|
||||||
|
.modal-btn {
|
||||||
|
flex: 1;
|
||||||
|
height: 48rpx;
|
||||||
|
border: none;
|
||||||
|
border-radius: 24rpx;
|
||||||
|
font-size: 24rpx;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: all 0.3s ease;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
|
||||||
|
&.cancel-btn {
|
||||||
|
background: #f8f9fa;
|
||||||
|
color: #666;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #e9ecef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&.confirm-btn {
|
||||||
|
background: #005bac;
|
||||||
|
color: #fff;
|
||||||
|
font-weight: 600;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #004494;
|
||||||
|
}
|
||||||
|
|
||||||
|
&.disabled {
|
||||||
|
background: #e9ecef;
|
||||||
|
color: #adb5bd;
|
||||||
|
cursor: not-allowed;
|
||||||
|
|
||||||
|
&:active {
|
||||||
|
background: #e9ecef;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -0,0 +1,378 @@
|
||||||
|
<!--
|
||||||
|
* @Descripttion: 门票详情页面
|
||||||
|
* @version: 1.0.0
|
||||||
|
* @Author: Assistant
|
||||||
|
* @Date: 2025-01-22
|
||||||
|
-->
|
||||||
|
<template>
|
||||||
|
<view class="ticket-detail-container">
|
||||||
|
<!-- 自定义导航栏 -->
|
||||||
|
<view class="custom-navbar">
|
||||||
|
<view class="navbar-content">
|
||||||
|
<view class="back-btn" @click="goBack">
|
||||||
|
<u-icon name="arrow-left" size="20" color="#333"></u-icon>
|
||||||
|
</view>
|
||||||
|
<view class="navbar-title">我的门票</view>
|
||||||
|
<view class="placeholder"></view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 内容区域 -->
|
||||||
|
<view class="content-area">
|
||||||
|
<view v-if="ticketDetail" class="ticket-detail-card">
|
||||||
|
<!-- 订单编号 -->
|
||||||
|
<view class="order-section">
|
||||||
|
<text class="order-label">订单编号:</text>
|
||||||
|
<text class="order-code">{{ ticketDetail.orderCode }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 活动信息 -->
|
||||||
|
<view class="activity-section">
|
||||||
|
<view class="activity-title">{{ ticketDetail.actName }}</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">门票价格:</text>
|
||||||
|
<text class="detail-value price">¥{{ ticketDetail.price }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">支付时间:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.creationTime }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 支付信息 -->
|
||||||
|
<view class="pay-section">
|
||||||
|
<view class="section-title">支付信息</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">支付编号:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.memberCode }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">支付昵称:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.memberName }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 购票人信息 -->
|
||||||
|
<view class="buyer-section">
|
||||||
|
<view class="section-title">购票人信息</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">姓名:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.buyName }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">联系方式:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.phone }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">证件证号:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.idCard }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">性别:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.sexVal }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">服装尺寸:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.clothSize }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item" v-if="ticketDetail.cohabitant">
|
||||||
|
<text class="detail-label">同住人:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.cohabitant }}</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">紧急联系方式:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.emergencyPhone }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 展开更多信息 -->
|
||||||
|
<view class="expand-section" @click="toggleExpand">
|
||||||
|
<text class="expand-text">{{ expanded ? '收起' : '查看更多' }}</text>
|
||||||
|
<u-icon
|
||||||
|
:name="expanded ? 'arrow-up' : 'arrow-down'"
|
||||||
|
size="12"
|
||||||
|
color="#999"
|
||||||
|
></u-icon>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 更多信息(展开时显示) -->
|
||||||
|
<view v-if="expanded" class="more-info">
|
||||||
|
<view class="section-title">其他信息</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">订单金额:</text>
|
||||||
|
<text class="detail-value price"
|
||||||
|
>¥{{ ticketDetail.orderAmount }}</text
|
||||||
|
>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<view class="detail-item">
|
||||||
|
<text class="detail-label">购买数量:</text>
|
||||||
|
<text class="detail-value">{{ ticketDetail.quantity }}</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 加载状态 -->
|
||||||
|
<view v-if="loading" class="loading-state">
|
||||||
|
<u-loading-icon mode="spinner"></u-loading-icon>
|
||||||
|
<text class="loading-text">加载中...</text>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 错误状态 -->
|
||||||
|
<view v-if="error && !loading" class="error-state">
|
||||||
|
<text class="error-text">{{ error }}</text>
|
||||||
|
<button class="retry-btn" @click="loadTicketDetail">重试</button>
|
||||||
|
</view>
|
||||||
|
|
||||||
|
<!-- 空状态 -->
|
||||||
|
<view v-if="!ticketDetail && !loading && !error" class="empty-state">
|
||||||
|
<text class="empty-text">暂无数据</text>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</view>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
import { getTicketDetail } from '@/config/ticket.js'
|
||||||
|
|
||||||
|
export default {
|
||||||
|
data() {
|
||||||
|
return {
|
||||||
|
ticketId: '',
|
||||||
|
ticketDetail: null,
|
||||||
|
loading: false,
|
||||||
|
error: '',
|
||||||
|
expanded: false,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onLoad(options) {
|
||||||
|
if (options.ticketId) {
|
||||||
|
this.ticketId = options.ticketId
|
||||||
|
this.loadTicketDetail()
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
// 返回上一页
|
||||||
|
goBack() {
|
||||||
|
uni.navigateBack()
|
||||||
|
},
|
||||||
|
|
||||||
|
// 切换展开状态
|
||||||
|
toggleExpand() {
|
||||||
|
this.expanded = !this.expanded
|
||||||
|
},
|
||||||
|
|
||||||
|
// 加载门票详情
|
||||||
|
async loadTicketDetail() {
|
||||||
|
if (!this.ticketId) {
|
||||||
|
this.error = '缺少门票ID'
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.loading = true
|
||||||
|
this.error = ''
|
||||||
|
|
||||||
|
try {
|
||||||
|
const res = await getTicketDetail({ ticketId: this.ticketId })
|
||||||
|
|
||||||
|
if (res.code === 200) {
|
||||||
|
this.ticketDetail = res.data || res.rows?.[0]
|
||||||
|
} else {
|
||||||
|
this.error = res.msg || '加载失败'
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.error('加载门票详情失败:', error)
|
||||||
|
this.error = '网络错误,请重试'
|
||||||
|
} finally {
|
||||||
|
this.loading = false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<style lang="scss" scoped>
|
||||||
|
.ticket-detail-container {
|
||||||
|
min-height: 100vh;
|
||||||
|
background: #f8f8f8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-navbar {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
z-index: 999;
|
||||||
|
background: #fff;
|
||||||
|
padding-top: var(--status-bar-height);
|
||||||
|
border-bottom: 1px solid #eee;
|
||||||
|
|
||||||
|
.navbar-content {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
height: 44px;
|
||||||
|
padding: 0 16px;
|
||||||
|
|
||||||
|
.back-btn {
|
||||||
|
width: 40px;
|
||||||
|
height: 40px;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.navbar-title {
|
||||||
|
flex: 1;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.placeholder {
|
||||||
|
width: 40px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.content-area {
|
||||||
|
margin-top: calc(var(--status-bar-height) + 44px);
|
||||||
|
padding: 16px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.ticket-detail-card {
|
||||||
|
background: #fff;
|
||||||
|
border-radius: 12px;
|
||||||
|
overflow: hidden;
|
||||||
|
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.06);
|
||||||
|
|
||||||
|
.order-section {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
|
||||||
|
.order-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-code {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
margin-left: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.activity-section {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
|
||||||
|
.activity-title {
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-section,
|
||||||
|
.buyer-section,
|
||||||
|
.more-info {
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
font-size: 16px;
|
||||||
|
font-weight: 600;
|
||||||
|
color: #333;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-item {
|
||||||
|
display: flex;
|
||||||
|
margin-bottom: 12px;
|
||||||
|
|
||||||
|
&:last-child {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-label {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
min-width: 100px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.detail-value {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #666;
|
||||||
|
flex: 1;
|
||||||
|
|
||||||
|
&.price {
|
||||||
|
color: #005bac;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.expand-section {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 16px;
|
||||||
|
border-bottom: 1px solid #f5f5f5;
|
||||||
|
cursor: pointer;
|
||||||
|
|
||||||
|
.expand-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-right: 4px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.more-info {
|
||||||
|
border-bottom: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.loading-state,
|
||||||
|
.error-state,
|
||||||
|
.empty-state {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 60px 0;
|
||||||
|
|
||||||
|
.loading-text,
|
||||||
|
.error-text,
|
||||||
|
.empty-text {
|
||||||
|
font-size: 14px;
|
||||||
|
color: #999;
|
||||||
|
margin-top: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.retry-btn {
|
||||||
|
margin-top: 16px;
|
||||||
|
background: #005bac;
|
||||||
|
color: #fff;
|
||||||
|
border: none;
|
||||||
|
border-radius: 20px;
|
||||||
|
padding: 8px 24px;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue