280 lines
6.6 KiB
Plaintext
280 lines
6.6 KiB
Plaintext
<template>
|
|
<scroll-view class="records-page" direction="vertical">
|
|
<view class="empty-state" v-if="!loading && records.length === 0">
|
|
<text class="empty-text">暂无兑换记录</text>
|
|
</view>
|
|
|
|
<view class="loading-state" v-if="loading">
|
|
<text class="loading-text">加载中...</text>
|
|
</view>
|
|
|
|
<view class="record-list" v-if="!loading && records.length > 0">
|
|
<view class="record-item" v-for="record in records" :key="record.id">
|
|
<view class="record-header">
|
|
<text class="record-product-name">{{ record.product_name }}</text>
|
|
<text class="record-status" :class="getStatusClass(record.status)">{{ getStatusText(record.status) }}</text>
|
|
</view>
|
|
|
|
<view class="record-info">
|
|
<view class="info-row">
|
|
<text class="info-label">消耗积分</text>
|
|
<text class="info-value">{{ record.points_used }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="info-label">兑换数量</text>
|
|
<text class="info-value">{{ record.quantity }}</text>
|
|
</view>
|
|
<view class="info-row">
|
|
<text class="info-label">兑换时间</text>
|
|
<text class="info-value">{{ formatTime(record.created_at) }}</text>
|
|
</view>
|
|
<view class="info-row" v-if="record.tracking_no">
|
|
<text class="info-label">物流单号</text>
|
|
<text class="info-value">{{ record.tracking_no }}</text>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</view>
|
|
</scroll-view>
|
|
</template>
|
|
|
|
<script setup lang="uts">
|
|
import { ref, onMounted } from 'vue'
|
|
import { supabaseService } from '@/utils/supabaseService.uts'
|
|
|
|
type ExchangeRecord = {
|
|
id: string
|
|
product_name: string
|
|
product_image: string | null
|
|
product_type: string
|
|
quantity: number
|
|
points_used: number
|
|
status: number
|
|
tracking_no: string | null
|
|
created_at: string
|
|
}
|
|
|
|
const records = ref<ExchangeRecord[]>([])
|
|
const loading = ref<boolean>(true)
|
|
|
|
const loadRecords = async (): Promise<void> => {
|
|
loading.value = true
|
|
try {
|
|
const result = await supabaseService.getExchangeRecords()
|
|
const parsed: ExchangeRecord[] = []
|
|
|
|
for (let i = 0; i < result.length; i++) {
|
|
const item = result[i]
|
|
const itemAny = item as any
|
|
|
|
// 处理数组返回
|
|
let recordData: any
|
|
if (Array.isArray(itemAny)) {
|
|
recordData = itemAny[0]
|
|
} else {
|
|
recordData = itemAny
|
|
}
|
|
|
|
let id = ''
|
|
let quantity = 1
|
|
let points_used = 0
|
|
let status = 0
|
|
let tracking_no: string | null = null
|
|
let created_at = ''
|
|
let product_name = ''
|
|
let product_image: string | null = null
|
|
let product_type = 'coupon'
|
|
|
|
// 转换为 UTSJSONObject
|
|
let recordObj: UTSJSONObject | null = null
|
|
if (recordData instanceof UTSJSONObject) {
|
|
recordObj = recordData
|
|
} else {
|
|
recordObj = JSON.parse(JSON.stringify(recordData)) as UTSJSONObject
|
|
}
|
|
|
|
id = recordObj.getString('id') ?? ''
|
|
quantity = recordObj.getNumber('quantity') ?? 1
|
|
points_used = recordObj.getNumber('points_used') ?? 0
|
|
status = recordObj.getNumber('status') ?? 0
|
|
tracking_no = recordObj.getString('tracking_no')
|
|
created_at = recordObj.getString('created_at') ?? ''
|
|
|
|
// 获取关联的商品信息
|
|
const product = recordObj.get('product')
|
|
if (product != null) {
|
|
let productObj: UTSJSONObject | null = null
|
|
if (product instanceof UTSJSONObject) {
|
|
productObj = product
|
|
} else {
|
|
productObj = JSON.parse(JSON.stringify(product)) as UTSJSONObject
|
|
}
|
|
product_name = productObj.getString('name') ?? ''
|
|
product_image = productObj.getString('image_url')
|
|
product_type = productObj.getString('product_type') ?? 'coupon'
|
|
}
|
|
|
|
parsed.push({
|
|
id,
|
|
product_name,
|
|
product_image,
|
|
product_type,
|
|
quantity,
|
|
points_used,
|
|
status,
|
|
tracking_no,
|
|
created_at
|
|
})
|
|
}
|
|
|
|
records.value = parsed
|
|
} catch (e) {
|
|
console.error('加载兑换记录失败:', e)
|
|
} finally {
|
|
loading.value = false
|
|
}
|
|
}
|
|
|
|
const getStatusText = (status: number): string => {
|
|
if (status === 0) return '待处理'
|
|
if (status === 1) return '已发货'
|
|
if (status === 2) return '已完成'
|
|
if (status === 3) return '已取消'
|
|
return '未知'
|
|
}
|
|
|
|
const getStatusClass = (status: number): string => {
|
|
if (status === 0) return 'status-pending'
|
|
if (status === 1) return 'status-shipped'
|
|
if (status === 2) return 'status-completed'
|
|
if (status === 3) return 'status-cancelled'
|
|
return ''
|
|
}
|
|
|
|
const formatTime = (timeStr: string): string => {
|
|
if (timeStr == '') return ''
|
|
const date = new Date(timeStr)
|
|
const y = date.getFullYear()
|
|
const m = (date.getMonth() + 1).toString().padStart(2, '0')
|
|
const d = date.getDate().toString().padStart(2, '0')
|
|
const hh = date.getHours().toString().padStart(2, '0')
|
|
const mm = date.getMinutes().toString().padStart(2, '0')
|
|
return `${y}-${m}-${d} ${hh}:${mm}`
|
|
}
|
|
|
|
onMounted(() => {
|
|
loadRecords()
|
|
})
|
|
</script>
|
|
|
|
<style>
|
|
.records-page {
|
|
flex: 1;
|
|
height: 100%;
|
|
background-color: #f5f5f5;
|
|
padding: 12px;
|
|
}
|
|
|
|
.empty-state {
|
|
padding: 60px 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.empty-text {
|
|
font-size: 14px;
|
|
color: #999;
|
|
}
|
|
|
|
.loading-state {
|
|
padding: 60px 0;
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
}
|
|
|
|
.loading-text {
|
|
font-size: 14px;
|
|
color: #999;
|
|
}
|
|
|
|
.record-list {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.record-item {
|
|
background-color: white;
|
|
border-radius: 8px;
|
|
padding: 12px;
|
|
margin-bottom: 8px;
|
|
}
|
|
|
|
.record-header {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
margin-bottom: 12px;
|
|
padding-bottom: 8px;
|
|
border-bottom: 1px solid #f0f0f0;
|
|
}
|
|
|
|
.record-product-name {
|
|
font-size: 16px;
|
|
font-weight: bold;
|
|
color: #333;
|
|
flex: 1;
|
|
}
|
|
|
|
.record-status {
|
|
font-size: 12px;
|
|
padding: 4px 8px;
|
|
border-radius: 4px;
|
|
}
|
|
|
|
.status-pending {
|
|
background-color: #fff7e6;
|
|
color: #d48806;
|
|
}
|
|
|
|
.status-shipped {
|
|
background-color: #e6f7ff;
|
|
color: #1890ff;
|
|
}
|
|
|
|
.status-completed {
|
|
background-color: #f6ffed;
|
|
color: #52c41a;
|
|
}
|
|
|
|
.status-cancelled {
|
|
background-color: #f5f5f5;
|
|
color: #999;
|
|
}
|
|
|
|
.record-info {
|
|
display: flex;
|
|
flex-direction: column;
|
|
}
|
|
|
|
.info-row {
|
|
display: flex;
|
|
flex-direction: row;
|
|
justify-content: space-between;
|
|
align-items: center;
|
|
padding: 6px 0;
|
|
}
|
|
|
|
.info-label {
|
|
font-size: 14px;
|
|
color: #999;
|
|
}
|
|
|
|
.info-value {
|
|
font-size: 14px;
|
|
color: #333;
|
|
}
|
|
</style>
|