feat: 个人中心优化

This commit is contained in:
Gsh
2025-10-12 21:08:09 +08:00
parent d32906702a
commit 6afd0cb955
5 changed files with 570 additions and 208 deletions

View File

@@ -315,9 +315,10 @@ onMounted(async () => {
<style scoped>
.api-key-management {
padding: 20px;
max-width: 600px;
padding:5px 20px;
max-width: 800px;
margin: 0 auto;
min-height: 200px;
}
/* 未领取状态样式 */
@@ -389,20 +390,37 @@ onMounted(async () => {
/* 已领取状态样式 */
.claimed-state {
margin: 30px 0;
padding: 30px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
border-radius: 16px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
}
.key-title {
text-align: center;
color: #333;
margin-bottom: 20px;
margin-bottom: 30px;
font-size: 22px;
font-weight: 600;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.key-display {
margin: 20px 0;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.key-input {
font-family: monospace;
font-family: 'Courier New', monospace;
font-size: 14px;
}
.key-input :deep(.el-input__inner) {
font-weight: 600;
letter-spacing: 1px;
}
/* 添加按钮间距 */
@@ -414,71 +432,89 @@ onMounted(async () => {
.key-input :deep(.el-input-group__append .el-button + .el-button) {
margin-left: 4px;
}
.key-actions {
text-align: center;
margin-top: 30px;
padding: 20px;
background: white;
border-radius: 12px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
.key-hint {
color: #999;
font-size: 14px;
margin-top: 10px;
margin-top: 12px;
font-style: italic;
}
/* 使用说明样式 */
.usage-guide {
margin-top: 40px;
margin-top: 10px;
padding: 10px 20px;
background: white;
border-radius: 16px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.08);
}
.guide-content {
background: #f8f9fa;
padding: 15px;
border-radius: 4px;
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
padding: 20px;
border-radius: 8px;
line-height: 1.8;
border-left: 4px solid #409eff;
}
/* 成功弹窗样式 */
.success-dialog {
text-align: center;
padding: 20px 0;
padding: 30px 0;
}
.success-message {
font-size: 18px;
font-size: 20px;
font-weight: 600;
color: #333;
margin: 15px 0 5px;
margin: 20px 0 10px;
}
.success-tip {
color: #999;
font-size: 14px;
color: #666;
font-size: 15px;
margin-top: 8px;
}
/* 未领取状态样式 */
.unclaimed-state {
text-align: center;
margin: 30px 0;
margin: 40px 0;
padding: 40px;
perspective: 600px;
background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
border-radius: 20px;
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.12);
}
.gift-container {
position: relative;
width: 150px;
height: 150px;
margin: 0 auto;
width: 180px;
height: 180px;
margin: 0 auto 30px;
cursor: pointer;
filter: drop-shadow(0 10px 20px rgba(0, 0, 0, 0.15));
}
.gift-box {
position: relative;
width: 100%;
height: 100%;
transition: all 0.3s;
transition: all 0.4s cubic-bezier(0.68, -0.55, 0.265, 1.55);
transform-style: preserve-3d;
}
.gift-box:hover:not(.opening) {
transform: translateY(-5px);
transform: translateY(-10px) scale(1.05);
}
.gift-box.opening .gift-lid {
@@ -592,16 +628,23 @@ onMounted(async () => {
.claim-text {
margin-top: 30px;
padding: 20px;
background: rgba(255, 255, 255, 0.9);
border-radius: 12px;
backdrop-filter: blur(10px);
}
.claim-text h3 {
color: #e74c3c;
margin-bottom: 10px;
font-size: 18px;
margin-bottom: 15px;
font-size: 20px;
font-weight: 600;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}
.claim-text p {
color: #666;
font-size: 14px;
color: #555;
font-size: 15px;
font-weight: 500;
}
</style>

View File

@@ -38,6 +38,23 @@ const progressColor = computed(() => {
function formatNumber(num: number): string {
return num.toLocaleString();
}
/*
前端已准备好后端需要提供以下API
接口地址: GET /account/premium/token-package
返回数据格式:
{
"success": true,
"data": {
"totalQuota": 1000000, // 购买总额度
"usedQuota": 350000, // 已使用额度
"remainingQuota": 650000, // 剩余额度(可选,前端会自动计算)
"usagePercentage": 35, // 使用百分比(可选)
"packageName": "尊享VIP套餐", // 套餐名称(可选)
"expireDate": "2024-12-31" // 过期时间(可选)
}
} */
// 获取尊享服务Token包数据
async function fetchPremiumTokenPackage() {
@@ -83,7 +100,7 @@ onMounted(() => {
</script>
<template>
<div class="premium-service" v-loading="loading">
<div v-loading="loading" class="premium-service">
<div class="header">
<h2>
<el-icon><TrophyBase /></el-icon>
@@ -102,7 +119,9 @@ onMounted(() => {
<el-card class="package-card" shadow="hover">
<template #header>
<div class="card-header">
<el-icon class="header-icon"><Coin /></el-icon>
<el-icon class="header-icon">
<Coin />
</el-icon>
<span class="header-title">{{ packageData.packageName }}</span>
</div>
</template>
@@ -111,21 +130,39 @@ onMounted(() => {
<!-- 统计数据 -->
<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 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 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 class="stat-label">
剩余额度
</div>
<div class="stat-value">
{{ formatNumber(packageData.remainingQuota) }}
</div>
<div class="stat-unit">
Tokens
</div>
</div>
</div>
@@ -147,11 +184,11 @@ onMounted(() => {
<div class="progress-legend">
<div class="legend-item">
<span class="legend-dot used-dot"></span>
<span class="legend-dot used-dot" />
<span class="legend-text">已使用: {{ usagePercent }}%</span>
</div>
<div class="legend-item">
<span class="legend-dot remaining-dot"></span>
<span class="legend-dot remaining-dot" />
<span class="legend-text">剩余: {{ remainingPercent }}%</span>
</div>
</div>
@@ -191,7 +228,9 @@ onMounted(() => {
shadow="hover"
>
<div class="warning-content">
<el-icon class="warning-icon" color="#e6a23c"><WarningFilled /></el-icon>
<el-icon class="warning-icon" color="#e6a23c">
<WarningFilled />
</el-icon>
<div class="warning-text">
<h3>额度即将用完</h3>
<p>您的Token额度已使用{{ usagePercent }}%剩余额度较少建议及时充值</p>

View File

@@ -155,8 +155,8 @@ onMounted(() => {
append-to-body
>
<h3 class="text-lg font-bold mb-3">
请扫码加入微信交流群<br>
备注ai获取专属客服支持
请扫码加入微信交流群<br>
备注ai获取专属客服支持
</h3>
<div class="mb-4 flex items-center justify-center space-x-2">
<span class="font-semibold">站长微信账号</span>
@@ -334,59 +334,94 @@ onMounted(() => {
.fullscreen-image-overlay {
position: fixed;
inset: 0;
background: rgba(0, 0, 0, 0.8);
background: rgba(0, 0, 0, 0.85);
backdrop-filter: blur(8px);
z-index: 9999;
display: flex;
justify-content: center;
align-items: center;
cursor: pointer;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fullscreen-image {
max-width: 90%;
max-height: 90%;
border: 8px solid white;
border-radius: 16px;
box-shadow: 0 0 40px rgba(255, 255, 255, 0.2);
border-radius: 20px;
box-shadow: 0 0 60px rgba(255, 255, 255, 0.3);
animation: zoomIn 0.3s ease;
}
@keyframes zoomIn {
from {
transform: scale(0.8);
opacity: 0;
}
to {
transform: scale(1);
opacity: 1;
}
}
.recharge-log-container {
padding: 20px;
background: #fff;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
padding: 30px;
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
}
.recharge-log-container:hover {
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.12);
}
.log-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
padding-bottom: 15px;
border-bottom: 1px solid #f0f0f0;
margin-bottom: 25px;
padding-bottom: 20px;
border-bottom: 2px solid #e9ecef;
}
.log-title {
display: flex;
align-items: center;
margin: 0;
font-size: 18px;
font-size: 22px;
font-weight: 600;
color: #333;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.log-title .el-icon {
margin-right: 8px;
margin-right: 10px;
color: #409eff;
font-size: 24px;
}
.header-actions {
display: flex;
align-items: center;
gap: 10px;
}
.amount-cell {
font-family: 'Arial', sans-serif;
font-weight: bold;
font-weight: 700;
font-size: 15px;
color: #e74c3c;
text-shadow: 0 1px 2px rgba(231, 76, 60, 0.2);
}
.ellipsis-text {
@@ -402,38 +437,63 @@ onMounted(() => {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 20px;
padding-top: 15px;
border-top: 1px solid #f0f0f0;
margin-top: 25px;
padding-top: 20px;
border-top: 2px solid #e9ecef;
}
.summary {
color: #666;
font-size: 14px;
font-size: 15px;
font-weight: 500;
}
.highlight {
color: #409eff;
font-weight: bold;
font-weight: 700;
font-size: 18px;
padding: 0 6px;
}
/* 表格样式优化 */
:deep(.el-table) {
font-size: 14px;
border-radius: 12px;
overflow: hidden;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.05);
}
:deep(.el-table th) {
background-color: #f8fafc;
color: #333;
//background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
//color: white;
font-weight: 600;
font-size: 14px;
padding: 8px 0;
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.1);
}
:deep(.el-table th .cell) {
//color: white;
}
:deep(.el-table--striped .el-table__body tr.el-table__row--striped td) {
background-color: #fafafa;
background-color: #f8f9fb;
}
:deep(.el-table .cell) {
padding: 8px 12px;
padding: 12px 16px;
}
:deep(.el-table tbody tr) {
transition: all 0.3s ease;
}
:deep(.el-table tbody tr:hover) {
background: linear-gradient(90deg, #f0f7ff 0%, #e6f4ff 100%) !important;
transform: scale(1.01);
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.08);
}
/* 分页样式优化 */

View File

@@ -362,8 +362,8 @@ onBeforeUnmount(() => {
<el-card v-loading="loading" class="chart-card">
<template #header>
<div class="card-header">
<span>近七天每日Token消耗量</span>
<el-tag type="primary">
<span class="card-title">📊 近七天每日Token消耗量</span>
<el-tag type="primary" size="large" effect="dark">
近七日总计: {{ totalTokens }} tokens
</el-tag>
</div>
@@ -376,7 +376,7 @@ onBeforeUnmount(() => {
<el-card v-loading="loading" class="chart-card">
<template #header>
<div class="card-header">
<span>各模型Token消耗占比</span>
<span class="card-title">🥧 各模型Token消耗占比</span>
</div>
</template>
<div class="chart-container">
@@ -387,7 +387,7 @@ onBeforeUnmount(() => {
<el-card v-loading="loading" class="chart-card">
<template #header>
<div class="card-header">
<span>各模型总Token消耗量</span>
<span class="card-title">📈 各模型总Token消耗量</span>
</div>
</template>
<div class="chart-container">
@@ -399,9 +399,17 @@ onBeforeUnmount(() => {
<style scoped>
.usage-statistics {
padding: 20px;
padding: 30px;
position: relative;
background: linear-gradient(135deg, #fff 0%, #f8f9fa 100%);
border-radius: 16px;
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
transition: all 0.3s ease;
min-height: 100vh;
}
.usage-statistics:hover {
box-shadow: 0 6px 30px rgba(0, 0, 0, 0.12);
}
.usage-statistics.fullscreen-mode {
@@ -411,60 +419,100 @@ onBeforeUnmount(() => {
right: 0;
bottom: 0;
z-index: 2000;
background: #fff;
padding: 20px;
background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%);
padding: 30px;
overflow-y: auto;
border-radius: 0;
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
margin-bottom: 30px;
padding-bottom: 20px;
border-bottom: 2px solid #e9ecef;
}
.header h2 {
display: flex;
align-items: center;
margin: 0;
font-size: 20px;
font-size: 24px;
font-weight: 600;
color: #333;
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.05);
}
.header .el-icon {
margin-right: 8px;
margin-right: 10px;
color: #3a4de9;
font-size: 28px;
}
.chart-card {
margin-bottom: 20px;
border-radius: 8px;
box-shadow: 0 1px 4px rgba(0, 0, 0, 0.08);
margin-bottom: 30px;
border-radius: 16px;
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.1);
transition: all 0.3s ease;
overflow: hidden;
background: white;
}
.chart-card:hover {
box-shadow: 0 6px 24px rgba(0, 0, 0, 0.15);
transform: translateY(-4px);
}
.card-header {
display: flex;
justify-content: space-between;
align-items: center;
font-size: 16px;
font-weight: 600;
color: #333;
padding: 8px 0;
}
.card-title {
font-size: 18px;
font-weight: 700;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.chart-container {
width: 100%;
padding: 10px;
background: linear-gradient(135deg, #fafbfc 0%, #f5f6f8 100%);
border-radius: 12px;
}
.chart {
width: 100%;
transition: all 0.3s ease;
}
@media (max-width: 768px) {
.usage-statistics {
padding: 15px;
}
.header {
flex-direction: column;
align-items: flex-start;
gap: 10px;
gap: 12px;
margin-bottom: 20px;
}
.header h2 {
font-size: 20px;
}
.chart-card {
margin-bottom: 15px;
margin-bottom: 20px;
}
.chart {
@@ -472,7 +520,11 @@ onBeforeUnmount(() => {
}
.usage-statistics.fullscreen-mode {
padding: 10px;
padding: 15px;
}
.card-header {
font-size: 14px;
}
}
</style>

View File

@@ -1,11 +1,11 @@
<script lang="ts" setup>
import { Camera, Edit, SuccessFilled } from '@element-plus/icons-vue';
import { Camera, Edit, Postcard, Promotion, SuccessFilled, User } from '@element-plus/icons-vue';
import { format } from 'date-fns';
import { computed, onMounted, ref } from 'vue';
import { getUserInfo } from '@/api';
import QrCodeLogin from '@/components/LoginDialog/components/QrCodeLogin/index.vue';
import { useUserStore } from '@/stores';
import { getUserProfilePicture, WECHAT_QRCODE_TYPE } from '@/utils/user.ts';
import { getUserProfilePicture, isUserVip, WECHAT_QRCODE_TYPE } from '@/utils/user.ts';
const userStore = useUserStore();
@@ -25,11 +25,17 @@ const userIcon = computed(() => {
const userNick = computed(() => {
return user.value.nick || user.value.userName || '未知用户';
});
// 是否绑定了微信
const isWechatBound = computed(() => {
return userStore.userInfo.isBindFuwuhao || false;
});
// 用户VIP状态
const userVipStatus = computed(() => {
return isUserVip();
});
// 格式化日期
function formatDate(dateString: string | null) {
if (!dateString)
@@ -93,125 +99,192 @@ function handleWechatBind() {
// 微信绑定成功
function bindWechat() {
wechatDialogVisible.value = false;
ElMessage.success('微信绑定成功!');
}
</script>
<template>
<div class="user-profile">
<el-card class="profile-card">
<template #header>
<div class="card-header">
<h3>个人信息</h3>
<el-button v-if="false" type="primary" size="small" @click="handleEdit">
<el-icon><Edit /></el-icon>
编辑信息
</el-button>
</div>
</template>
<!-- 顶部标题 -->
<div class="header">
<h2>
<el-icon><User /></el-icon>
个人信息
</h2>
</div>
<div class="profile-content">
<!-- 用户卡片 -->
<el-card class="profile-card" shadow="hover">
<!-- 头像和基本信息区域 -->
<div class="user-header-section">
<!-- 头像区域 -->
<div class="avatar-section">
<el-avatar :size="100" :src="userIcon" class="user-avatar">
{{ userNick.charAt(0) }}
</el-avatar>
<div class="avatar-wrapper">
<el-avatar :size="120" :src="userIcon" class="user-avatar">
{{ userNick.charAt(0) }}
</el-avatar>
<div v-if="userVipStatus" class="vip-badge">
<el-icon><Promotion /></el-icon>
VIP
</div>
</div>
<div v-if="false" class="avatar-actions">
<el-button size="small" @click="changeAvatar">
<el-button size="small" type="primary" @click="changeAvatar">
<el-icon><Camera /></el-icon>
更换头像
</el-button>
</div>
</div>
<!-- 基本信息 -->
<div class="info-section">
<el-descriptions :column="1" border>
<el-descriptions-item label="用户名">
{{ user.userName || '-' }}
</el-descriptions-item>
<!-- 用户名称和状态 -->
<div class="user-info-quick">
<h3 class="user-name">{{ userNick }}</h3>
<div class="user-tags">
<el-tag v-if="userVipStatus" type="warning" effect="dark" size="large">
<el-icon><Promotion /></el-icon>
尊享VIP会员
</el-tag>
<el-tag v-else type="info" size="large">
普通用户
</el-tag>
<el-tag :type="getSexTagType(user.sex)" size="large">
{{ getSexText(user.sex) }}
</el-tag>
</div>
<div class="user-stats">
<div class="stat-item">
<div class="stat-value">{{ formatDate(user.creationTime)?.split(' ')[0] || '-' }}</div>
<div class="stat-label">注册时间</div>
</div>
</div>
</div>
</div>
<el-descriptions-item label="昵称">
{{ userNick }}
</el-descriptions-item>
<el-divider />
<el-descriptions-item label="性别">
<el-tag :type="getSexTagType(user.sex)">
{{ getSexText(user.sex) }}
</el-tag>
</el-descriptions-item>
<!-- 详细信息区域 -->
<div class="info-section">
<div class="info-grid">
<!-- 用户名 -->
<div class="info-item">
<div class="info-label">
<el-icon><User /></el-icon>
用户名
</div>
<div class="info-value">{{ user.userName || '-' }}</div>
</div>
<el-descriptions-item label="注册时间">
{{ formatDate(user.creationTime) }}
</el-descriptions-item>
<!-- 昵称 -->
<div class="info-item">
<div class="info-label">
<el-icon><Postcard /></el-icon>
昵称
</div>
<div class="info-value">{{ userNick }}</div>
</div>
<el-descriptions-item label="邮箱">
<!-- 邮箱 -->
<div class="info-item">
<div class="info-label">
<el-icon><Message /></el-icon>
邮箱
</div>
<div class="info-value">
<span v-if="user.email">
{{ maskEmail(user.email) }}
<el-tooltip content="已验证" placement="top">
<el-icon color="#67C23A"><SuccessFilled /></el-icon>
<el-icon color="#67C23A" style="margin-left: 5px;"><SuccessFilled /></el-icon>
</el-tooltip>
</span>
<span v-else class="unset-text">未设置</span>
</el-descriptions-item>
</div>
</div>
<el-descriptions-item label="手机号">
<span v-if="user.phone">
{{ maskPhone(user.phone) }}
</span>
<!-- 手机号 -->
<div class="info-item">
<div class="info-label">
<el-icon><Phone /></el-icon>
手机号
</div>
<div class="info-value">
<span v-if="user.phone">{{ maskPhone(user.phone) }}</span>
<span v-else class="unset-text">未设置</span>
</el-descriptions-item>
</div>
</div>
<el-descriptions-item label="微信绑定">
<div class="wechat-binding">
<span v-if="isWechatBound">
<el-icon color="#07C160"><SuccessFilled /></el-icon>
绑定
<!-- <span class="wechat-id">({{ maskWechat(wechatInfo) }})</span> -->
</span>
<span v-else class="unset-text">
未绑定
</span>
<el-button
v-if="!isWechatBound"
class="bind-btn"
type="primary"
@click="handleWechatBind"
>
绑定
</el-button>
</div>
</el-descriptions-item>
<el-descriptions-item label="个人简介">
<span v-if="user.introduction">
{{ user.introduction }}
<!-- 微信绑定 -->
<div class="info-item full-width">
<div class="info-label">
<el-icon color="#07C160"><ChatDotRound /></el-icon>
微信绑定
</div>
<div class="info-value wechat-binding">
<span v-if="isWechatBound" class="wechat-status">
<el-icon color="#07C160"><SuccessFilled /></el-icon>
已绑定
</span>
<span v-else class="wechat-status unset-text">
未绑定
</span>
<el-button
v-if="!isWechatBound"
type="success"
size="small"
@click="handleWechatBind"
>
立即绑定
</el-button>
</div>
</div>
<!-- 个人简介 -->
<div class="info-item full-width">
<div class="info-label">
<el-icon><Document /></el-icon>
个人简介
</div>
<div class="info-value">
<span v-if="user.introduction">{{ user.introduction }}</span>
<span v-else class="unset-text">暂无简介</span>
</el-descriptions-item>
</el-descriptions>
</div>
</div>
</div>
</div>
<!-- 操作按钮预留 -->
<div v-if="false" class="action-section">
<el-button type="primary" @click="handleEdit">
<el-icon><Edit /></el-icon>
编辑资料
</el-button>
</div>
</el-card>
<!-- 微信绑定对话框 -->
<el-dialog
v-model="wechatDialogVisible"
title="微信绑定"
width="400px"
width="450px"
:close-on-click-modal="false"
>
<div class="wechat-dialog">
<div class="wechat-tip">
<el-alert
type="info"
:closable="false"
show-icon
>
<template #title>
<div>请使用微信扫描下方二维码完成绑定</div>
</template>
</el-alert>
</div>
<QrCodeLogin :type="WECHAT_QRCODE_TYPE.Bind" @bind-wechat="bindWechat()" />
</div>
<template #footer>
<el-button @click="wechatDialogVisible = false">
取消
</el-button>
<el-button
type="primary"
@click="wechatDialogVisible = false"
>
关闭
</el-button>
</template>
</el-dialog>
</div>
@@ -222,26 +295,37 @@ function bindWechat() {
padding: 20px;
}
.profile-card {
border-radius: 8px;
box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}
.card-header {
.header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.card-header h3 {
.header h2 {
display: flex;
align-items: center;
margin: 0;
font-size: 20px;
color: #333;
}
.profile-content {
.header .el-icon {
margin-right: 8px;
color: #409eff;
}
.profile-card {
border-radius: 12px;
box-shadow: 0 2px 12px rgba(0, 0, 0, 0.1);
}
/* 用户头部区域 */
.user-header-section {
display: flex;
gap: 40px;
align-items: flex-start;
gap: 30px;
align-items: center;
padding: 20px 0;
}
.avatar-section {
@@ -249,33 +333,127 @@ function bindWechat() {
flex-shrink: 0;
}
.avatar-wrapper {
position: relative;
display: inline-block;
}
.user-avatar {
margin-bottom: 15px;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-size: 40px;
font-size: 48px;
font-weight: bold;
border: 4px solid #fff;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15);
}
.vip-badge {
position: absolute;
bottom: 0;
right: -10px;
background: linear-gradient(135deg, #f5af19 0%, #f12711 100%);
color: white;
padding: 4px 12px;
border-radius: 20px;
font-size: 12px;
font-weight: bold;
display: flex;
align-items: center;
gap: 4px;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2);
}
.avatar-actions {
margin-top: 10px;
margin-top: 15px;
}
.info-section {
.user-info-quick {
flex: 1;
}
:deep(.el-descriptions__body) {
background-color: #fafafa;
.user-name {
font-size: 28px;
font-weight: 600;
color: #333;
margin: 0 0 15px 0;
}
:deep(.el-descriptions__label) {
.user-tags {
display: flex;
gap: 10px;
margin-bottom: 20px;
flex-wrap: wrap;
}
.user-stats {
display: flex;
gap: 30px;
}
.stat-item {
text-align: center;
}
.stat-value {
font-size: 16px;
font-weight: 600;
width: 100px;
color: #409eff;
margin-bottom: 4px;
}
.stat-label {
font-size: 13px;
color: #909399;
}
/* 信息区域 */
.info-section {
padding: 10px 0;
}
.info-grid {
display: grid;
grid-template-columns: repeat(2, 1fr);
gap: 20px;
}
.info-item {
display: flex;
flex-direction: column;
gap: 8px;
padding: 15px;
background: #f8f9fa;
border-radius: 8px;
transition: all 0.3s;
}
.info-item:hover {
background: #e9ecef;
transform: translateY(-2px);
}
.info-item.full-width {
grid-column: 1 / -1;
}
.info-label {
display: flex;
align-items: center;
gap: 6px;
font-size: 14px;
color: #666;
font-weight: 500;
}
.info-value {
font-size: 15px;
color: #333;
font-weight: 500;
}
.unset-text {
color: #999;
font-style: italic;
font-weight: normal;
}
.wechat-binding {
@@ -284,60 +462,50 @@ function bindWechat() {
justify-content: space-between;
}
.wechat-id {
color: #666;
font-size: 12px;
margin-left: 5px;
.wechat-status {
display: flex;
align-items: center;
gap: 6px;
}
.bind-btn {
margin-left: 10px;
/* 操作区域 */
.action-section {
margin-top: 30px;
padding-top: 20px;
border-top: 1px solid #f0f0f0;
text-align: center;
}
/* 微信绑定对话框 */
.wechat-dialog {
text-align: center;
}
.qrcode-section {
margin: 20px 0;
}
.qrcode-placeholder {
width: 200px;
height: 200px;
margin: 0 auto;
border: 2px dashed #ddd;
border-radius: 8px;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: #999;
}
.qrcode-placeholder .el-icon {
font-size: 48px;
margin-bottom: 10px;
}
.wechat-tip {
color: #666;
margin-top: 10px;
}
.wechat-info {
color: #07C160;
font-weight: 500;
margin-bottom: 20px;
}
/* 响应式 */
@media (max-width: 768px) {
.profile-content {
.user-header-section {
flex-direction: column;
gap: 20px;
text-align: center;
}
.avatar-section {
align-self: center;
.user-info-quick {
width: 100%;
}
.user-stats {
justify-content: center;
}
.info-grid {
grid-template-columns: 1fr;
}
.info-item.full-width {
grid-column: 1;
}
}
</style>