feat: 优化

This commit is contained in:
2026-02-26 18:52:09 +08:00
parent c2e4fde218
commit b76e3ff47d
17 changed files with 1027 additions and 1630 deletions

View File

@@ -1,17 +1,29 @@
<script setup>
import { computed, onMounted } from 'vue'
import { computed, onMounted, ref, reactive } from 'vue'
import { useUserStore } from '@/stores/user'
import {
UserOutlined,
DatabaseOutlined,
WalletOutlined,
import { getPointRecordPage } from '@/api/pointRecord'
import {
UserOutlined,
DatabaseOutlined,
WalletOutlined,
PayCircleOutlined,
ClockCircleOutlined,
SafetyCertificateOutlined
SafetyCertificateOutlined,
PlusOutlined,
MinusOutlined
} from '@ant-design/icons-vue'
const userStore = useUserStore()
// 积分记录数据
const pointRecords = ref([])
const recordsLoading = ref(false)
const recordsPagination = reactive({
current: 1,
pageSize: 10,
total: 0
})
// 存储空间数据
const GB_TO_MB = 1024
const totalStorage = computed(() => userStore.totalStorage * GB_TO_MB)
@@ -54,6 +66,67 @@ function maskMobile(mobile) {
return mobile.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2')
}
// 获取积分记录
async function fetchPointRecords() {
recordsLoading.value = true
try {
const res = await getPointRecordPage({
pageNo: recordsPagination.current,
pageSize: recordsPagination.pageSize
})
if (res.data) {
pointRecords.value = res.data.list || []
recordsPagination.total = res.data.total || 0
}
} catch (e) {
console.error('获取积分记录失败:', e)
} finally {
recordsLoading.value = false
}
}
// 分页变化
function handleTableChange(pagination) {
recordsPagination.current = pagination.current
recordsPagination.pageSize = pagination.pageSize
fetchPointRecords()
}
// 格式化积分记录时间
function formatRecordTime(dateStr) {
if (!dateStr) return ''
const date = new Date(dateStr)
return date.toLocaleString('zh-CN', {
month: '2-digit',
day: '2-digit',
hour: '2-digit',
minute: '2-digit'
})
}
// 获取业务类型显示名称
function getBizTypeName(bizType) {
const typeMap = {
'signin': '签到',
'recharge': '充值',
'exchange': '兑换',
'admin': '后台调整',
'gift': '礼包赠送',
'digital_human': '数字人生成'
}
return typeMap[bizType] || bizType || '其他'
}
// 获取状态显示
function getStatusInfo(status) {
const statusMap = {
'pending': { text: '处理中', color: 'orange' },
'confirmed': { text: '已完成', color: 'green' },
'canceled': { text: '已取消', color: 'default' }
}
return statusMap[status] || { text: status, color: 'default' }
}
onMounted(async () => {
if (userStore.isLoggedIn) {
// 获取用户基本信息和档案信息
@@ -63,6 +136,8 @@ onMounted(async () => {
if (!userStore.profile) {
await userStore.fetchUserProfile()
}
// 获取积分记录
await fetchPointRecords()
}
})
</script>
@@ -160,20 +235,64 @@ onMounted(async () => {
</a-col>
</a-row>
<!-- 最近活动/设置占位 -->
<a-card title="最近活动" :bordered="false" class="activity-card mt-6">
<!-- 积分记录 -->
<a-card title="积分记录" :bordered="false" class="activity-card mt-6">
<template #extra>
<a href="#">查看全部</a>
<span class="record-count"> {{ recordsPagination.total }} 条记录</span>
</template>
<a-list item-layout="horizontal" :data-source="[]">
<template #renderItem="{ item }">
<!-- 这里是空列表暂时留白 -->
</template>
<div class="empty-state">
<ClockCircleOutlined class="empty-icon" />
<p>暂无最近活动记录</p>
</div>
</a-list>
<a-spin :spinning="recordsLoading">
<a-list
v-if="pointRecords.length > 0"
item-layout="horizontal"
:data-source="pointRecords"
class="point-record-list"
>
<template #renderItem="{ item }">
<a-list-item>
<a-list-item-meta>
<template #avatar>
<div :class="['record-icon', item.type === 'increase' ? 'increase' : 'decrease']">
<PlusOutlined v-if="item.type === 'increase'" />
<MinusOutlined v-else />
</div>
</template>
<template #title>
<div class="record-title">
<span class="record-reason">{{ item.reason || getBizTypeName(item.bizType) }}</span>
<a-tag :color="getStatusInfo(item.status).color" size="small">
{{ getStatusInfo(item.status).text }}
</a-tag>
</div>
</template>
<template #description>
<div class="record-desc">
<span>{{ formatRecordTime(item.createTime) }}</span>
<span v-if="item.bizType" class="record-biz-type">{{ getBizTypeName(item.bizType) }}</span>
</div>
</template>
</a-list-item-meta>
<div :class="['record-amount', item.type === 'increase' ? 'increase' : 'decrease']">
{{ item.type === 'increase' ? '+' : '-' }}{{ Math.abs(item.pointAmount) }}
</div>
</a-list-item>
</template>
</a-list>
<a-pagination
v-if="recordsPagination.total > recordsPagination.pageSize"
v-model:current="recordsPagination.current"
v-model:page-size="recordsPagination.pageSize"
:total="recordsPagination.total"
:show-size-changer="false"
:show-total="total => `${total}`"
size="small"
class="record-pagination"
@change="handleTableChange"
/>
<div v-if="pointRecords.length === 0 && !recordsLoading" class="empty-state">
<ClockCircleOutlined class="empty-icon" />
<p>暂无积分记录</p>
</div>
</a-spin>
</a-card>
</a-col>
@@ -382,4 +501,82 @@ onMounted(async () => {
color: #52c41a;
margin-right: 12px;
}
/* Point Record List */
.activity-card {
border-radius: 12px;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.03);
}
.record-count {
color: var(--color-text-secondary);
font-size: 13px;
}
.point-record-list {
max-height: 400px;
overflow-y: auto;
}
.record-icon {
width: 36px;
height: 36px;
border-radius: 50%;
display: flex;
align-items: center;
justify-content: center;
font-size: 16px;
}
.record-icon.increase {
background: rgba(82, 196, 26, 0.1);
color: #52c41a;
}
.record-icon.decrease {
background: rgba(255, 77, 79, 0.1);
color: #ff4d4f;
}
.record-title {
display: flex;
align-items: center;
gap: 8px;
}
.record-reason {
font-weight: 500;
color: var(--color-text);
}
.record-desc {
display: flex;
gap: 12px;
font-size: 12px;
color: var(--color-text-secondary);
}
.record-biz-type {
padding: 1px 6px;
background: rgba(0, 0, 0, 0.04);
border-radius: 4px;
}
.record-amount {
font-size: 18px;
font-weight: 600;
}
.record-amount.increase {
color: #52c41a;
}
.record-amount.decrease {
color: #ff4d4f;
}
.record-pagination {
margin-top: 16px;
text-align: center;
}
</style>