feat: 优化
This commit is contained in:
@@ -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>
|
||||
|
||||
Reference in New Issue
Block a user