1026 lines
26 KiB
Vue
1026 lines
26 KiB
Vue
<!--
|
||
* @Descripttion: 门票活动页面
|
||
* @version: 1.0.0
|
||
* @Author: Assistant
|
||
* @Date: 2025-01-22
|
||
-->
|
||
<template>
|
||
<view class="ticket-container">
|
||
<!-- Tab切换 -->
|
||
<view class="tab-container">
|
||
<view class="tab-wrapper">
|
||
<view
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 0 }"
|
||
@click="switchTab(0)"
|
||
>
|
||
<text class="tab-text">门票活动</text>
|
||
<view class="tab-line" v-if="currentTab === 0"></view>
|
||
</view>
|
||
<view
|
||
class="tab-item"
|
||
:class="{ active: currentTab === 1 }"
|
||
@click="switchTab(1)"
|
||
>
|
||
<text class="tab-text">我的门票</text>
|
||
<view class="tab-line" v-if="currentTab === 1"></view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 内容区域 -->
|
||
<view class="content-area">
|
||
<!-- 门票活动列表 -->
|
||
<view v-if="currentTab === 0" class="activity-list">
|
||
<view
|
||
class="activity-card"
|
||
v-for="item in activityList"
|
||
:key="item.pkId"
|
||
>
|
||
<view class="card-content">
|
||
<view class="activity-image">
|
||
<image :src="item.actCover" mode="aspectFill"></image>
|
||
</view>
|
||
<view class="activity-info">
|
||
<view class="activity-title">{{ item.actName }}</view>
|
||
<view class="activity-detail">
|
||
<text class="detail-label">活动日期:</text>
|
||
<text class="detail-value"
|
||
>{{ item.actStartDate }}~{{ item.actEndDate }}</text
|
||
>
|
||
</view>
|
||
<view class="activity-detail">
|
||
<text class="detail-label">购买日期:</text>
|
||
<text class="detail-value"
|
||
>{{ item.disStartDate }}~{{ item.disEndDate }}</text
|
||
>
|
||
</view>
|
||
<view class="activity-detail">
|
||
<text class="detail-label">总票数:</text>
|
||
<text class="detail-value">{{ item.quantity }}</text>
|
||
</view>
|
||
<view class="bottom-section">
|
||
<view class="price-info">
|
||
<text class="price-symbol">¥</text>
|
||
<text class="price-value">{{ item.payMoney }}</text>
|
||
</view>
|
||
<button class="buy-btn" @click="goBuyTicket(item)">购买</button>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-if="!activityList.length && !loading" class="empty-state">
|
||
<text class="empty-text">没有更多数据了</text>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view v-if="loading" class="loading-state">
|
||
<u-loading-icon mode="spinner"></u-loading-icon>
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 我的门票列表 -->
|
||
<view v-if="currentTab === 1" class="ticket-list">
|
||
<view class="ticket-card" v-for="item in ticketList" :key="item.pkId">
|
||
<view class="ticket-header">
|
||
<text class="order-code">订单编号:{{ item.orderCode }}</text>
|
||
</view>
|
||
<view class="ticket-content">
|
||
<view class="ticket-info">
|
||
<view class="ticket-title">{{ item.actName }}</view>
|
||
<!-- 基础信息:始终显示 -->
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">门票价格:</text>
|
||
<text class="detail-value price">¥{{ item.price }}</text>
|
||
</view>
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">支付时间:</text>
|
||
<text class="detail-value">{{ item.creationTime }}</text>
|
||
</view>
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">支付编号:</text>
|
||
<text class="detail-value">{{ item.memberCode }}</text>
|
||
</view>
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">支付昵称:</text>
|
||
<text class="detail-value">{{ item.memberName }}</text>
|
||
</view>
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">姓名:</text>
|
||
<text class="detail-value">{{ item.buyName }}</text>
|
||
</view>
|
||
<view class="ticket-detail">
|
||
<text class="detail-label">联系方式:</text>
|
||
<text class="detail-value">{{ item.phone }}</text>
|
||
</view>
|
||
|
||
<!-- 展开显示的更多信息 -->
|
||
<view v-if="item.expanded" class="expanded-details">
|
||
<view class="ticket-detail" v-if="item.idCard">
|
||
<text class="detail-label">证件证号:</text>
|
||
<text class="detail-value">{{ item.idCard }}</text>
|
||
</view>
|
||
<view class="ticket-detail" v-if="item.sexVal">
|
||
<text class="detail-label">性别:</text>
|
||
<text class="detail-value">{{ item.sexVal }}</text>
|
||
</view>
|
||
<view class="ticket-detail" v-if="item.clothSize">
|
||
<text class="detail-label">服装尺寸:</text>
|
||
<text class="detail-value">{{ item.clothSize }}</text>
|
||
</view>
|
||
<view class="ticket-detail" v-if="item.cohabitant">
|
||
<text class="detail-label">同住人:</text>
|
||
<text class="detail-value">{{ item.cohabitant }}</text>
|
||
</view>
|
||
<view class="ticket-detail" v-if="item.emergencyPhone">
|
||
<text class="detail-label">紧急联系方式:</text>
|
||
<text class="detail-value">{{ item.emergencyPhone }}</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 操作按钮:仅在24小时内显示 -->
|
||
<view
|
||
v-if="isWithin24Hours(item.creationTime)"
|
||
class="action-buttons"
|
||
>
|
||
<button class="cancel-btn" @click="showCancelConfirm(item)">
|
||
撤销门票
|
||
</button>
|
||
<button class="edit-btn" @click="showEditModal(item)">
|
||
修改信息
|
||
</button>
|
||
</view>
|
||
|
||
<view class="expand-action" @click="toggleExpand(item)">
|
||
<text class="expand-text">{{
|
||
item.expanded ? '收起' : '查看更多'
|
||
}}</text>
|
||
<u-icon
|
||
:name="item.expanded ? 'arrow-up' : 'arrow-down'"
|
||
size="12"
|
||
color="#999"
|
||
></u-icon>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 空状态 -->
|
||
<view v-if="!ticketList.length && !ticketLoading" class="empty-state">
|
||
<text class="empty-text">没有更多数据了</text>
|
||
</view>
|
||
|
||
<!-- 加载状态 -->
|
||
<view v-if="ticketLoading" class="loading-state">
|
||
<u-loading-icon mode="spinner"></u-loading-icon>
|
||
<text class="loading-text">加载中...</text>
|
||
</view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 撤销确认弹窗 -->
|
||
<u-modal
|
||
:show="showCancelModal"
|
||
title="确认撤销"
|
||
:content="cancelModalContent"
|
||
:show-cancel-button="true"
|
||
confirm-text="确认撤销"
|
||
cancel-text="取消"
|
||
@confirm="confirmCancel"
|
||
@cancel="showCancelModal = false"
|
||
></u-modal>
|
||
|
||
<!-- 修改信息弹窗 -->
|
||
<u-popup :show="editModalVisible" mode="center" border-radius="12">
|
||
<view class="edit-modal">
|
||
<view class="modal-header">
|
||
<text class="modal-title">修改门票信息</text>
|
||
<u-icon name="close" size="20" @click="closeEditModal"></u-icon>
|
||
</view>
|
||
<scroll-view scroll-y class="modal-content">
|
||
<view class="form-item">
|
||
<text class="form-label optional">活动名称</text>
|
||
<input
|
||
class="form-input disabled"
|
||
:value="editForm.actName"
|
||
disabled
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label optional">订单编号</text>
|
||
<input
|
||
class="form-input disabled"
|
||
:value="editForm.orderCode"
|
||
disabled
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label">姓名</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.buyName"
|
||
placeholder="请输入姓名"
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label">手机号</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.phone"
|
||
placeholder="请输入手机号"
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label">身份证号</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.idCard"
|
||
placeholder="请输入身份证号"
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label">性别</text>
|
||
<u-radio-group v-model="editForm.sex" direction="row">
|
||
<u-radio :name="1" label="男"></u-radio>
|
||
<u-radio :name="0" label="女"></u-radio>
|
||
</u-radio-group>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label">尺码</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.clothSize"
|
||
placeholder="请输入尺码"
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label optional">同住人</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.cohabitant"
|
||
placeholder="请输入同住人"
|
||
/>
|
||
</view>
|
||
<view class="form-item">
|
||
<text class="form-label optional">紧急联系人</text>
|
||
<input
|
||
class="form-input"
|
||
v-model="editForm.emergencyPhone"
|
||
placeholder="请输入紧急联系人电话"
|
||
/>
|
||
</view>
|
||
</scroll-view>
|
||
<view class="modal-footer">
|
||
<button class="confirm-btn" @click="updateTicketInfo">确定</button>
|
||
</view>
|
||
</view>
|
||
</u-popup>
|
||
</view>
|
||
</template>
|
||
|
||
<script>
|
||
import {
|
||
getTicketActivityList,
|
||
getMyTicketList,
|
||
cancelTicket,
|
||
updateTicket,
|
||
} from '@/config/ticket.js'
|
||
|
||
export default {
|
||
data() {
|
||
return {
|
||
currentTab: 0,
|
||
activityList: [],
|
||
ticketList: [],
|
||
loading: false,
|
||
ticketLoading: false,
|
||
activityPage: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
},
|
||
ticketPage: {
|
||
pageNum: 1,
|
||
pageSize: 10,
|
||
},
|
||
// 弹窗相关
|
||
showCancelModal: false,
|
||
editModalVisible: false,
|
||
selectedTicket: null,
|
||
editForm: {
|
||
pkId: '',
|
||
actName: '',
|
||
memberCode: '',
|
||
memberName: '',
|
||
orderCode: '',
|
||
orderAmount: '',
|
||
price: '',
|
||
quantity: '',
|
||
buyName: '',
|
||
phone: '',
|
||
idCard: '',
|
||
sex: '',
|
||
sexVal: '',
|
||
clothSize: '',
|
||
cohabitant: '',
|
||
emergencyPhone: '',
|
||
creationTime: '',
|
||
},
|
||
}
|
||
},
|
||
computed: {
|
||
// 撤销弹窗内容
|
||
cancelModalContent() {
|
||
return this.selectedTicket
|
||
? `确定要撤销订单 ${this.selectedTicket.orderCode} 吗?撤销后不可恢复。`
|
||
: '确定要撤销此订单吗?撤销后不可恢复。'
|
||
},
|
||
},
|
||
onLoad() {
|
||
this.loadActivityList()
|
||
},
|
||
onPullDownRefresh() {
|
||
this.refreshCurrentTab()
|
||
},
|
||
// onReachBottom() {
|
||
// this.loadMoreData()
|
||
// },
|
||
methods: {
|
||
// 返回上一页
|
||
goBack() {
|
||
uni.navigateBack()
|
||
},
|
||
|
||
// 切换Tab
|
||
switchTab(index) {
|
||
this.currentTab = index
|
||
if (index === 0) {
|
||
this.loadActivityList()
|
||
} else {
|
||
this.loadTicketList()
|
||
}
|
||
},
|
||
|
||
// 刷新当前Tab数据
|
||
refreshCurrentTab() {
|
||
if (this.currentTab === 0) {
|
||
this.activityPage.pageNum = 1
|
||
this.activityList = []
|
||
this.loadActivityList()
|
||
} else {
|
||
this.ticketPage.pageNum = 1
|
||
this.ticketList = []
|
||
this.loadTicketList()
|
||
}
|
||
},
|
||
|
||
// 加载更多数据
|
||
loadMoreData() {
|
||
if (this.currentTab === 0) {
|
||
this.activityPage.pageNum++
|
||
this.loadActivityList()
|
||
} else {
|
||
this.ticketPage.pageNum++
|
||
this.loadTicketList()
|
||
}
|
||
},
|
||
|
||
// 加载活动列表
|
||
async loadActivityList() {
|
||
this.loading = true
|
||
try {
|
||
const res = await getTicketActivityList(this.activityPage)
|
||
if (res.code === 200) {
|
||
if (this.activityPage.pageNum === 1) {
|
||
this.activityList = res.rows || []
|
||
} else {
|
||
this.activityList.push(...(res.rows || []))
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载活动列表失败:', error)
|
||
uni.$u.toast('加载失败,请重试')
|
||
} finally {
|
||
this.loading = false
|
||
uni.stopPullDownRefresh()
|
||
}
|
||
},
|
||
|
||
// 加载门票列表
|
||
async loadTicketList() {
|
||
this.ticketLoading = true
|
||
try {
|
||
const res = await getMyTicketList(this.ticketPage)
|
||
if (res.code === 200) {
|
||
if (this.ticketPage.pageNum === 1) {
|
||
this.ticketList = res.rows || []
|
||
} else {
|
||
this.ticketList.push(...(res.rows || []))
|
||
}
|
||
}
|
||
} catch (error) {
|
||
console.error('加载门票列表失败:', error)
|
||
uni.$u.toast('加载失败,请重试')
|
||
} finally {
|
||
this.ticketLoading = false
|
||
uni.stopPullDownRefresh()
|
||
}
|
||
},
|
||
|
||
// 去购买门票
|
||
goBuyTicket(activity) {
|
||
uni.navigateTo({
|
||
url: `/pages/ticket/buy?activityId=${activity.pkId}&activityName=${encodeURIComponent(activity.actName)}&price=${activity.payMoney}`,
|
||
})
|
||
},
|
||
|
||
// 查看门票详情
|
||
goTicketDetail(ticket) {
|
||
uni.navigateTo({
|
||
url: `/pages/ticket/detail?ticketId=${ticket.pkId}`,
|
||
})
|
||
},
|
||
|
||
// 切换展开/收起状态
|
||
toggleExpand(item) {
|
||
// 使用 $set 确保响应式更新
|
||
this.$set(item, 'expanded', !item.expanded)
|
||
},
|
||
|
||
// 判断是否为当天购买
|
||
isWithin24Hours(creationTime) {
|
||
if (!creationTime) return false
|
||
const createDate = new Date(creationTime)
|
||
const now = new Date()
|
||
|
||
// 获取创建日期的年月日
|
||
const createYear = createDate.getFullYear()
|
||
const createMonth = createDate.getMonth()
|
||
const createDay = createDate.getDate()
|
||
|
||
// 获取当前日期的年月日
|
||
const nowYear = now.getFullYear()
|
||
const nowMonth = now.getMonth()
|
||
const nowDay = now.getDate()
|
||
|
||
// 判断是否为同一天
|
||
return (
|
||
createYear === nowYear &&
|
||
createMonth === nowMonth &&
|
||
createDay === nowDay
|
||
)
|
||
},
|
||
|
||
// 显示撤销确认弹窗
|
||
showCancelConfirm(ticket) {
|
||
this.selectedTicket = ticket
|
||
this.showCancelModal = true
|
||
},
|
||
|
||
// 确认撤销门票
|
||
async confirmCancel() {
|
||
if (!this.selectedTicket) return
|
||
|
||
try {
|
||
uni.showLoading({ title: '撤销中...' })
|
||
const res = await cancelTicket({
|
||
orderCode: this.selectedTicket.orderCode,
|
||
})
|
||
|
||
if (res.code === 200) {
|
||
uni.$u.toast('撤销成功')
|
||
this.showCancelModal = false
|
||
this.selectedTicket = null
|
||
// 刷新列表
|
||
this.refreshCurrentTab()
|
||
} else {
|
||
uni.$u.toast(res.msg || '撤销失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('撤销门票失败:', error)
|
||
uni.$u.toast('撤销失败,请重试')
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
|
||
// 显示修改信息弹窗
|
||
showEditModal(ticket) {
|
||
this.selectedTicket = ticket
|
||
// 填充表单数据
|
||
this.editForm = {
|
||
pkId: ticket.pkId,
|
||
actName: ticket.actName,
|
||
memberCode: ticket.memberCode,
|
||
memberName: ticket.memberName,
|
||
orderCode: ticket.orderCode,
|
||
orderAmount: ticket.orderAmount,
|
||
price: ticket.price,
|
||
quantity: ticket.quantity,
|
||
buyName: ticket.buyName || '',
|
||
phone: ticket.phone || '',
|
||
idCard: ticket.idCard || '',
|
||
sex: ticket.sex || '',
|
||
sexVal: ticket.sexVal || '',
|
||
clothSize: ticket.clothSize || '',
|
||
cohabitant: ticket.cohabitant || '',
|
||
emergencyPhone: ticket.emergencyPhone || '',
|
||
creationTime: ticket.creationTime,
|
||
}
|
||
this.editModalVisible = true
|
||
},
|
||
|
||
// 关闭修改弹窗
|
||
closeEditModal() {
|
||
this.editModalVisible = false
|
||
this.selectedTicket = null
|
||
this.editForm = {
|
||
pkId: '',
|
||
actName: '',
|
||
memberCode: '',
|
||
memberName: '',
|
||
orderCode: '',
|
||
orderAmount: '',
|
||
price: '',
|
||
quantity: '',
|
||
buyName: '',
|
||
phone: '',
|
||
idCard: '',
|
||
sex: '',
|
||
sexVal: '',
|
||
clothSize: '',
|
||
cohabitant: '',
|
||
emergencyPhone: '',
|
||
creationTime: '',
|
||
}
|
||
},
|
||
|
||
// 更新门票信息
|
||
async updateTicketInfo() {
|
||
// 表单验证
|
||
if (!this.editForm.buyName) {
|
||
uni.$u.toast('请输入姓名')
|
||
return
|
||
}
|
||
if (!this.editForm.phone) {
|
||
uni.$u.toast('请输入手机号')
|
||
return
|
||
}
|
||
if (!this.editForm.idCard) {
|
||
uni.$u.toast('请输入身份证号')
|
||
return
|
||
}
|
||
if (!this.editForm.sex && this.editForm.sex !== 0) {
|
||
uni.$u.toast('请选择性别')
|
||
return
|
||
}
|
||
if (!this.editForm.clothSize) {
|
||
uni.$u.toast('请输入尺码')
|
||
return
|
||
}
|
||
if (this.editForm.emergencyPhone === this.editForm.phone) {
|
||
uni.$u.toast('紧急联系方式不能与联系方式相同')
|
||
return
|
||
}
|
||
|
||
// 设置性别值
|
||
this.editForm.sexVal = this.editForm.sex === '1' ? '男' : '女'
|
||
|
||
try {
|
||
uni.showLoading({ title: '更新中...' })
|
||
const res = await updateTicket(this.editForm)
|
||
|
||
if (res.code === 200) {
|
||
uni.$u.toast('修改成功')
|
||
this.closeEditModal()
|
||
// 刷新列表
|
||
this.refreshCurrentTab()
|
||
} else {
|
||
uni.$u.toast(res.msg || '修改失败')
|
||
}
|
||
} catch (error) {
|
||
console.error('更新门票信息失败:', error)
|
||
uni.$u.toast('修改失败,请重试')
|
||
} finally {
|
||
uni.hideLoading()
|
||
}
|
||
},
|
||
},
|
||
}
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
::v-deep(.uni-scroll-view) {
|
||
box-sizing: border-box;
|
||
}
|
||
.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: 2rpx solid #eee;
|
||
|
||
.navbar-content {
|
||
display: flex;
|
||
align-items: center;
|
||
height: 88rpx;
|
||
padding: 0 32rpx;
|
||
|
||
.back-btn {
|
||
width: 80rpx;
|
||
height: 80rpx;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
|
||
.navbar-title {
|
||
flex: 1;
|
||
text-align: center;
|
||
font-size: 36rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
|
||
.placeholder {
|
||
width: 80rpx;
|
||
}
|
||
}
|
||
}
|
||
|
||
.tab-container {
|
||
position: fixed;
|
||
top: calc(var(--status-bar-height) + 88rpx);
|
||
left: 0;
|
||
right: 0;
|
||
z-index: 998;
|
||
background: #fff;
|
||
border-bottom: 2rpx solid #eee;
|
||
|
||
.tab-wrapper {
|
||
display: flex;
|
||
align-items: center;
|
||
|
||
.tab-item {
|
||
flex: 1;
|
||
position: relative;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
padding: 32rpx 0;
|
||
cursor: pointer;
|
||
|
||
.tab-text {
|
||
font-size: 32rpx;
|
||
color: #666;
|
||
transition: color 0.3s;
|
||
}
|
||
|
||
.tab-line {
|
||
position: absolute;
|
||
bottom: 0;
|
||
width: 60rpx;
|
||
height: 6rpx;
|
||
background: #005bac;
|
||
border-radius: 3rpx;
|
||
}
|
||
|
||
&.active .tab-text {
|
||
color: #005bac;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.content-area {
|
||
margin-top: calc(100rpx);
|
||
padding: 24rpx;
|
||
min-height: calc(100vh - 100rpx);
|
||
}
|
||
|
||
.activity-card {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
margin-bottom: 24rpx;
|
||
overflow: hidden;
|
||
box-shadow: 0 2rpx 12rpx rgba(0, 0, 0, 0.08);
|
||
border: 1rpx solid #f0f0f0;
|
||
|
||
.card-content {
|
||
display: flex;
|
||
padding: 24rpx;
|
||
gap: 20rpx;
|
||
|
||
.activity-image {
|
||
flex-shrink: 0;
|
||
width: 208rpx;
|
||
height: 208rpx;
|
||
border-radius: 40rpx;
|
||
overflow: hidden;
|
||
image {
|
||
width: 100%;
|
||
height: 100%;
|
||
}
|
||
}
|
||
|
||
.activity-info {
|
||
flex: 1;
|
||
display: flex;
|
||
flex-direction: column;
|
||
|
||
.activity-title {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
line-height: 1.4;
|
||
margin-bottom: 16rpx;
|
||
}
|
||
|
||
.activity-detail {
|
||
display: flex;
|
||
margin-bottom: 8rpx;
|
||
|
||
.detail-label {
|
||
font-size: 20rpx;
|
||
color: #999;
|
||
min-width: 140rpx;
|
||
}
|
||
|
||
.detail-value {
|
||
font-size: 20rpx;
|
||
color: #666;
|
||
flex: 1;
|
||
}
|
||
}
|
||
|
||
.bottom-section {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
.price-info {
|
||
display: flex;
|
||
align-items: baseline;
|
||
color: #ff4444;
|
||
|
||
.price-symbol {
|
||
font-size: 24rpx;
|
||
margin-right: 2rpx;
|
||
}
|
||
|
||
.price-value {
|
||
font-size: 32rpx;
|
||
font-weight: 700;
|
||
}
|
||
}
|
||
|
||
.buy-btn {
|
||
background: #005bac;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 40rpx;
|
||
padding: 0rpx 32rpx;
|
||
font-size: 20rpx;
|
||
font-weight: 600;
|
||
margin: 0;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.ticket-card {
|
||
background: #fff;
|
||
border-radius: 16rpx;
|
||
margin-bottom: 24rpx;
|
||
padding: 24rpx;
|
||
box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.04);
|
||
|
||
.ticket-header {
|
||
margin-bottom: 16rpx;
|
||
|
||
.order-code {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
}
|
||
}
|
||
|
||
.ticket-content {
|
||
.ticket-info {
|
||
.ticket-title {
|
||
font-size: 28rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
line-height: 1.3;
|
||
}
|
||
|
||
.ticket-detail {
|
||
display: flex;
|
||
margin-bottom: 12rpx;
|
||
|
||
.detail-label {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
min-width: 140rpx;
|
||
}
|
||
|
||
.detail-value {
|
||
font-size: 24rpx;
|
||
color: #666;
|
||
|
||
&.price {
|
||
color: #ff4444;
|
||
font-weight: 600;
|
||
}
|
||
}
|
||
}
|
||
|
||
.expanded-details {
|
||
animation: fadeIn 0.3s ease-in-out;
|
||
|
||
.ticket-detail {
|
||
margin-bottom: 12rpx;
|
||
}
|
||
}
|
||
|
||
.action-buttons {
|
||
display: flex;
|
||
gap: 16rpx;
|
||
margin-top: 16rpx;
|
||
padding: 16rpx 0;
|
||
|
||
.cancel-btn,
|
||
.edit-btn {
|
||
flex: 1;
|
||
height: 60rpx;
|
||
border: none;
|
||
border-radius: 30rpx;
|
||
font-size: 24rpx;
|
||
font-weight: 600;
|
||
margin: 0;
|
||
}
|
||
|
||
.cancel-btn {
|
||
background: #fff;
|
||
color: #ff4444;
|
||
border: 2rpx solid #ff4444;
|
||
}
|
||
|
||
.edit-btn {
|
||
background: #005bac;
|
||
color: #fff;
|
||
}
|
||
}
|
||
|
||
.expand-action {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
margin-top: 16rpx;
|
||
padding: 16rpx 0;
|
||
border-top: 1rpx solid #eee;
|
||
cursor: pointer;
|
||
transition: background-color 0.2s;
|
||
|
||
&:active {
|
||
background-color: #f8f8f8;
|
||
}
|
||
|
||
.expand-text {
|
||
font-size: 24rpx;
|
||
color: #999;
|
||
margin-right: 8rpx;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.empty-state,
|
||
.loading-state {
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
justify-content: center;
|
||
padding: 120rpx 0;
|
||
|
||
.empty-text,
|
||
.loading-text {
|
||
font-size: 28rpx;
|
||
color: #999;
|
||
margin-top: 16rpx;
|
||
}
|
||
}
|
||
|
||
@keyframes fadeIn {
|
||
from {
|
||
opacity: 0;
|
||
transform: translateY(-10rpx);
|
||
}
|
||
to {
|
||
opacity: 1;
|
||
transform: translateY(0);
|
||
}
|
||
}
|
||
|
||
// 修改信息弹窗样式
|
||
.edit-modal {
|
||
width: 640rpx;
|
||
max-height: 90vh;
|
||
background: #fff;
|
||
border-radius: 24rpx;
|
||
overflow: hidden;
|
||
|
||
.modal-header {
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: space-between;
|
||
padding: 32rpx;
|
||
border-bottom: 2rpx solid #eee;
|
||
|
||
.modal-title {
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
color: #333;
|
||
}
|
||
}
|
||
|
||
.modal-content {
|
||
max-height: 70vh;
|
||
padding: 32rpx;
|
||
box-sizing: border-box;
|
||
padding-bottom: 20px;
|
||
overflow-y: hidden;
|
||
.form-item {
|
||
margin-bottom: 32rpx;
|
||
|
||
.form-label {
|
||
display: block;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
margin-bottom: 16rpx;
|
||
|
||
&::after {
|
||
content: '*';
|
||
color: #ff4444;
|
||
margin-left: 4rpx;
|
||
}
|
||
|
||
&.optional::after {
|
||
display: none;
|
||
}
|
||
}
|
||
|
||
.form-input {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
padding: 0 24rpx;
|
||
border: 2rpx solid #ddd;
|
||
border-radius: 12rpx;
|
||
font-size: 28rpx;
|
||
color: #333;
|
||
background: #fff;
|
||
box-sizing: border-box;
|
||
|
||
&.disabled {
|
||
background: #f5f5f5;
|
||
color: #999;
|
||
}
|
||
|
||
&:focus {
|
||
border-color: #005bac;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
.modal-footer {
|
||
padding: 32rpx;
|
||
border-top: 2rpx solid #eee;
|
||
|
||
.confirm-btn {
|
||
width: 100%;
|
||
height: 80rpx;
|
||
background: #005bac;
|
||
color: #fff;
|
||
border: none;
|
||
border-radius: 40rpx;
|
||
font-size: 32rpx;
|
||
font-weight: 600;
|
||
margin: 0;
|
||
}
|
||
}
|
||
}
|
||
</style>
|