241 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
			
		
		
	
	
			241 lines
		
	
	
		
			7.2 KiB
		
	
	
	
		
			Vue
		
	
	
	
	
	
| <route lang="json5" type="page">
 | ||
| {
 | ||
|   layout: 'default',
 | ||
|   style: {
 | ||
|     navigationBarTitleText: '退款记录',
 | ||
|   },
 | ||
| }
 | ||
| </route>
 | ||
| 
 | ||
| <template>
 | ||
|   <view class="min-h-screen bg-gray-50 pb-20">
 | ||
|     <!-- 消费统计 -->
 | ||
|     <view class="mx-4 mt-4">
 | ||
|       <view class="bg-white rounded-2xl shadow-sm p-6">
 | ||
|         <view class="text-center">
 | ||
|           <text class="text-lg font-bold text-gray-800 mb-2 block">退款统计</text>
 | ||
|           <view class="grid grid-cols-2 gap-4">
 | ||
|             <view class="text-center">
 | ||
|               <text class="text-2xl font-bold text-sky-500 block">¥{{ totalSpend }}</text>
 | ||
|               <text class="text-sm text-gray-500">总退款数</text>
 | ||
|             </view>
 | ||
|             <view class="text-center">
 | ||
|               <text class="text-2xl font-bold text-indigo-500 block">{{ spendCount }}</text>
 | ||
|               <text class="text-sm text-gray-500">退款次数</text>
 | ||
|             </view>
 | ||
|           </view>
 | ||
|         </view>
 | ||
|       </view>
 | ||
|     </view>
 | ||
| 
 | ||
|     <!-- 消费记录列表 -->
 | ||
|     <view class="mx-4 mt-4">
 | ||
|       <view class="bg-white rounded-2xl shadow-sm overflow-hidden">
 | ||
|         <view class="p-4 border-b border-gray-100 flex justify-between items-center">
 | ||
|           <text class="text-base font-bold text-gray-800">退款明细</text>
 | ||
|           <text class="text-sm text-sky-500" @tap="refreshData">刷新</text>
 | ||
|         </view>
 | ||
|         <view v-if="loading" class="p-8 text-center">
 | ||
|           <text class="text-gray-500">加载中...</text>
 | ||
|         </view>
 | ||
|         <view v-else-if="error" class="p-8 text-center">
 | ||
|           <text class="text-red-500">{{ error }}</text>
 | ||
|         </view>
 | ||
|         <view v-else-if="spendList.length === 0" class="p-8 text-center">
 | ||
|           <text class="text-gray-500">暂无退款记录</text>
 | ||
|         </view>
 | ||
|         <view v-else class="divide-y divide-gray-100">
 | ||
|           <view v-for="(item, index) in spendList" :key="index" class="p-4">
 | ||
|             <!-- 顶部:退款金额和状态 -->
 | ||
|             <view class="flex items-center justify-between mb-3">
 | ||
|               <text class="text-lg font-bold text-rose-500">
 | ||
|                 -¥{{ formatPrice(item.refundPoints) }}
 | ||
|               </text>
 | ||
|               <view
 | ||
|                 :class="[
 | ||
|                   'px-3 py-1 rounded-full text-xs border',
 | ||
|                   item.refundStatus === '0'
 | ||
|                     ? 'bg-yellow-50 text-yellow-600 border-yellow-100'
 | ||
|                     : item.refundStatus === '1'
 | ||
|                       ? 'bg-green-50 text-green-600 border-green-100'
 | ||
|                       : 'bg-red-50 text-red-600 border-red-100',
 | ||
|                 ]"
 | ||
|               >
 | ||
|                 {{ getRefundStatusText(item.refundStatus) }}
 | ||
|               </view>
 | ||
|             </view>
 | ||
| 
 | ||
|             <!-- 中间:退款原因 -->
 | ||
|             <view class="mb-3">
 | ||
|               <view class="flex items-center mb-1">
 | ||
|                 <view
 | ||
|                   class="bg-sky-50 text-sky-600 px-2 py-0.5 rounded-full text-xs border border-sky-100 mr-2"
 | ||
|                 >
 | ||
|                   退款原因
 | ||
|                 </view>
 | ||
|                 <text class="text-gray-600 text-sm flex-1">{{ item.refundReason }}</text>
 | ||
|               </view>
 | ||
|             </view>
 | ||
| 
 | ||
|             <!-- 底部:时间和操作按钮 -->
 | ||
|             <view class="flex items-center justify-between">
 | ||
|               <view class="flex flex-col space-y-1">
 | ||
|                 <text class="text-xs text-gray-500">
 | ||
|                   申请时间:{{ formatDate(item.createTime) }}
 | ||
|                 </text>
 | ||
|                 <text v-if="item.auditTime" class="text-xs text-gray-500">
 | ||
|                   审核时间:{{ formatDate(item.auditTime) }}
 | ||
|                 </text>
 | ||
|               </view>
 | ||
|               <button
 | ||
|                 v-if="item.refundStatus === '0'"
 | ||
|                 class="flex items-center justify-center bg-white border border-green-200 text-green-500 px-4 py-1.5 rounded-lg text-xs hover:bg-green-50 active:bg-green-100 transition-colors mr-0"
 | ||
|                 @tap="handleCancelRefund(item.id)"
 | ||
|               >
 | ||
|                 <i class="i-carbon-close text-sm mr-1"></i>
 | ||
|                 撤销
 | ||
|               </button>
 | ||
|             </view>
 | ||
|           </view>
 | ||
|         </view>
 | ||
|       </view>
 | ||
|     </view>
 | ||
|   </view>
 | ||
| </template>
 | ||
| 
 | ||
| <script lang="ts" setup>
 | ||
| import { ref, computed, onMounted } from 'vue'
 | ||
| import { getUserRefundInfoAPI, cancelRefundAPI } from '@/service/login'
 | ||
| import type { RefundInfoList } from '@/service/login/type'
 | ||
| 
 | ||
| const spendList = ref<RefundInfoList[]>([])
 | ||
| const loading = ref(false)
 | ||
| const error = ref('')
 | ||
| 
 | ||
| // 计算总消费
 | ||
| const totalSpend = computed(() => {
 | ||
|   return spendList.value.reduce((sum, item) => sum + Number(item.refundPoints), 0).toFixed(2)
 | ||
| })
 | ||
| 
 | ||
| // 计算消费次数
 | ||
| const spendCount = computed(() => spendList.value.length)
 | ||
| 
 | ||
| // 获取消费类型文本
 | ||
| const getSpendTypeText = (type: number) => {
 | ||
|   const typeMap: Record<number, string> = {
 | ||
|     1: '解锁用户',
 | ||
|     2: '充值',
 | ||
|     3: '其他',
 | ||
|   }
 | ||
|   return typeMap[type] || '未知类型'
 | ||
| }
 | ||
| 
 | ||
| // 格式化日期
 | ||
| const formatDate = (dateStr: string) => {
 | ||
|   try {
 | ||
|     const date = new Date(dateStr)
 | ||
|     return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')} ${String(date.getHours()).padStart(2, '0')}:${String(date.getMinutes()).padStart(2, '0')}`
 | ||
|   } catch (e) {
 | ||
|     return dateStr
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 格式化价格
 | ||
| const formatPrice = (price: string) => {
 | ||
|   try {
 | ||
|     return Number(price).toFixed(2)
 | ||
|   } catch (e) {
 | ||
|     return '0.00'
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 获取消费记录
 | ||
| const getSpendList = async () => {
 | ||
|   loading.value = true
 | ||
|   error.value = ''
 | ||
| 
 | ||
|   try {
 | ||
|     const res = await getUserRefundInfoAPI()
 | ||
|     if (res.code === 200) {
 | ||
|       spendList.value = res.data || []
 | ||
|     } else {
 | ||
|       error.value = res.message || '获取充值记录失败'
 | ||
|       uni.showToast({
 | ||
|         title: error.value,
 | ||
|         icon: 'none',
 | ||
|         duration: 2000,
 | ||
|       })
 | ||
|     }
 | ||
|   } catch (e) {
 | ||
|     error.value = '网络请求失败,请稍后重试'
 | ||
|     uni.showToast({
 | ||
|       title: error.value,
 | ||
|       icon: 'none',
 | ||
|       duration: 2000,
 | ||
|     })
 | ||
|   } finally {
 | ||
|     loading.value = false
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 刷新数据
 | ||
| const refreshData = () => {
 | ||
|   getSpendList()
 | ||
| }
 | ||
| 
 | ||
| // 获取退款状态文本
 | ||
| const getRefundStatusText = (status: string) => {
 | ||
|   const statusMap: Record<string, string> = {
 | ||
|     '0': '审核中',
 | ||
|     '1': '已通过',
 | ||
|     '2': '已拒绝',
 | ||
|   }
 | ||
|   return statusMap[status] || '未知状态'
 | ||
| }
 | ||
| 
 | ||
| // 处理撤销退款
 | ||
| const handleCancelRefund = async (id: string) => {
 | ||
|   try {
 | ||
|     uni.showModal({
 | ||
|       title: '提示',
 | ||
|       content: '确定要撤销该退款申请吗?',
 | ||
|       success: async (res) => {
 | ||
|         if (res.confirm) {
 | ||
|           uni.showLoading({
 | ||
|             title: '处理中...',
 | ||
|             mask: true,
 | ||
|           })
 | ||
| 
 | ||
|           const result = await cancelRefundAPI(id)
 | ||
| 
 | ||
|           if (result.code === 200) {
 | ||
|             uni.showToast({
 | ||
|               title: '撤销成功',
 | ||
|               icon: 'success',
 | ||
|             })
 | ||
|             // 刷新列表
 | ||
|             getSpendList()
 | ||
|           } else {
 | ||
|             uni.showToast({
 | ||
|               title: result.message || '撤销失败',
 | ||
|               icon: 'none',
 | ||
|             })
 | ||
|           }
 | ||
|         }
 | ||
|       },
 | ||
|     })
 | ||
|   } catch (error) {
 | ||
|     uni.showToast({
 | ||
|       title: '操作失败,请稍后重试',
 | ||
|       icon: 'none',
 | ||
|     })
 | ||
|   } finally {
 | ||
|     uni.hideLoading()
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| onMounted(() => {
 | ||
|   getSpendList()
 | ||
| })
 | ||
| </script>
 | 
