487 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
			
		
		
	
	
			487 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			Vue
		
	
	
	
| <template>
 | ||
|   <view class="refund-container">
 | ||
|     <!-- 导航栏 -->
 | ||
|     <u-navbar
 | ||
|       title="退款列表"
 | ||
|       :border-bottom="false"
 | ||
|       :background="{ backgroundColor: '#005bac' }"
 | ||
|       title-color="#fff"
 | ||
|     />
 | ||
|     <view class="tips">
 | ||
|       <u-icon name="info-circle" color="#005bac" size="20"></u-icon>
 | ||
|       <text class="tips-text">如有疑问,请联系客服</text>
 | ||
|     </view>
 | ||
|     <!-- <view class="date-filter">
 | ||
|       <view class="date-picker-container">
 | ||
|         <view class="date-input-wrapper" @click="showStartDatePicker = true">
 | ||
|           <text>{{ startDate || '开始时间' }}</text>
 | ||
|         </view>
 | ||
|         <text class="separator">至</text>
 | ||
|         <view class="date-input-wrapper" @click="showEndDatePicker = true">
 | ||
|           <text>{{ endDate || '结束时间' }}</text>
 | ||
|         </view>
 | ||
|       </view>
 | ||
|       <button class="search-button" @click="handleSearch">
 | ||
|         <u-icon name="search" color="#ffffff" size="20" />
 | ||
|       </button>
 | ||
|     </view> -->
 | ||
|     <!-- 空状态 -->
 | ||
|     <u-empty
 | ||
|       mode="data"
 | ||
|       v-if="refundList.length === 0 && !loading"
 | ||
|       text="暂无退款记录"
 | ||
|     ></u-empty>
 | ||
|     <!-- 退款列表 -->
 | ||
|     <view class="refund-list">
 | ||
|       <u-list @scrolltolower="loadMore" :show-scrollbar="false">
 | ||
|         <u-list-item v-for="(item, index) in refundList" :key="index">
 | ||
|           <view class="refund-item">
 | ||
|             <view class="refund-header">
 | ||
|               <view class="order-info">
 | ||
|                 <text class="order-number"
 | ||
|                   >订单编号:{{ item.businessCode }}</text
 | ||
|                 >
 | ||
|                 <text class="member-code">会员编号:{{ item.memberCode }}</text>
 | ||
|               </view>
 | ||
|               <view
 | ||
|                 class="refund-status"
 | ||
|                 :class="getStatusClass(item.refundStatus)"
 | ||
|               >
 | ||
|                 {{ getStatusText(item.refundStatus) }}
 | ||
|               </view>
 | ||
|             </view>
 | ||
|             <view class="refund-content">
 | ||
|               <view class="refund-amount">
 | ||
|                 <text class="amount-label">退款金额</text>
 | ||
|                 <text class="amount-value"
 | ||
|                   >¥{{ stateFormat(item.refundMoney) }}</text
 | ||
|                 >
 | ||
|               </view>
 | ||
|               <view class="refund-time">
 | ||
|                 <text class="time-label">退款时间</text>
 | ||
|                 <text class="time-value">{{
 | ||
|                   formatDate(item.finishTime)
 | ||
|                 }}</text>
 | ||
|               </view>
 | ||
|             </view>
 | ||
|           </view>
 | ||
|         </u-list-item>
 | ||
|       </u-list>
 | ||
| 
 | ||
|       <!-- 加载更多 -->
 | ||
|       <u-loadmore :status="loadStatus" />
 | ||
|     </view>
 | ||
| 
 | ||
|     <u-datetime-picker
 | ||
|       :show="showStartDatePicker"
 | ||
|       v-model="startDate"
 | ||
|       mode="date"
 | ||
|       @confirm="onStartDateConfirm"
 | ||
|       @cancel="showStartDatePicker = false"
 | ||
|       style="flex: 0"
 | ||
|     ></u-datetime-picker>
 | ||
|     <u-datetime-picker
 | ||
|       :show="showEndDatePicker"
 | ||
|       v-model="endDate"
 | ||
|       mode="date"
 | ||
|       @confirm="onEndDateConfirm"
 | ||
|       @cancel="showEndDatePicker = false"
 | ||
|       style="flex: 0"
 | ||
|     ></u-datetime-picker>
 | ||
|   </view>
 | ||
| </template>
 | ||
| 
 | ||
| <script>
 | ||
| import { getRefundList } from '@/config/mine'
 | ||
| import dayjs from '../../uni_modules/uview-ui/libs/util/dayjs.js'
 | ||
| 
 | ||
| export default {
 | ||
|   name: 'RefundDetail',
 | ||
|   data() {
 | ||
|     return {
 | ||
|       // 筛选条件
 | ||
|       startDate: '',
 | ||
|       endDate: '',
 | ||
|       showStartDatePicker: false,
 | ||
|       showEndDatePicker: false,
 | ||
|       maxDate: new Date().getTime(),
 | ||
| 
 | ||
|       // 列表数据
 | ||
|       refundList: [],
 | ||
|       loading: false,
 | ||
|       loadStatus: 'loadmore',
 | ||
| 
 | ||
|       // 分页参数
 | ||
|       currentPage: 1,
 | ||
|       pageSize: 10,
 | ||
|       hasMore: true,
 | ||
| 
 | ||
|       // 状态映射
 | ||
|       statusMap: {
 | ||
|         0: '退款申请中',
 | ||
|         1: '退款中',
 | ||
|         2: '已退款',
 | ||
|         3: '退款失败',
 | ||
|       },
 | ||
|     }
 | ||
|   },
 | ||
|   onLoad() {
 | ||
|     this.loadRefundList()
 | ||
|   },
 | ||
|   onPullDownRefresh() {
 | ||
|     this.refreshList()
 | ||
|   },
 | ||
|   methods: {
 | ||
|     // 加载退款列表
 | ||
|     async loadRefundList(isLoadMore = false) {
 | ||
|       if (this.loading) return
 | ||
| 
 | ||
|       this.loading = true
 | ||
|       this.loadStatus = 'loading'
 | ||
| 
 | ||
|       try {
 | ||
|         const params = {
 | ||
|           pageNum: this.currentPage,
 | ||
|           pageSize: this.pageSize,
 | ||
|           startDate: this.startDate,
 | ||
|           endDate: this.endDate,
 | ||
|         }
 | ||
| 
 | ||
|         const res = await getRefundList(params)
 | ||
| 
 | ||
|         if (res.code === 200) {
 | ||
|           const newList = res.rows || []
 | ||
| 
 | ||
|           if (isLoadMore) {
 | ||
|             this.refundList = [...this.refundList, ...newList]
 | ||
|           } else {
 | ||
|             this.refundList = newList
 | ||
|           }
 | ||
| 
 | ||
|           // 判断是否还有更多数据
 | ||
|           this.hasMore = newList.length === this.pageSize
 | ||
|           this.loadStatus = this.hasMore ? 'loadmore' : 'nomore'
 | ||
| 
 | ||
|           if (this.hasMore) {
 | ||
|             this.currentPage++
 | ||
|           }
 | ||
|         } else {
 | ||
|           this.$u.toast(res.message || '加载失败')
 | ||
|           this.loadStatus = 'loadmore'
 | ||
|         }
 | ||
|       } catch (error) {
 | ||
|         console.error('加载退款列表失败:', error)
 | ||
|         this.$u.toast('加载失败,请重试')
 | ||
|         this.loadStatus = 'loadmore'
 | ||
|       } finally {
 | ||
|         this.loading = false
 | ||
|         uni.stopPullDownRefresh()
 | ||
|       }
 | ||
|     },
 | ||
|     stateFormat(val) {
 | ||
|       if (val) {
 | ||
|         return Number(val)
 | ||
|           .toFixed(2)
 | ||
|           .replace(/(\d)(?=(\d{3})+\.)/g, ($0, $1) => {
 | ||
|             return $1 + ','
 | ||
|           })
 | ||
|           .replace(/\.$/, '')
 | ||
|       }
 | ||
|     },
 | ||
|     // 加载更多
 | ||
|     loadMore() {
 | ||
|       if (this.hasMore && !this.loading) {
 | ||
|         this.loadRefundList(true)
 | ||
|       }
 | ||
|     },
 | ||
| 
 | ||
|     // 刷新列表
 | ||
|     refreshList() {
 | ||
|       this.currentPage = 1
 | ||
|       this.hasMore = true
 | ||
|       this.loadRefundList()
 | ||
|     },
 | ||
| 
 | ||
|     // 搜索
 | ||
|     handleSearch() {
 | ||
|       if (this.startDate && this.endDate && this.startDate > this.endDate) {
 | ||
|         this.$u.toast('开始日期不能大于结束日期')
 | ||
|         return
 | ||
|       }
 | ||
|       this.refreshList()
 | ||
|     },
 | ||
| 
 | ||
|     // 重置
 | ||
|     handleReset() {
 | ||
|       this.startDate = ''
 | ||
|       this.endDate = ''
 | ||
|       this.refreshList()
 | ||
|     },
 | ||
| 
 | ||
|     onStartDateConfirm(e) {
 | ||
|       this.startDate = this.formatDate(new Date(e.value))
 | ||
|       this.startDateValue = e.value
 | ||
|       this.showStartDatePicker = false
 | ||
|     },
 | ||
|     onEndDateConfirm(e) {
 | ||
|       this.endDate = this.formatDate(new Date(e.value))
 | ||
|       this.endDateValue = e.value
 | ||
|       this.showEndDatePicker = false
 | ||
|     },
 | ||
|     // 格式化显示日期
 | ||
|     formatDate(dateString) {
 | ||
|       if (!dateString) return ''
 | ||
|       return dayjs(dateString).format('YYYY-MM-DD HH:mm:ss')
 | ||
|     },
 | ||
|     // 获取状态文本
 | ||
|     getStatusText(status) {
 | ||
|       console.log(status)
 | ||
|       return this.statusMap[status] || '未知状态'
 | ||
|     },
 | ||
|     // 获取状态样式类
 | ||
|     getStatusClass(status) {
 | ||
|       const classMap = {
 | ||
|         0: 'status-pending',
 | ||
|         1: 'status-failed',
 | ||
|         2: 'status-success',
 | ||
|         3: 'status-cancelled',
 | ||
|       }
 | ||
|       return classMap[status] || 'status-default'
 | ||
|     },
 | ||
|   },
 | ||
| }
 | ||
| </script>
 | ||
| 
 | ||
| <style lang="scss" scoped>
 | ||
| .refund-container {
 | ||
|   min-height: 100vh;
 | ||
|   background-color: #f5f5f5;
 | ||
| }
 | ||
| 
 | ||
| .tips {
 | ||
|   display: flex;
 | ||
|   align-items: center;
 | ||
|   justify-content: center;
 | ||
|   background-color: #f8f9fa;
 | ||
|   margin: 16rpx 30rpx;
 | ||
|   padding: 12rpx 20rpx;
 | ||
|   border-radius: 4rpx;
 | ||
|   border-left: 3rpx solid #005bac;
 | ||
| 
 | ||
|   .tips-text {
 | ||
|     font-size: 22rpx;
 | ||
|     color: #005bac;
 | ||
|     font-weight: 400;
 | ||
|     margin-left: 8rpx;
 | ||
|     line-height: 1.5;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| .filter-section {
 | ||
|   background-color: #fff;
 | ||
|   padding: 20rpx 30rpx;
 | ||
|   margin-bottom: 20rpx;
 | ||
| 
 | ||
|   .date-filter {
 | ||
|     display: flex;
 | ||
|     align-items: center;
 | ||
|     margin-bottom: 20rpx;
 | ||
| 
 | ||
|     .date-item {
 | ||
|       flex: 1;
 | ||
|       display: flex;
 | ||
|       align-items: center;
 | ||
|       justify-content: space-between;
 | ||
|       padding: 20rpx;
 | ||
|       border: 1px solid #e4e4e4;
 | ||
|       border-radius: 8rpx;
 | ||
|       background-color: #fafafa;
 | ||
| 
 | ||
|       .date-label {
 | ||
|         font-size: 28rpx;
 | ||
|         color: #666;
 | ||
|       }
 | ||
| 
 | ||
|       .date-value {
 | ||
|         font-size: 28rpx;
 | ||
|         color: #333;
 | ||
|         margin-left: 10rpx;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     .date-separator {
 | ||
|       padding: 0 20rpx;
 | ||
|       font-size: 28rpx;
 | ||
|       color: #666;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .filter-actions {
 | ||
|     display: flex;
 | ||
|     justify-content: center;
 | ||
|     gap: 20rpx;
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| .refund-list {
 | ||
|   padding: 10rpx 30rpx 0;
 | ||
| }
 | ||
| 
 | ||
| .refund-item {
 | ||
|   background-color: #fff;
 | ||
|   border-radius: 12rpx;
 | ||
|   padding: 30rpx;
 | ||
|   margin-bottom: 20rpx;
 | ||
|   box-shadow: 0 2rpx 8rpx rgba(0, 0, 0, 0.1);
 | ||
| 
 | ||
|   .refund-header {
 | ||
|     display: flex;
 | ||
|     justify-content: space-between;
 | ||
|     align-items: flex-start;
 | ||
|     margin-bottom: 20rpx;
 | ||
| 
 | ||
|     .order-info {
 | ||
|       flex: 1;
 | ||
| 
 | ||
|       .order-number {
 | ||
|         display: block;
 | ||
|         font-size: 28rpx;
 | ||
|         color: #333;
 | ||
|         font-weight: 500;
 | ||
|         margin-bottom: 8rpx;
 | ||
|       }
 | ||
| 
 | ||
|       .member-code {
 | ||
|         font-size: 24rpx;
 | ||
|         color: #666;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     .refund-status {
 | ||
|       padding: 8rpx 16rpx;
 | ||
|       border-radius: 20rpx;
 | ||
|       font-size: 24rpx;
 | ||
|       font-weight: 500;
 | ||
| 
 | ||
|       &.status-pending {
 | ||
|         background-color: #fff7e6;
 | ||
|         color: #fa8c16;
 | ||
|       }
 | ||
| 
 | ||
|       &.status-success {
 | ||
|         background-color: #f6ffed;
 | ||
|         color: #52c41a;
 | ||
|       }
 | ||
| 
 | ||
|       &.status-failed {
 | ||
|         background-color: #fff2f0;
 | ||
|         color: #ff4d4f;
 | ||
|       }
 | ||
| 
 | ||
|       &.status-cancelled {
 | ||
|         background-color: #f5f5f5;
 | ||
|         color: #8c8c8c;
 | ||
|       }
 | ||
| 
 | ||
|       &.status-default {
 | ||
|         background-color: #f5f5f5;
 | ||
|         color: #666;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .refund-content {
 | ||
|     display: flex;
 | ||
|     justify-content: space-between;
 | ||
|     align-items: center;
 | ||
| 
 | ||
|     .refund-amount,
 | ||
|     .refund-time {
 | ||
|       display: flex;
 | ||
|       flex-direction: column;
 | ||
|       align-items: flex-start;
 | ||
| 
 | ||
|       .amount-label,
 | ||
|       .time-label {
 | ||
|         font-size: 24rpx;
 | ||
|         color: #666;
 | ||
|         margin-bottom: 8rpx;
 | ||
|       }
 | ||
| 
 | ||
|       .amount-value {
 | ||
|         font-size: 32rpx;
 | ||
|         color: #005bac;
 | ||
|         font-weight: 600;
 | ||
|       }
 | ||
| 
 | ||
|       .time-value {
 | ||
|         font-size: 28rpx;
 | ||
|         color: #333;
 | ||
|       }
 | ||
|     }
 | ||
| 
 | ||
|     .refund-time {
 | ||
|       align-items: flex-end;
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| 
 | ||
| // 响应式适配
 | ||
| @media (max-width: 750rpx) {
 | ||
|   .filter-section {
 | ||
|     .date-filter {
 | ||
|       flex-direction: column;
 | ||
|       gap: 20rpx;
 | ||
| 
 | ||
|       .date-separator {
 | ||
|         display: none;
 | ||
|       }
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| .date-filter {
 | ||
|   display: flex;
 | ||
|   align-items: center;
 | ||
|   padding: 15px 10px;
 | ||
|   background-color: #ffffff;
 | ||
| 
 | ||
|   .date-picker-container {
 | ||
|     flex: 1;
 | ||
|     display: flex;
 | ||
|     align-items: center;
 | ||
|     background-color: #f2f2f2;
 | ||
|     border-radius: 8px;
 | ||
|     padding: 4px;
 | ||
|     .date-input-wrapper {
 | ||
|       flex: 1;
 | ||
|       text-align: center;
 | ||
|       padding: 6px 0;
 | ||
|       font-size: 14px;
 | ||
|       color: #333;
 | ||
|     }
 | ||
|     .separator {
 | ||
|       color: #999;
 | ||
|       margin: 0 5px;
 | ||
|     }
 | ||
|   }
 | ||
| 
 | ||
|   .search-button {
 | ||
|     width: 44px;
 | ||
|     height: 36px;
 | ||
|     margin-left: 10px;
 | ||
|     background-color: #007aff;
 | ||
|     color: white;
 | ||
|     display: flex;
 | ||
|     align-items: center;
 | ||
|     justify-content: center;
 | ||
|     border-radius: 4px;
 | ||
|     padding: 0;
 | ||
|     line-height: 1;
 | ||
|     border: none;
 | ||
|     &:after {
 | ||
|       border: none;
 | ||
|     }
 | ||
|   }
 | ||
| }
 | ||
| </style>
 |