fix: login state refresh, hero layout, default avatar consistency

This commit is contained in:
yuzhiran
2026-06-15 11:04:00 +08:00
parent 07c6557454
commit 5a49d15696
3 changed files with 57 additions and 25 deletions
+45 -16
View File
@@ -1,19 +1,32 @@
<template>
<view class="page fade-in">
<view class="hero">
<text class="hero-title">{{ greeting }}</text>
<text class="hero-sub">试试下面的功能开启你的求职练习</text>
<view class="user-card card" v-if="userInfo" @click="goProfile">
<image class="avatar" :src="userInfo.avatar || '/static/avatar-default.svg'" mode="aspectFill" />
<view class="user-meta">
<text class="user-name">{{ userInfo.nickname || '同学' }}</text>
<view class="user-tags">
<text class="tag tag-plan">{{ userInfo.plan || '免费版' }}</text>
<text class="tag tag-remaining">剩余 {{ userInfo.remaining || 0 }} </text>
<view class="hero-row">
<view class="hero-left">
<text class="hero-title">{{ greeting }}</text>
<text class="hero-sub">试试下面的功能开启你的求职练习</text>
</view>
<view class="hero-right">
<view class="user-card card" v-if="userInfo" @click="goProfile">
<image class="avatar" :src="userInfo.avatar || '/static/avatar-default.png'" mode="aspectFill" />
<view class="user-meta">
<text class="user-name">{{ userInfo.nickname || '同学' }}</text>
<view class="user-tags">
<text class="tag tag-plan">{{ userInfo.plan || '免费版' }}</text>
<text class="tag tag-remaining">剩余 {{ userInfo.remaining || 0 }} </text>
</view>
</view>
<text class="arrow"></text>
</view>
<view class="guest-card card" v-else @click="goLogin">
<image class="avatar" src="/static/avatar-default.png" mode="aspectFill" />
<view class="user-meta">
<text class="user-name">立即登录</text>
<text class="guest-hint">登录后体验全部功能</text>
</view>
<text class="arrow"></text>
</view>
</view>
<text class="arrow"></text>
</view>
</view>
@@ -129,6 +142,7 @@
<script setup>
import { ref, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { api } from '../../config'
const userInfo = ref(null)
@@ -139,8 +153,12 @@ const positionsLoading = ref(true)
const dailyQuestion = ref(null)
const showAnswer = ref(false)
const loadUserInfo = () => {
try { const s = uni.getStorageSync('userInfo'); if (s) userInfo.value = JSON.parse(s); else userInfo.value = null } catch (e) { userInfo.value = null }
}
onMounted(async () => {
try { const s = uni.getStorageSync('userInfo'); if (s) userInfo.value = JSON.parse(s) } catch (e) {}
loadUserInfo()
const h = new Date().getHours()
if (h < 6) greeting.value = '夜深了,早点休息 🌙'
else if (h < 12) greeting.value = '早上好 ☀️'
@@ -170,9 +188,12 @@ onMounted(async () => {
finally { positionsLoading.value = false }
})
onShow(loadUserInfo)
const refreshDaily = () => { showAnswer.value = false; /* trigger reload */ }
const goProfile = () => uni.switchTab({ url: '/pages/user/user' })
const goLogin = () => uni.navigateTo({ url: '/pages/login/login' })
const goInterview = () => uni.navigateTo({ url: '/pages/interview/interview' })
const goResume = () => uni.navigateTo({ url: '/pages/resume/resume' })
const goProgress = () => uni.navigateTo({ url: '/pages/progress/progress' })
@@ -190,16 +211,24 @@ const startInterview = (pos) => uni.navigateTo({ url: `/pages/interview/intervie
background: linear-gradient(135deg, var(--color-gradient-start) 0%, var(--color-gradient-mid) 50%, var(--color-gradient-end) 100%);
padding: 48rpx 32rpx 72rpx; border-radius: 0 0 48rpx 48rpx;
}
.hero-row { display: flex; align-items: flex-start; gap: 24rpx; }
.hero-left { flex: 1; min-width: 0; padding-top: 8rpx; }
.hero-right { flex-shrink: 0; width: 320rpx; }
.hero-title { font-size: 40rpx; font-weight: 700; color: #FFF; display: block; line-height: 1.3; }
.hero-sub { font-size: 22rpx; color: rgba(255,255,255,0.7); margin-top: 8rpx; display: block; }
.user-card {
.user-card, .guest-card {
background: rgba(255,255,255,0.95); backdrop-filter: blur(20rpx);
border-radius: var(--radius-xl); padding: 24rpx 28rpx;
display: flex; align-items: center; margin-top: 24rpx;
border-radius: var(--radius-xl); padding: 20rpx 24rpx;
display: flex; align-items: center;
box-shadow: 0 8rpx 32rpx rgba(0,0,0,0.1);
}
.avatar { width: 88rpx; height: 88rpx; border-radius: 50%; margin-right: 20rpx; border: 3rpx solid var(--color-primary-light); flex-shrink: 0; }
.guest-card { background: rgba(255,255,255,0.15); backdrop-filter: blur(10rpx); }
.guest-card .avatar { border-color: rgba(255,255,255,0.3); }
.guest-card .user-name { font-size: 26rpx; color: #FFF; }
.guest-hint { font-size: 20rpx; color: rgba(255,255,255,0.6); margin-top: 4rpx; display: block; }
.guest-card .arrow { color: rgba(255,255,255,0.4); }
.avatar { width: 72rpx; height: 72rpx; border-radius: 50%; margin-right: 16rpx; border: 3rpx solid var(--color-primary-light); flex-shrink: 0; }
.user-meta { flex: 1; min-width: 0; }
.user-name { font-size: 30rpx; font-weight: 600; color: var(--color-text); }
.user-tags { display: flex; gap: 10rpx; margin-top: 10rpx; }
+7 -4
View File
@@ -3,7 +3,7 @@
<!-- 个人中心 -->
<view class="header" v-if="isLoggedIn">
<view class="profile-section">
<image class="avatar" :src="userInfo.avatar || '/static/avatar-default.svg'" mode="aspectFill" />
<image class="avatar" :src="userInfo.avatar || '/static/avatar-default.png'" mode="aspectFill" />
<view class="profile-info">
<text class="nickname">{{ userInfo.nickname || '未设置昵称' }}</text>
<view class="plan-badge">{{ userInfo.plan || '免费版' }}</view>
@@ -33,7 +33,6 @@
<view class="guest-avatar"><text class="guest-icon">👤</text></view>
<view class="guest-info">
<text class="guest-name">未登录 / 点击登录</text>
<text class="guest-hint">登录后体验全部功能</text>
</view>
<text class="header-arrow"></text>
</view>
@@ -84,6 +83,7 @@
<script setup>
import { ref, computed, onMounted } from 'vue'
import { onShow } from '@dcloudio/uni-app'
import { api } from '../../config'
const userInfo = ref({})
@@ -93,13 +93,16 @@ const token = ref('')
const isLoggedIn = computed(() => !!token.value)
onMounted(() => {
const refreshState = () => {
token.value = uni.getStorageSync('token') || ''
if (!token.value) return
try { const s = uni.getStorageSync('userInfo'); if (s) userInfo.value = JSON.parse(s) } catch(e) {}
loadStats()
checkAdmin()
})
}
onMounted(refreshState)
onShow(refreshState)
const loadStats = async () => {
try {