Files
hejiu/App.vue
T
cg d335ec290a refactor(app): 重构应用主题和页面结构
- 移除动态主题切换功能,改为全局统一深色主题
- 实现自定义TabBar组件替换原生tabBar,解决iOS闪白问题
- 创建main容器页面统一管理三个tab页面的生命周期和状态
- 将所有页面的onShow/onHide等生命周期方法迁移到子组件内部
- 更新页面路径从index改为main,并调整路由跳转逻辑
- 移除theme-mixin和相关主题工具函数
- 统一页面背景色设置,优化用户体验一致性
2026-09-23 20:56:14 +08:00

404 lines
8.4 KiB
Vue
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<script>
import client, { refreshAuthToken } from './common/api'
import wsManager from './common/websocket'
export default {
onLaunch() {
console.log('碰盏日记 App Launch')
// 一次性设置窗口背景色(深色主题),避免切换 tab 时露白底
try {
uni.setBackgroundColor({
backgroundColor: '#0B0B14',
backgroundColorTop: '#0B0B14',
backgroundColorBottom: '#0B0B14'
})
} catch (e) {}
// 尝试刷新 token
this.restoreAuth()
// 初始化 WebSocket 连接(私信功能)
this.initWebSocket()
// 数据迁移:清除旧版 logo.png 头像引用
this.migrateUserData()
// 启动路由守卫
this.checkLaunchRoute()
},
onShow() {
console.log('App Show')
},
onHide() {
console.log('App Hide')
},
methods: {
// 恢复登录态:从缓存恢复 token 并尝试刷新
async restoreAuth() {
const token = uni.getStorageSync('auth_token')
if (token) {
client.setToken(token)
// 后台尝试刷新 token(静默,不阻塞启动)
refreshAuthToken().catch(() => {})
}
},
// 初始化 WebSocket 连接(私信实时通信)
initWebSocket() {
const token = uni.getStorageSync('auth_token')
if (token) {
wsManager.connect(token)
}
},
// 数据迁移:清除旧版 logo.png 头像引用
migrateUserData() {
try {
const raw = uni.getStorageSync('user_info')
if (raw) {
const user = JSON.parse(raw)
if (user.avatar && user.avatar.includes('logo.png')) {
user.avatar = ''
uni.setStorageSync('user_info', JSON.stringify(user))
}
}
} catch (e) { /* ignore */ }
},
// 启动时检查引导状态,决定跳转目标
checkLaunchRoute() {
const isFirst = uni.getStorageSync('is_first_launch')
if (!isFirst || isFirst === 'true') {
// 首次使用 → 引导页
// 延迟一帧再跳:启动早期首页还未就绪,立即 reLaunch 可能报 timeout
setTimeout(() => {
uni.reLaunch({ url: '/pages/onboarding/onboarding', fail: () => {} })
}, 100)
}
// 否则正常进入主容器(main),pages.json 中 main 为第一个页面
}
}
}
</script>
<style lang="scss">
/* ==========================================
* 碰盏日记 - 全局样式
* 设计概念: 琥珀夜光 Amber Night
* ========================================== */
page {
background-color: $bg-base;
color: $text-primary;
font-family: $font-base;
font-size: $fs-base;
line-height: $lh-normal;
-webkit-font-smoothing: antialiased;
}
/* --- 通用工具类 --- */
.page-container {
min-height: 100vh;
background-color: $bg-base;
color: $text-primary;
padding-bottom: env(safe-area-inset-bottom);
box-sizing: border-box;
}
.card {
background-color: $bg-card;
color: $text-primary;
border-radius: $radius-lg;
padding: $sp-lg;
box-shadow: $shadow-sm;
}
.card-elevated {
background-color: $bg-elevated;
color: $text-primary;
border-radius: $radius-lg;
padding: $sp-lg;
box-shadow: $shadow-md;
}
/* --- 文本层级 --- */
.text-hero {
font-size: $fs-hero;
font-weight: $fw-black;
line-height: $lh-tight;
letter-spacing: -2rpx;
color: $text-primary;
}
.text-display {
font-size: $fs-3xl;
font-weight: $fw-black;
line-height: $lh-tight;
color: $text-primary;
}
.text-h1 {
font-size: $fs-2xl;
font-weight: $fw-bold;
line-height: $lh-tight;
color: $text-primary;
}
.text-h2 {
font-size: $fs-xl;
font-weight: $fw-bold;
line-height: $lh-tight;
color: $text-primary;
}
.text-h3 {
font-size: $fs-lg;
font-weight: $fw-medium;
line-height: $lh-normal;
color: $text-primary;
}
.text-body {
font-size: $fs-base;
font-weight: $fw-normal;
line-height: $lh-normal;
color: $text-primary;
}
.text-caption {
font-size: $fs-sm;
color: $text-secondary;
line-height: $lh-normal;
}
.text-tiny {
font-size: $fs-xs;
color: $text-tertiary;
}
/* --- 数字专用 --- */
.text-num {
font-family: $font-num;
font-weight: $fw-bold;
letter-spacing: -1rpx;
}
/* --- 色彩文字 --- */
.text-amber {
color: $amber;
}
.text-mint {
color: $mint;
}
.text-coral {
color: $coral;
}
.text-secondary {
color: $text-secondary;
}
/* --- 按钮系统 --- */
.btn-primary {
background: linear-gradient(135deg, $amber, $amber-deep);
color: $text-on-amber;
font-size: $fs-md;
font-weight: $fw-bold;
padding: $sp-md $sp-xl;
border-radius: $radius-full;
border: none;
text-align: center;
box-shadow: $shadow-amber;
transition: all $duration-fast $ease-out;
&:active {
transform: scale(0.97);
box-shadow: 0 4rpx 16rpx rgba(232, 168, 56, 0.2);
}
}
.btn-primary-lg {
@extend .btn-primary;
padding: $sp-lg $sp-xl;
font-size: $fs-lg;
border-radius: $radius-full;
}
.btn-secondary {
background-color: $bg-elevated;
color: $text-primary;
font-size: $fs-base;
font-weight: $fw-medium;
padding: $sp-md $sp-xl;
border-radius: $radius-full;
border: 2rpx solid var(--border-subtle, rgba(255, 255, 255, 0.10));
transition: all $duration-fast $ease-out;
display: flex;
align-items: center;
justify-content: center;
&:active {
background-color: $bg-card-alt;
transform: scale(0.97);
}
}
.btn-ghost {
background-color: transparent;
color: $amber;
font-size: $fs-base;
font-weight: $fw-medium;
padding: $sp-sm $sp-lg;
border: 2rpx solid $amber;
border-radius: $radius-full;
text-align: center;
transition: all $duration-fast $ease-out;
&:active {
background-color: $amber-glow;
}
}
/* 添加酒水按钮(Step 1 底部) */
.btn-add-drink {
background: linear-gradient(135deg, $amber, $amber-deep);
color: $text-on-amber;
font-size: $fs-md;
font-weight: $fw-bold;
padding: $sp-md $sp-xl;
border-radius: $radius-full;
border: none;
text-align: center;
box-shadow: $shadow-amber;
transition: all $duration-fast $ease-out;
display: flex;
align-items: center;
justify-content: center;
&:active {
transform: scale(0.97);
box-shadow: 0 4rpx 16rpx rgba(232, 168, 56, 0.2);
}
&[disabled] {
background: transparent;
color: $text-tertiary;
border: 2rpx solid var(--border-subtle, rgba(255, 255, 255, 0.10));
box-shadow: none;
}
}
.btn-text {
background: none;
border: none;
color: $text-secondary;
font-size: $fs-sm;
padding: $sp-xs $sp-sm;
}
/* --- 琥珀CTA大按钮(签名元素) --- */
.btn-cta {
background: linear-gradient(135deg, $amber-light, $amber, $amber-deep);
color: $text-on-amber;
font-size: $fs-xl;
font-weight: $fw-bold;
padding: $sp-lg 0;
border-radius: $radius-xl;
border: none;
text-align: center;
box-shadow: $shadow-amber;
width: 100%;
position: relative;
overflow: hidden;
&::after {
content: '';
position: absolute;
top: 0;
left: -100%;
right: auto;
bottom: auto;
width: 100%;
height: 100%;
border: none;
transform: none;
background: linear-gradient(90deg, transparent, var(--btn-shimmer, rgba(255, 255, 255, 0.15)), transparent);
animation: shimmer 3s infinite;
}
&:active {
transform: scale(0.98);
}
}
@keyframes shimmer {
0% { left: -100%; }
100% { left: 100%; }
}
/* --- 标签 --- */
.tag {
display: inline-flex;
align-items: center;
padding: $sp-xs $sp-md;
border-radius: $radius-full;
font-size: $fs-sm;
font-weight: $fw-medium;
background-color: $bg-elevated;
color: $text-secondary;
&.tag-active {
background-color: $amber-glow;
color: $amber;
border: 2rpx solid rgba(232, 168, 56, 0.3);
}
}
/* --- 分隔线 --- */
.divider {
height: 2rpx;
background: linear-gradient(90deg, transparent, var(--divider-color, rgba(255, 255, 255, 0.08)), transparent);
margin: $sp-lg 0;
}
/* --- 弹性布局辅助 --- */
.flex {
display: flex;
}
.flex-col {
display: flex;
flex-direction: column;
}
.flex-center {
display: flex;
align-items: center;
justify-content: center;
}
.flex-between {
display: flex;
align-items: center;
justify-content: space-between;
}
.flex-1 {
flex: 1;
}
/* --- 安全区域 --- */
.safe-bottom {
padding-bottom: calc(env(safe-area-inset-bottom) + 120rpx);
}
/* --- 健康提示条 --- */
.health-bar {
display: flex;
align-items: center;
justify-content: center;
padding: $sp-sm;
font-size: $fs-xs;
color: $text-tertiary;
background-color: var(--bg-subtle, rgba(255, 255, 255, 0.03));
text {
opacity: 0.5;
}
}
</style>