735 lines
20 KiB
Vue
735 lines
20 KiB
Vue
<template>
|
||
<view class="page-profile page-layout">
|
||
<view class="status-bar-placeholder"></view>
|
||
|
||
<!-- 学习者档案头 -->
|
||
<view class="profile-card">
|
||
<view class="profile-avatar">
|
||
<image
|
||
v-if="userStore.userInfo?.avatarUrl"
|
||
:src="userStore.userInfo.avatarUrl"
|
||
class="avatar-img"
|
||
mode="aspectFill"
|
||
/>
|
||
<view v-else class="avatar-placeholder">
|
||
<AppIcon name="planet-white" :size="26" />
|
||
</view>
|
||
</view>
|
||
<view class="profile-main" @click="editNickname">
|
||
<text class="profile-name">{{ userStore.userInfo?.nickName || '探索者' }}<text v-if="userStore.isLoggedIn" class="nick-edit"> ✏️</text></text>
|
||
<text class="profile-sub">{{ profileSubText }}</text>
|
||
</view>
|
||
<view class="streak-chip" v-if="stats && stats.streak > 0">
|
||
<AppIcon name="flame" :size="13" />
|
||
<text>{{ stats.streak }} 天</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 学习数据 -->
|
||
<view class="stats-row">
|
||
<view class="stat-tile" @click="goProgress">
|
||
<text class="stat-num">{{ stats?.totalLit || 0 }}</text>
|
||
<text class="stat-label">点亮星球</text>
|
||
</view>
|
||
<view class="stat-tile">
|
||
<text class="stat-num">{{ stats?.streak || 0 }}</text>
|
||
<text class="stat-label">连续天数</text>
|
||
</view>
|
||
<view class="stat-tile" @click="goFavorites">
|
||
<text class="stat-num">{{ collectedCount }}</text>
|
||
<text class="stat-label">收藏知识</text>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 已登录:星尘余额 + 今日免费 -->
|
||
<view class="balance-card" v-if="userStore.isLoggedIn">
|
||
<view class="balance-left">
|
||
<view class="coin-row">
|
||
<text class="coin-icon">✨</text>
|
||
<text class="coin-num">{{ vpayBalance }}</text>
|
||
<text class="coin-name">星尘</text>
|
||
</view>
|
||
<text class="free-left">今日免费问答剩余 {{ freeRemaining }} 次</text>
|
||
</view>
|
||
<view class="balance-actions">
|
||
<view class="recharge-go" @click="goRecharge"><text>充值</text></view>
|
||
<view class="recharge-go outline" @click="goLedger"><text>明细</text></view>
|
||
</view>
|
||
</view>
|
||
|
||
<!-- 未登录:引导登录 -->
|
||
<view class="balance-card" v-if="!userStore.isLoggedIn" @click="goLogin">
|
||
<view class="balance-left">
|
||
<text class="login-guide-title">登录后开始探索</text>
|
||
<text class="login-guide-sub">每天 5 次免费 AI 问答 · 点亮知识星球</text>
|
||
</view>
|
||
<view class="recharge-go"><text>去登录</text></view>
|
||
</view>
|
||
<!-- 菜单列表 -->
|
||
<view class="menu-section">
|
||
<view class="menu-item" @click="goFavorites">
|
||
<view class="m-icon" style="background:var(--dim1-bg)"><AppIcon name="star" :size="16" /></view>
|
||
<text class="m-label">我的收藏</text>
|
||
<text class="m-badge">{{ collectedCount }}</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
<view class="menu-item" @click="goProgress">
|
||
<view class="m-icon" style="background:var(--dim2-bg)"><AppIcon name="rocket" :size="16" /></view>
|
||
<text class="m-label">学习进度</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
<view class="menu-item" @click="goAchievements">
|
||
<view class="m-icon" style="background:var(--dim4-bg)"><AppIcon name="trophy" :size="16" /></view>
|
||
<text class="m-label">成就</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
<view class="menu-item" @click="goLeaderboard">
|
||
<view class="m-icon" style="background:var(--dim3-bg)"><AppIcon name="sparkle" :size="16" /></view>
|
||
<text class="m-label">排行榜</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
<view class="menu-item" @click="goFeedback">
|
||
<view class="m-icon" style="background:var(--dim5-bg)"><AppIcon name="feedback" :size="16" /></view>
|
||
<text class="m-label">意见反馈</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
<view class="menu-item" @click="goSettings">
|
||
<view class="m-icon" style="background:var(--bg-tertiary)"><AppIcon name="settings-gray" :size="16" /></view>
|
||
<text class="m-label">设置</text>
|
||
<AppIcon name="arrow-gray" :size="12" />
|
||
</view>
|
||
</view>
|
||
<view v-if="userStore.isLoggedIn" class="action-btn logout" @click="handleLogout">
|
||
<text>退出登录</text>
|
||
</view>
|
||
|
||
<text class="version">宇之然 AI 维度 v{{ versionText }}</text>
|
||
|
||
<!-- 页脚:公司信息 / 联系客服 -->
|
||
<view class="foot">
|
||
<image class="foot-qr" src="/static/yzr/kefu.png" mode="widthFix" show-menu-by-longpress @click="previewKefu" />
|
||
<text class="foot-tip">微信客服 · 长按识别二维码,或点下方按钮直接联系</text>
|
||
<!-- #ifdef MP-WEIXIN -->
|
||
<button class="foot-contact" open-type="contact" session-from="profile-footer">💬 在线联系客服</button>
|
||
<!-- #endif -->
|
||
<text class="foot-line">联系邮箱:contact@yuzhiran.com</text>
|
||
<text class="foot-line">北京宇之然科技中心 · © 2026</text>
|
||
<!-- #ifdef H5 -->
|
||
<view class="foot-line"><a class="foot-link" href="https://beian.miit.gov.cn/" target="_blank" rel="noopener">京ICP备2026007249号-2</a> · <a class="foot-link" href="https://beian.mps.gov.cn/#/query/webSearch?code=11011502039622" target="_blank" rel="noopener">京公网安备11011502039622号</a></view>
|
||
<!-- #endif -->
|
||
</view>
|
||
</view>
|
||
</template>
|
||
|
||
<script setup>
|
||
import { onShow, onShareAppMessage, onShareTimeline } from '@dcloudio/uni-app'
|
||
import { ref, computed, onMounted } from 'vue'
|
||
import { useUserStore } from '@/stores/user'
|
||
import { knowledgeApi, aiChatApi, request } from '@/utils/api'
|
||
import { DIMENSIONS } from '@/utils/dimensions'
|
||
import AppIcon from '@/components/AppIcon.vue'
|
||
import { APP_VERSION } from '@/utils/version'
|
||
|
||
const SUB_GUEST = '游客 · 点亮进度保存在本机,登录后同步'
|
||
const SUB_USER = '已点亮 {n} 颗星球 · 连续 {d} 天'
|
||
|
||
const PLAN_DESC_FREE = '每日 5 次 AI 问答 · 答对检测题点亮星球'
|
||
|
||
const userStore = useUserStore()
|
||
const dimensions = DIMENSIONS
|
||
|
||
const collectedCount = ref(0)
|
||
const vpayBalance = ref(0)
|
||
const freeRemaining = ref(5)
|
||
const stats = ref(null)
|
||
const byDim = ref({})
|
||
const quotaInfo = ref(null)
|
||
|
||
const versionText = APP_VERSION
|
||
|
||
const profileSubText = computed(() => {
|
||
if (!userStore.isLoggedIn) return SUB_GUEST
|
||
if (!stats.value) return '知识星图探索中'
|
||
return `已点亮 ${stats.value.totalLit} 颗星球 · 连续 ${stats.value.streak} 天`
|
||
})
|
||
|
||
|
||
const planDesc = computed(() =>
|
||
userStore.isSubscribed ? '全量知识解锁 · AI 问答无限次' : PLAN_DESC_FREE
|
||
)
|
||
const planBtnText = computed(() => {
|
||
if (userStore.isLoggedIn && userStore.isSubscribed) return '已订阅'
|
||
if (userStore.isLoggedIn) return '升级 Pro'
|
||
return '登录后升级'
|
||
})
|
||
|
||
const planPercent = computed(() => {
|
||
const sub = userStore.subInfo
|
||
if (!sub?.expiresAt || !sub?.startedAt) return 100
|
||
const total = new Date(sub.expiresAt) - new Date(sub.startedAt)
|
||
const passed = Date.now() - new Date(sub.startedAt)
|
||
if (total <= 0) return 100
|
||
return Math.min(100, Math.max(0, Math.round((passed / total) * 100)))
|
||
})
|
||
|
||
const planExpiryText = computed(() => {
|
||
if (!userStore.subInfo?.expiresAt) return ''
|
||
const diffDays = Math.ceil((new Date(userStore.subInfo.expiresAt) - Date.now()) / 86400000)
|
||
return diffDays <= 0 ? '已过期' : `${diffDays} 天后到期`
|
||
})
|
||
|
||
const quotaPercent = computed(() => {
|
||
if (!quotaInfo.value) return 0
|
||
const total = (quotaInfo.value.freeQuota || 5) + (quotaInfo.value.sharedQuota || 0)
|
||
if (!total) return 0
|
||
return Math.round((quotaInfo.value.remainingQuota / total) * 100)
|
||
})
|
||
|
||
onMounted(() => {
|
||
loadStats()
|
||
if (userStore.isLoggedIn) {
|
||
userStore.fetchMe()
|
||
loadCollected()
|
||
}
|
||
})
|
||
|
||
// 每次进入/返回本页都刷新余额与额度(充值页支付成功后返回时余额同步)
|
||
onShow(() => {
|
||
if (userStore.isLoggedIn) {
|
||
loadVpayInfo()
|
||
loadQuota()
|
||
}
|
||
})
|
||
|
||
async function loadVpayInfo() {
|
||
try {
|
||
const data = await request('GET', '/api/vpay/info', null, userStore.token)
|
||
vpayBalance.value = data.balance || 0
|
||
if (userStore.quota) freeRemaining.value = userStore.quota.remainingQuota ?? 5
|
||
} catch (e) {
|
||
// 未开通或未登录
|
||
}
|
||
}
|
||
|
||
async function loadStats() {
|
||
try {
|
||
const data = await knowledgeApi.stats(userStore.isLoggedIn ? userStore.token : '')
|
||
stats.value = data.user
|
||
byDim.value = data.byDim || {}
|
||
} catch (e) {
|
||
// 游客或失败:不显示进度区
|
||
}
|
||
}
|
||
|
||
async function loadCollected() {
|
||
if (!userStore.token) return
|
||
try {
|
||
const list = await knowledgeApi.collected(userStore.token)
|
||
collectedCount.value = list.length
|
||
} catch (e) {
|
||
collectedCount.value = 0
|
||
}
|
||
}
|
||
|
||
async function loadQuota() {
|
||
try {
|
||
quotaInfo.value = await aiChatApi.quota(userStore.token)
|
||
} catch (e) {}
|
||
}
|
||
|
||
function dimPercent(dimId) {
|
||
const total = byDim.value[dimId] || 0
|
||
if (!total) return 0
|
||
return Math.round(((stats.value?.litByDim?.[dimId] || 0) / total) * 100)
|
||
}
|
||
|
||
// 修改昵称(点击我的页昵称)
|
||
function editNickname() {
|
||
if (!userStore.isLoggedIn) {
|
||
uni.showModal({
|
||
title: '请先登录',
|
||
content: '登录后即可修改昵称',
|
||
confirmText: '去登录',
|
||
showCancel: false,
|
||
success: () => uni.navigateTo({ url: '/pages/login/login' }),
|
||
})
|
||
return
|
||
}
|
||
uni.showModal({
|
||
title: '修改昵称',
|
||
editable: true,
|
||
placeholderText: '请输入新昵称(最多20字)',
|
||
success: async (m) => {
|
||
if (!m.confirm) return
|
||
const nickName = String(m.content || '').trim()
|
||
if (!nickName) return uni.showToast({ title: '昵称不能为空', icon: 'none' })
|
||
try {
|
||
await request('PUT', '/api/auth/nickname', { nickName }, userStore.token)
|
||
await userStore.fetchMe()
|
||
uni.showToast({ title: '昵称已更新', icon: 'success' })
|
||
} catch (e) {
|
||
uni.showToast({ title: e.message || '修改失败', icon: 'none' })
|
||
}
|
||
},
|
||
})
|
||
}
|
||
|
||
function previewKefu() {
|
||
uni.previewImage({ urls: ['/static/yzr/kefu.png'] })
|
||
}
|
||
|
||
function goDim(id) {
|
||
uni.navigateTo({ url: `/pages/dimension/dimension?id=${id}` })
|
||
}
|
||
|
||
async function handleLogout() {
|
||
const res = await uni.showModal({ title: '退出登录', content: '确定退出当前账号?' })
|
||
if (res.confirm) {
|
||
userStore.logout()
|
||
stats.value = null
|
||
uni.showToast({ title: '已退出', icon: 'none' })
|
||
}
|
||
}
|
||
|
||
function goLogin() { uni.navigateTo({ url: '/pages/login/login' }) }
|
||
|
||
function goHome() { uni.switchTab({ url: '/pages/index/index' }) }
|
||
function goLedger() { uni.navigateTo({ url: '/pages/vpay/ledger' }) }
|
||
function goRecharge() { uni.navigateTo({ url: '/pages/vpay/recharge' }) }
|
||
function goChat() { uni.switchTab({ url: '/pages/chat/chat' }) }
|
||
function goFavorites() { uni.navigateTo({ url: '/pages/favorites/favorites' }) }
|
||
function goProgress() { uni.navigateTo({ url: '/pages/progress/progress' }) }
|
||
function goAchievements() { uni.navigateTo({ url: '/pages/achievements/achievements' }) }
|
||
function goLeaderboard() { uni.navigateTo({ url: '/pages/leaderboard/leaderboard' }) }
|
||
function goFeedback() { uni.navigateTo({ url: '/pages/feedback/feedback' }) }
|
||
function goSettings() { uni.navigateTo({ url: '/pages/settings/settings' }) }
|
||
function goPayment() {
|
||
if (!userStore.isLoggedIn) {
|
||
uni.navigateTo({ url: '/pages/login/login' })
|
||
return
|
||
}
|
||
uni.navigateTo({ url: '/pages/payment/payment' })
|
||
}
|
||
|
||
function goShare() {
|
||
if (!userStore.token) return
|
||
uni.showShareMenu({ withShareTicket: true })
|
||
aiChatApi.shareGain(userStore.token).then(() => {
|
||
uni.showToast({ title: '已记录分享 +5 次', icon: 'success' })
|
||
loadQuota()
|
||
}).catch(() => {})
|
||
}
|
||
|
||
// #ifdef MP-WEIXIN
|
||
onShareAppMessage(() => ({
|
||
title: '我在 AI 维度点亮了知识星球,来一起探索',
|
||
path: '/pages/index/index'
|
||
}))
|
||
onShareTimeline(() => ({
|
||
title: 'AI 维度 · 点亮你的知识星球'
|
||
}))
|
||
// #endif
|
||
</script>
|
||
|
||
<style lang="scss" scoped>
|
||
.page-profile {
|
||
min-height: 100vh;
|
||
background: var(--bg-primary);
|
||
}
|
||
|
||
.status-bar-placeholder { height: 44px; }
|
||
|
||
.profile-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 14px;
|
||
padding: 8px 0 16px;
|
||
}
|
||
|
||
.profile-avatar {
|
||
width: 62px; height: 62px;
|
||
border-radius: 50%;
|
||
flex-shrink: 0;
|
||
overflow: hidden;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
|
||
.avatar-img { width: 100%; height: 100%; }
|
||
.avatar-placeholder {
|
||
width: 100%; height: 100%;
|
||
border-radius: 50%;
|
||
background: linear-gradient(135deg, var(--color-brand), #8b5cf6);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
}
|
||
}
|
||
|
||
.profile-main { flex: 1; min-width: 0; }
|
||
.profile-name {
|
||
display: block;
|
||
font-size: 20px;
|
||
font-weight: 700;
|
||
color: var(--text-primary);
|
||
margin-bottom: 4px;
|
||
}
|
||
.nick-edit { font-size: 14px; opacity: 0.7; }
|
||
.profile-sub {
|
||
display: block;
|
||
font-size: 12px;
|
||
color: var(--text-tertiary);
|
||
line-height: 1.5;
|
||
}
|
||
|
||
.streak-chip {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 4px;
|
||
padding: 6px 12px;
|
||
border-radius: var(--radius-full);
|
||
background: rgba(229, 28, 28, 0.08);
|
||
border: 1px solid rgba(229, 28, 28, 0.15);
|
||
font-size: 12px;
|
||
font-weight: 700;
|
||
color: var(--dim5-color);
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 学习数据 */
|
||
.stats-row {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.stat-tile {
|
||
flex: 1;
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 14px 0;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 4px;
|
||
box-shadow: var(--card-shadow, none);
|
||
|
||
.stat-num {
|
||
font-size: 20px;
|
||
font-weight: 800;
|
||
color: var(--text-primary);
|
||
}
|
||
.stat-label {
|
||
font-size: 11px;
|
||
color: var(--text-tertiary);
|
||
}
|
||
}
|
||
|
||
/* 五星域进度 */
|
||
.dims-progress {
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 6px 16px;
|
||
margin-bottom: 12px;
|
||
box-shadow: var(--card-shadow, none);
|
||
}
|
||
.dim-row {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 10px;
|
||
padding: 10px 0;
|
||
}
|
||
.dim-dot {
|
||
width: 26px; height: 26px;
|
||
border-radius: 8px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.dim-name {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
width: 56px;
|
||
flex-shrink: 0;
|
||
}
|
||
.dim-bar {
|
||
flex: 1;
|
||
height: 6px;
|
||
border-radius: 3px;
|
||
background: var(--bg-tertiary);
|
||
overflow: hidden;
|
||
}
|
||
.dim-bar-fill {
|
||
height: 100%;
|
||
border-radius: 3px;
|
||
transition: width 0.4s ease;
|
||
}
|
||
.dim-frac {
|
||
font-size: 11px;
|
||
color: var(--text-muted);
|
||
width: 40px;
|
||
text-align: right;
|
||
flex-shrink: 0;
|
||
}
|
||
|
||
/* 订阅 */
|
||
.plan-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
border-radius: var(--radius-lg);
|
||
padding: 16px;
|
||
margin-bottom: 12px;
|
||
background: linear-gradient(135deg, #1a1a3a, #2d2b5e);
|
||
border: 1px solid rgba(123, 135, 253, 0.3);
|
||
}
|
||
.plan-info { flex: 1; min-width: 0; }
|
||
.plan-title {
|
||
display: block;
|
||
font-size: 16px;
|
||
font-weight: 700;
|
||
color: #fff;
|
||
margin-bottom: 4px;
|
||
}
|
||
.plan-desc {
|
||
display: block;
|
||
font-size: 11px;
|
||
color: rgba(255, 255, 255, 0.55);
|
||
line-height: 1.5;
|
||
}
|
||
.plan-progress {
|
||
margin-top: 8px;
|
||
.progress-track {
|
||
height: 3px;
|
||
background: rgba(255, 255, 255, 0.15);
|
||
border-radius: 2px;
|
||
overflow: hidden;
|
||
}
|
||
.progress-fill {
|
||
height: 100%;
|
||
background: linear-gradient(90deg, #7b87fd, #a2b2ff);
|
||
border-radius: 2px;
|
||
}
|
||
.progress-text {
|
||
font-size: 10px;
|
||
color: rgba(255, 255, 255, 0.4);
|
||
margin-top: 4px;
|
||
display: block;
|
||
}
|
||
}
|
||
.plan-btn {
|
||
padding: 9px 16px;
|
||
border-radius: var(--radius-full);
|
||
background: linear-gradient(135deg, var(--color-brand), #8b5cf6);
|
||
color: #fff;
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
flex-shrink: 0;
|
||
|
||
&.disabled { opacity: 0.5; }
|
||
}
|
||
|
||
/* 配额 */
|
||
.quota-card {
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 14px 16px;
|
||
margin-bottom: 12px;
|
||
box-shadow: var(--card-shadow, none);
|
||
}
|
||
.quota-head {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 6px;
|
||
margin-bottom: 10px;
|
||
|
||
.quota-card-title {
|
||
font-size: 13px;
|
||
font-weight: 600;
|
||
color: var(--text-primary);
|
||
}
|
||
}
|
||
.quota-bar {
|
||
height: 6px;
|
||
border-radius: 3px;
|
||
background: var(--bg-tertiary);
|
||
overflow: hidden;
|
||
margin-bottom: 8px;
|
||
}
|
||
.quota-fill {
|
||
height: 100%;
|
||
border-radius: 3px;
|
||
background: linear-gradient(90deg, var(--color-brand), var(--color-brand-light));
|
||
transition: width 0.3s ease;
|
||
}
|
||
.quota-foot {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
|
||
.quota-text {
|
||
font-size: 12px;
|
||
color: var(--text-secondary);
|
||
}
|
||
.quota-share {
|
||
font-size: 12px;
|
||
font-weight: 600;
|
||
color: var(--color-brand);
|
||
}
|
||
}
|
||
|
||
/* 菜单 */
|
||
.menu-section {
|
||
background: var(--glass-bg);
|
||
border: 1px solid var(--glass-border);
|
||
border-radius: var(--radius-lg);
|
||
padding: 4px 16px;
|
||
margin-bottom: 16px;
|
||
box-shadow: var(--card-shadow, none);
|
||
}
|
||
.menu-item {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: 12px;
|
||
padding: 13px 0;
|
||
border-bottom: 1px solid var(--glass-border);
|
||
|
||
&:last-child { border-bottom: none; }
|
||
}
|
||
.m-icon {
|
||
width: 32px; height: 32px;
|
||
border-radius: 10px;
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
flex-shrink: 0;
|
||
}
|
||
.m-label {
|
||
flex: 1;
|
||
font-size: 14px;
|
||
color: var(--text-primary);
|
||
}
|
||
.m-badge {
|
||
font-size: 11px;
|
||
color: var(--text-muted);
|
||
}
|
||
|
||
/* 操作 */
|
||
.action-row {
|
||
display: flex;
|
||
gap: 10px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.action-btn {
|
||
flex: 1;
|
||
height: 46px;
|
||
border-radius: var(--radius-md);
|
||
display: flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
|
||
&.primary {
|
||
background: linear-gradient(135deg, var(--color-brand), var(--color-brand-light));
|
||
color: #fff;
|
||
}
|
||
&.ghost {
|
||
background: var(--glass-bg);
|
||
border: 1.5px solid var(--glass-border);
|
||
color: var(--text-secondary);
|
||
}
|
||
&.logout {
|
||
flex: none;
|
||
width: 100%;
|
||
background: var(--glass-bg);
|
||
border: 1.5px solid var(--glass-border);
|
||
color: var(--dim5-color);
|
||
margin-bottom: 12px;
|
||
}
|
||
}
|
||
|
||
.version {
|
||
display: block;
|
||
text-align: center;
|
||
font-size: 11px;
|
||
color: var(--text-muted);
|
||
padding: 8px 0 20px;
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.vpay-entry {
|
||
display: flex; align-items: center; gap: 12px;
|
||
background: linear-gradient(135deg, rgba(91,95,248,.1), rgba(139,92,246,.06));
|
||
border: 1.5px solid var(--glass-hover-border);
|
||
border-radius: var(--radius-lg); padding: 14px 16px; margin-bottom: 12px;
|
||
}
|
||
.ve-icon { font-size: 22px; }
|
||
.ve-info { flex: 1; }
|
||
.ve-title { font-size: 14px; font-weight: 700; color: var(--text-primary); display: block; }
|
||
.ve-desc { font-size: 11px; color: var(--text-tertiary); }
|
||
.ve-arrow { font-size: 14px; color: var(--text-muted); }
|
||
</style>
|
||
|
||
<style scoped>
|
||
.balance-card {
|
||
display: flex; align-items: center; gap: 14px;
|
||
background: linear-gradient(135deg, #5b5ff8, #8b5cf6);
|
||
border-radius: var(--radius-lg);
|
||
padding: 18px 20px;
|
||
margin-bottom: 12px;
|
||
}
|
||
.balance-left { flex: 1; }
|
||
.coin-row { display: flex; align-items: baseline; gap: 6px; }
|
||
.coin-icon { font-size: 20px; }
|
||
.coin-num { font-size: 32px; font-weight: 800; color: #fff; }
|
||
.coin-name { font-size: 13px; color: rgba(255,255,255,.7); }
|
||
.free-left { display: block; font-size: 11px; color: rgba(255,255,255,.55); margin-top: 4px; }
|
||
.recharge-go {
|
||
padding: 10px 22px;
|
||
background: #fff;
|
||
border-radius: var(--radius-full);
|
||
color: #5b5ff8;
|
||
font-size: 14px;
|
||
font-weight: 700;
|
||
flex-shrink: 0;
|
||
}
|
||
</style>
|
||
|
||
<style scoped>
|
||
.stats-hint { text-align: center; padding: 4px 0 8px; }
|
||
.stats-hint text { font-size: 11px; color: var(--text-muted); }
|
||
</style>
|
||
|
||
<style scoped>
|
||
.foot {
|
||
margin-top: 8px;
|
||
padding: 24px 0 16px;
|
||
display: flex;
|
||
flex-direction: column;
|
||
align-items: center;
|
||
gap: 6px;
|
||
}
|
||
.foot-qr { width: 120px; border-radius: 8px; background: #fff; }
|
||
.foot-tip { font-size: 11px; color: var(--text-muted, #b6bac9); }
|
||
.foot-contact {
|
||
margin-top: 4px;
|
||
font-size: 13px;
|
||
color: #6366f1;
|
||
background: var(--color-brand-bg, #f0f0ff);
|
||
border-radius: 999px;
|
||
padding: 0 18px;
|
||
height: 32px;
|
||
line-height: 32px;
|
||
}
|
||
.foot-contact::after { border: none; }
|
||
.foot-line { font-size: 11px; color: var(--text-muted, #b6bac9); }
|
||
.foot-link { font-size: 11px; color: var(--text-tertiary, #9aa0b4); text-decoration: none; }
|
||
.balance-actions { display: flex; gap: 8px; }
|
||
.recharge-go.outline { background: transparent; border: 1.5px solid rgba(255,255,255,.6); color: #fff; }
|
||
</style>
|