index.vue 8.54 KB
<template>
    <view class="min-h-screen bg-white pb-24">
        <!-- Loading State -->
        <view v-if="loading" class="flex justify-center items-center h-screen">
            <view class="text-gray-500">加载中...</view>
        </view>

        <!-- Content -->
        <view v-else>
            <!-- Top Image -->
            <view class="w-full h-48">
                <image :src="reward.banner || 'https://placehold.co/800x400/e2f3ff/0369a1?text=优惠券&font=roboto'" class="w-full h-full object-cover" />
            </view>

            <!-- Main Content -->
            <view class="p-6">
                <!-- Points and Title -->
                <view class="text-center mb-8">
                    <view class="text-4xl font-bold text-blue-500 mb-2">
                        <text class="text-2xl">{{ reward.title }}</text>
                    </view>
                    <!-- Status Badge -->
                    <!-- <view class="mt-2">
                        <text :class="getStatusClass(reward.status)">{{ getStatusText(reward.status) }}</text>
                    </view> -->
                </view>

                <!-- Details Sections -->
                <view class="space-y-6">
                    <!-- Applicable Stores -->
                    <view v-if="reward.applicable_stores && reward.applicable_stores.length > 0">
                        <h2 class="text-lg font-medium mb-3">可用门店</h2>
                        <view class="space-y-2 text-gray-600">
                            <view v-for="store in reward.applicable_stores" :key="store" class="flex text-sm">
                                <span class="mr-2">·</span>
                                <p>{{ store }}</p>
                            </view>
                        </view>
                    </view>

                    <!-- Expiration Rules -->
                    <view v-if="reward.expiration_rules && reward.expiration_rules.length > 0">
                        <h2 class="text-lg font-medium mb-3">有效期</h2>
                        <view class="space-y-2 text-gray-600">
                            <view v-for="rule in reward.expiration_rules" :key="rule" class="flex text-sm">
                                <span class="mr-2">·</span>
                                <p>{{ rule }}</p>
                            </view>
                        </view>
                    </view>

                    <!-- Expire Time -->
                    <view v-if="reward.expire_time">
                        <h2 class="text-lg font-medium mb-3">到期时间</h2>
                        <view class="text-gray-600 text-sm">
                            <p>{{ reward.expire_time }}</p>
                        </view>
                    </view>

                    <!-- Usage Rules -->
                    <view v-if="reward.usage_rules && reward.usage_rules.length > 0">
                        <h2 class="text-lg font-medium mb-3">使用规则</h2>
                        <view class="space-y-2 text-gray-600">
                            <view v-for="rule in reward.usage_rules" :key="rule" class="flex text-sm">
                                <span class="mr-2">·</span>
                                <p>{{ rule }}</p>
                            </view>
                        </view>
                    </view>
                </view>
            </view>

            <!-- Bottom Button -->
            <view class="fixed bottom-0 left-0 right-0 p-4 bg-white border-t border-gray-100">
                <nut-button
                    type="primary"
                    size="large"
                    block
                    :color="reward.status === 'UNUSED' ? THEME_COLORS.PRIMARY : '#D1D5DB'"
                    :disabled="reward.status !== 'UNUSED' || useLoading"
                    :loading="useLoading"
                    @click="handleRedeem"
                >
                    {{ getButtonText(reward.status) }}
                </nut-button>
            </view>
        </view>
    </view>
</template>

<script setup>
import { ref, onMounted } from 'vue';
import Taro, { useLoad } from '@tarojs/taro';
// 导入主题颜色
import { THEME_COLORS } from '@/utils/config';
// 导入接口
import { getMyCouponDetailAPI, useCouponAPI } from '@/api/coupon';

// 页面参数
const couponId = ref('');
const loading = ref(false);
const useLoading = ref(false);

// 优惠券详情数据
const reward = ref({
    id: '',
    title: '',
    banner: '',
    status: 'UNUSED', // UNUSED=未使用, USED=已使用, EXPIRED=已过期
    expire_time: '',
    expiration_rules: [],
    applicable_stores: [],
    usage_rules: []
});

/**
 * 获取我的优惠券详情
 */
const fetchCouponDetail = async () => {
    if (!couponId.value) {
        console.error('缺少优惠券ID');
        return;
    }

    loading.value = true;
    try {
        const response = await getMyCouponDetailAPI({ id: couponId.value });

        if (response && response.data) {
            reward.value = {
                id: response.data.id || '',
                title: response.data.title || '',
                banner: response.data.banner || '',
                status: response.data.status || 'UNUSED',
                expire_time: response.data.expire_time || '',
                expiration_rules: response.data.expiration_rules || [],
                applicable_stores: response.data.applicable_stores || [],
                usage_rules: response.data.usage_rules || []
            };
        }
    } catch (error) {
        console.error('获取优惠券详情失败:', error);
        Taro.showToast({
            title: '获取详情失败',
            icon: 'error'
        });
    } finally {
        loading.value = false;
    }
};

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

/**
 * 获取状态样式类
 */
const getStatusClass = (status) => {
    switch (status) {
        case 'UNUSED':
            return 'px-2 py-1 bg-green-100 text-green-600 rounded text-sm';
        case 'USED':
            return 'px-2 py-1 bg-gray-100 text-gray-600 rounded text-sm';
        case 'EXPIRED':
            return 'px-2 py-1 bg-red-100 text-red-600 rounded text-sm';
        default:
            return 'px-2 py-1 bg-gray-100 text-gray-600 rounded text-sm';
    }
};

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

/**
 * 处理优惠券核销
 */
const handleRedeem = async () => {
    if (reward.value.status !== 'UNUSED') {
        Taro.showToast({
            title: '优惠券不可用',
            icon: 'none'
        });
        return;
    }

    try {
        // 显示确认弹窗
        const result = await Taro.showModal({
            title: '温馨提示',
            content: '将核销此优惠券,是否确认?',
            confirmText: '确认核销',
            cancelText: '取消'
        });

        if (result.confirm) {
            useLoading.value = true;

            // 调用核销API
            const response = await useCouponAPI({ id: couponId.value });

            if (response) {
                // 核销成功
                reward.value.status = 'USED';

                Taro.showToast({
                    title: '核销成功',
                    icon: 'success',
                    duration: 2000
                });

                // 延迟返回上一页
                setTimeout(() => {
                    Taro.navigateBack();
                }, 2000);
            }
        }
    } catch (error) {
        console.error('核销失败:', error);
        Taro.showToast({
            title: error.message || '核销失败,请重试',
            icon: 'error'
        });
    } finally {
        useLoading.value = false;
    }
};

/**
 * 初始化页面数据
 */
const initPageData = async (options = {}) => {
    // 获取URL参数中的优惠券ID
    if (options.id) {
        couponId.value = options.id;
        await fetchCouponDetail();
    } else {
        console.error('缺少优惠券ID参数');
        Taro.showToast({
            title: '参数错误',
            icon: 'error'
        });
    }
};

// 页面加载时初始化数据
useLoad((options) => {
    initPageData(options);
});
</script>