index.vue 6.17 KB
<template>
  <view class="min-h-screen bg-gray-50">
    <!-- Tabs -->
    <view class="bg-white px-4 py-2 border-b border-gray-200">
      <view class="flex space-x-6">
        <view
          v-for="tab in tabs"
          :key="tab.name"
          @click="handleTabChange(tab.name)"
          :class="{
            'text-blue-500 border-b-2 border-blue-500': activeTab === tab.name,
            'text-gray-500': activeTab !== tab.name
          }"
          class="pb-2 px-1 text-sm font-medium transition-colors"
        >
          {{ tab.label }}
        </view>
      </view>
    </view>

    <!-- Loading State -->
    <view v-if="loading" class="flex justify-center items-center py-20">
      <view class="text-gray-500">加载中...</view>
    </view>

    <!-- Content -->
    <view v-else class="p-4">
      <view v-if="filteredRewards.length > 0" class="space-y-4">
        <view
          v-for="reward in filteredRewards"
          :key="reward.id"
          class="bg-white rounded-xl p-4 flex items-center shadow-[0_2px_8px_rgba(0,0,0,0.08)]"
        >
          <image :src="reward.thumbnail || 'https://placehold.co/120x120/e2f3ff/0369a1?text=券&font=roboto'" class="w-16 h-16 rounded-lg mr-4 flex-shrink-0" mode="aspectFill" />
          <view class="flex-1 min-w-0">
            <view class="font-medium text-base mb-1">{{ reward.title }}</view>
            <view v-if="reward.status === 'UNUSED'" class="text-xs text-gray-400">
              有效期至:{{ formatDate(reward.expire_time) }}
            </view>
            <view v-if="reward.status === 'USED'" class="text-xs text-red-500">
              使用日期:{{ formatDate(reward.used_time) }}
            </view>
          </view>
          <view class="ml-4 flex flex-col items-end">
            <button
              @click="handleUseReward(reward)"
              :disabled="reward.status !== 'UNUSED'"
              :class="{
                'bg-blue-500 text-white': reward.status === 'UNUSED',
                'bg-gray-300 text-gray-500': reward.status !== 'UNUSED'
              }"
              class="px-4 py-2 rounded-lg text-sm font-medium transition-colors flex-shrink-0"
            >
              {{ getButtonText(reward.status) }}
            </button>
          </view>
        </view>
      </view>

      <!-- Empty State -->
      <view v-else class="text-center py-20">
        <view class="text-gray-400 text-lg mb-2">暂无券</view>
        <view class="text-gray-500 text-sm">您还没有任何券</view>
      </view>

      <!-- Load More -->
      <view v-if="hasMore && filteredRewards.length > 0" class="text-center mt-6">
        <view
          @click="loadMore"
          class="text-blue-500 py-4"
        >
          {{ loading ? '加载中...' : '加载更多' }}
        </view>
      </view>

      <!-- No More Data -->
      <view v-if="!hasMore && filteredRewards.length > 0" class="text-center py-4 text-gray-500">
        没有更多数据了
      </view>
    </view>
  </view>
</template>

<script setup>
import { ref, computed } from 'vue';
import Taro from '@tarojs/taro';
import { useDidShow } from '@tarojs/taro';
// 导入接口
import { getMyCouponListAPI } from '@/api/coupon';

const tabs = ref([
  { name: 'all', label: '全部', status: '' },
  { name: 'unused', label: '未使用', status: 'UNUSED' },
  { name: 'used', label: '已使用', status: 'USED' },
  { name: 'expired', label: '已过期', status: 'EXPIRED' },
]);

const activeTab = ref('all');
const loading = ref(false);
const rewards = ref([]);
const currentPage = ref(0);
const hasMore = ref(true);

const filteredRewards = computed(() => {
  // 由于API已经根据status参数进行了筛选,这里直接返回rewards
  return rewards.value;
});

/**
 * 获取按钮文本
 */
const getButtonText = (status) => {
  switch (status) {
    case 'UNUSED':
      return '使用';
    case 'USED':
      return '已使用';
    case 'EXPIRED':
      return '已过期';
    default:
      return '';
  }
};

/**
 * 获取状态文本
 */
// const getStatusText = (status) => {
//   switch (status) {
//     case 'UNUSED':
//       return '未使用';
//     case 'USED':
//       return '已使用';
//     case 'EXPIRED':
//       return '已过期';
//     default:
//       return '';
//   }
// };

/**
 * 格式化日期
 */
const formatDate = (dateString) => {
  if (!dateString) return '';
  const date = new Date(dateString);
  return date.toLocaleDateString('zh-CN');
};

/**
 * 处理优惠券使用
 */
const handleUseReward = (reward) => {
  if (reward.status === 'UNUSED') {
    // 跳转到卡券详情页
    Taro.navigateTo({
      url: '/pages/CouponDetail/index?id=' + reward.id
    });
  }
};

/**
 * 获取我的优惠券列表
 */
const fetchMyCouponList = async (reset = false) => {
  if (loading.value || (!hasMore.value && !reset)) return;

  loading.value = true;
  try {
    const currentTab = tabs.value.find(tab => tab.name === activeTab.value);
    const params = {
      status: currentTab?.status || '',
      page: reset ? 0 : currentPage.value,
      limit: 10
    };

    const response = await getMyCouponListAPI(params);

    if (response && response.data) {
      const coupons = Array.isArray(response.data) ? response.data : [];

      if (reset) {
        rewards.value = coupons;
        currentPage.value = 0;
      } else {
        rewards.value = [...rewards.value, ...coupons];
      }

      // 如果返回的数据少于limit,说明没有更多数据了
      hasMore.value = coupons.length >= 10;
      currentPage.value += 1;
    }
  } catch (error) {
    console.error('获取我的优惠券列表失败:', error);
    Taro.showToast({
      title: '获取列表失败',
      icon: 'error'
    });
  } finally {
    loading.value = false;
  }
};

/**
 * 处理标签页切换
 */
const handleTabChange = (tabName) => {
  if (activeTab.value === tabName) return;

  activeTab.value = tabName;
  currentPage.value = 0;
  hasMore.value = true;
  fetchMyCouponList(true); // 重置并重新加载数据
};

/**
 * 加载更多
 */
const loadMore = () => {
  fetchMyCouponList(false);
};

/**
 * 初始化页面数据
 */
const initPageData = () => {
  fetchMyCouponList(true);
};

// 页面显示时刷新数据
useDidShow(() => {
  initPageData();
});
</script>