feat: 个人中心新增尊享服务、模型列表区分

This commit is contained in:
Gsh
2025-10-12 18:30:34 +08:00
parent 5934056fe6
commit 85bd1ce8d6
6 changed files with 579 additions and 126 deletions

View File

@@ -0,0 +1,457 @@
<script lang="ts" setup>
import { Clock, Coin, TrophyBase, WarningFilled } from '@element-plus/icons-vue';
import { getPremiumTokenPackage } from '@/api/user';
// 尊享服务数据
const loading = ref(false);
const packageData = ref<any>({
totalQuota: 0, // 购买总额度
usedQuota: 0, // 已使用额度
remainingQuota: 0, // 剩余额度
usagePercentage: 0, // 使用百分比
packageName: 'Token包', // 套餐名称
expireDate: '', // 过期时间
});
// 计算属性
const usagePercent = computed(() => {
if (packageData.value.totalQuota === 0)
return 0;
return Math.round((packageData.value.usedQuota / packageData.value.totalQuota) * 100);
});
const remainingPercent = computed(() => {
return 100 - usagePercent.value;
});
// 获取进度条颜色
const progressColor = computed(() => {
const percent = usagePercent.value;
if (percent >= 90)
return '#f56c6c'; // 红色
if (percent >= 70)
return '#e6a23c'; // 橙色
return '#67c23a'; // 绿色
});
// 格式化数字
function formatNumber(num: number): string {
return num.toLocaleString();
}
// 获取尊享服务Token包数据
async function fetchPremiumTokenPackage() {
loading.value = true;
try {
const res = await getPremiumTokenPackage();
if (res.success && res.data) {
packageData.value = {
totalQuota: res.data.totalQuota || 0,
usedQuota: res.data.usedQuota || 0,
remainingQuota: res.data.remainingQuota || 0,
usagePercentage: res.data.usagePercentage || 0,
packageName: res.data.packageName || 'Token包',
expireDate: res.data.expireDate || '',
};
// 计算剩余额度(如果接口没返回)
if (!packageData.value.remainingQuota) {
packageData.value.remainingQuota = packageData.value.totalQuota - packageData.value.usedQuota;
}
}
else {
ElMessage.warning('暂无尊享服务数据');
}
}
catch (error) {
console.error('获取尊享服务数据失败:', error);
ElMessage.error('获取尊享服务数据失败');
}
finally {
loading.value = false;
}
}
// 刷新数据
function refreshData() {
fetchPremiumTokenPackage();
}
onMounted(() => {
fetchPremiumTokenPackage();
});
</script>
<template>
<div class="premium-service" v-loading="loading">
<div class="header">
<h2>
<el-icon><TrophyBase /></el-icon>
尊享服务
</h2>
<el-button
type="primary"
size="small"
@click="refreshData"
>
刷新数据
</el-button>
</div>
<!-- 套餐信息卡片 -->
<el-card class="package-card" shadow="hover">
<template #header>
<div class="card-header">
<el-icon class="header-icon"><Coin /></el-icon>
<span class="header-title">{{ packageData.packageName }}</span>
</div>
</template>
<div class="package-content">
<!-- 统计数据 -->
<div class="stats-grid">
<div class="stat-item total">
<div class="stat-label">购买总额度</div>
<div class="stat-value">{{ formatNumber(packageData.totalQuota) }}</div>
<div class="stat-unit">Tokens</div>
</div>
<div class="stat-item used">
<div class="stat-label">已用额度</div>
<div class="stat-value">{{ formatNumber(packageData.usedQuota) }}</div>
<div class="stat-unit">Tokens</div>
</div>
<div class="stat-item remaining">
<div class="stat-label">剩余额度</div>
<div class="stat-value">{{ formatNumber(packageData.remainingQuota) }}</div>
<div class="stat-unit">Tokens</div>
</div>
</div>
<!-- 进度条 -->
<div class="progress-section">
<div class="progress-header">
<span class="progress-label">使用进度</span>
<span class="progress-percent" :style="{ color: progressColor }">
{{ usagePercent }}%
</span>
</div>
<el-progress
:percentage="usagePercent"
:color="progressColor"
:stroke-width="20"
:show-text="false"
/>
<div class="progress-legend">
<div class="legend-item">
<span class="legend-dot used-dot"></span>
<span class="legend-text">已使用: {{ usagePercent }}%</span>
</div>
<div class="legend-item">
<span class="legend-dot remaining-dot"></span>
<span class="legend-text">剩余: {{ remainingPercent }}%</span>
</div>
</div>
</div>
<!-- 过期时间 -->
<div v-if="packageData.expireDate" class="expire-info">
<el-icon><Clock /></el-icon>
<span>有效期至: {{ packageData.expireDate }}</span>
</div>
<!-- 温馨提示 -->
<el-alert
class="tips-alert"
type="info"
:closable="false"
show-icon
>
<template #title>
<div class="tips-content">
<p>温馨提示</p>
<ul>
<li>Token额度根据不同模型消耗速率不同</li>
<li>建议合理使用避免额度过快消耗</li>
<li>额度不足时请及时充值避免影响使用</li>
</ul>
</div>
</template>
</el-alert>
</div>
</el-card>
<!-- 购买提示卡片额度不足时显示 -->
<el-card
v-if="remainingPercent < 20"
class="warning-card"
shadow="hover"
>
<div class="warning-content">
<el-icon class="warning-icon" color="#e6a23c"><WarningFilled /></el-icon>
<div class="warning-text">
<h3>额度即将用完</h3>
<p>您的Token额度已使用{{ usagePercent }}%剩余额度较少建议及时充值</p>
</div>
<el-button type="warning" @click="$router.push('/products')">
立即充值
</el-button>
</div>
</el-card>
</div>
</template>
<style scoped>
.premium-service {
padding: 20px;
position: relative;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.header h2 {
display: flex;
align-items: center;
margin: 0;
font-size: 20px;
color: #333;
}
.header .el-icon {
margin-right: 8px;
color: #f59e0b;
}
/* 套餐卡片 */
.package-card {
margin-bottom: 20px;
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
.card-header {
display: flex;
align-items: center;
gap: 8px;
font-size: 18px;
font-weight: 600;
color: #333;
}
.header-icon {
font-size: 20px;
color: #f59e0b;
}
.package-content {
display: flex;
flex-direction: column;
gap: 24px;
}
/* 统计数据网格 */
.stats-grid {
display: grid;
grid-template-columns: repeat(3, 1fr);
gap: 16px;
}
.stat-item {
padding: 20px;
border-radius: 8px;
text-align: center;
transition: transform 0.2s;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
color: white;
}
.stat-item:hover {
transform: translateY(-4px);
}
.stat-item.total {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
}
.stat-item.used {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
}
.stat-item.remaining {
background: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
}
.stat-label {
font-size: 14px;
opacity: 0.9;
margin-bottom: 8px;
}
.stat-value {
font-size: 28px;
font-weight: 700;
margin-bottom: 4px;
}
.stat-unit {
font-size: 12px;
opacity: 0.8;
}
/* 进度条部分 */
.progress-section {
padding: 20px;
background: #f7f8fa;
border-radius: 8px;
}
.progress-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 12px;
}
.progress-label {
font-size: 16px;
font-weight: 600;
color: #333;
}
.progress-percent {
font-size: 20px;
font-weight: 700;
}
.progress-legend {
display: flex;
justify-content: center;
gap: 24px;
margin-top: 12px;
}
.legend-item {
display: flex;
align-items: center;
gap: 6px;
}
.legend-dot {
width: 12px;
height: 12px;
border-radius: 50%;
}
.used-dot {
background: #409eff;
}
.remaining-dot {
background: #e4e7ed;
}
.legend-text {
font-size: 14px;
color: #606266;
}
/* 过期信息 */
.expire-info {
display: flex;
align-items: center;
gap: 8px;
padding: 12px 16px;
background: #f0f9ff;
border-radius: 6px;
color: #0369a1;
font-size: 14px;
}
/* 温馨提示 */
.tips-alert {
border-radius: 8px;
}
.tips-content p {
margin: 0 0 8px 0;
font-weight: 600;
}
.tips-content ul {
margin: 0;
padding-left: 20px;
}
.tips-content li {
margin: 4px 0;
font-size: 13px;
}
/* 警告卡片 */
.warning-card {
border-radius: 12px;
border: 2px solid #e6a23c;
background: #fef3e9;
}
.warning-content {
display: flex;
align-items: center;
gap: 16px;
}
.warning-icon {
font-size: 40px;
flex-shrink: 0;
}
.warning-text {
flex: 1;
}
.warning-text h3 {
margin: 0 0 8px 0;
color: #e6a23c;
font-size: 18px;
}
.warning-text p {
margin: 0;
color: #606266;
font-size: 14px;
}
/* 响应式布局 */
@media (max-width: 768px) {
.premium-service {
padding: 10px;
}
.stats-grid {
grid-template-columns: 1fr;
gap: 12px;
}
.stat-value {
font-size: 24px;
}
.progress-legend {
flex-direction: column;
gap: 8px;
}
.warning-content {
flex-direction: column;
text-align: center;
}
}
</style>