Files
medical-mall/pages/mall/consumer/points/index.uvue

224 lines
4.8 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<template>
<view class="points-page">
<view class="points-header">
<view class="points-info">
<text class="points-label">当前积分</text>
<text class="points-value">{{ totalPoints }}</text>
</view>
<view class="points-actions">
<button class="exchange-btn" @click="handleExchange">积分兑换</button>
</view>
</view>
<view class="records-section">
<text class="section-title">积分明细</text>
<view v-if="loading" class="loading-state">
<text>加载中...</text>
</view>
<view v-else-if="records.length === 0" class="empty-state">
<text class="empty-text">暂无积分记录</text>
</view>
<view v-else class="record-list">
<view v-for="item in records" :key="item.id" class="record-item">
<view class="record-left">
<text class="record-title">{{ item.description ?? getTypeText(item.type) }}</text>
<text class="record-time">{{ formatTime(item.created_at) }}</text>
</view>
<view class="record-right">
<text class="record-amount" :class="{ positive: item.points > 0, negative: item.points < 0 }">
{{ item.points > 0 ? '+' : '' }}{{ item.points }}
</text>
</view>
</view>
</view>
</view>
</view>
</template>
<script setup lang="uts">
import { ref, onMounted } from 'vue'
import { supabaseService } from '@/utils/supabaseService.uts'
type PointRecord = {
id: string
user_id: string
points: number
type: string
description: string
created_at: string
}
const totalPoints = ref<number>(0)
const records = ref<PointRecord[]>([])
const loading = ref<boolean>(true)
onMounted(() => {
loadData()
})
const loadData = async () => {
loading.value = true
await Promise.all([
loadPoints(),
loadRecords()
])
loading.value = false
}
const loadPoints = async () => {
// 调用 service 获取积分 (需要supabaseService支持)
// 暂时如果service没更新先用mock
// const res = await supabaseService.getUserPoints()
// if (res != null) totalPoints.value = res
try {
const points = await supabaseService.getUserPoints()
totalPoints.value = points
} catch (e) {
console.error('获取积分失败', e)
}
}
const loadRecords = async () => {
try {
const list = await supabaseService.getPointRecords()
records.value = list
} catch (e) {
console.error('获取积分记录失败', e)
}
}
const handleExchange = () => {
uni.showToast({
title: '积分商城开发中',
icon: 'none'
})
}
const getTypeText = (type: string): string => {
const map: Record<string, string> = {
'signin': '每日签到',
'shopping': '购物奖励',
'redeem': '积分兑换',
'admin': '系统调整',
'register': '注册赠送'
}
return map[type] ?? '积分变动'
}
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}`
}
</script>
<style>
.points-page {
flex: 1;
}
.points-header {
background-color: #ff5000;
padding: 30px 20px;
color: white;
display: flex;
justify-content: space-between;
align-items: center;
}
.points-info {
display: flex;
flex-direction: column;
}
.points-label {
font-size: 14px;
opacity: 0.9;
margin-bottom: 8px;
}
.points-value {
font-size: 36px;
font-weight: bold;
}
.exchange-btn {
background-color: rgba(255,255,255,0.2);
color: white;
border: 1px solid rgba(255,255,255,0.4);
font-size: 14px;
border-radius: 20px;
padding: 0 15px;
height: 32px;
line-height: 32px;
}
.records-section {
background-color: white;
margin-top: 10px;
padding: 0 16px;
min-height: 500px;
}
.section-title {
font-size: 16px;
font-weight: bold;
padding: 16px 0;
border-bottom: 1px solid #f0f0f0;
display: flex;
}
.record-item {
display: flex;
justify-content: space-between;
align-items: center;
padding: 16px 0;
border-bottom: 1px solid #f9f9f9;
}
.record-left {
display: flex;
flex-direction: column;
margin-bottom: 4px;
font-size: 15px;
color: #333;
}
.record-time {
font-size: 12px;
color: #999;
}
.record-amount {
font-size: 16px;
font-weight: bold;
color: #333;
}
.record-amount.positive {
color: #ff5000;
}
.record-amount.negative {
color: #333;
}
.empty-state {
padding: 40px 0;
display: flex;
justify-content: center;
}
.empty-text {
color: #999;
font-size: 14px;
}
</style>