forked from angelo/web-retail-h5
				
			
		
			
				
	
	
		
			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="2" 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>
 |