fix: 登录页改造+亮色默认主题+颜色修复

- 登录页:修复 isMiniApp 检测逻辑,tab切换和注册按钮正常
- 主题系统:默认改为亮色模式,暗色可通过设置页切换
- 主题切换:设置页暗色开关已绑定实际切换逻辑
- 颜色修复:所有页面标题硬编码 #fff/white 改为 var(--text-primary)
- theme.scss 精简为工具类,变量定义集中到 App.vue
This commit is contained in:
Yuzhiran Dev
2026-07-11 01:00:03 +08:00
parent 51b394bbde
commit 25b81e9a11
14 changed files with 470 additions and 383 deletions
+192 -66
View File
@@ -9,7 +9,6 @@ import { onLaunch, onShow, onHide } from '@dcloudio/uni-app'
onLaunch(() => { onLaunch(() => {
console.log('[AI维度] App launched') console.log('[AI维度] App launched')
// 初始化主题
initTheme() initTheme()
}) })
@@ -22,78 +21,108 @@ onHide(() => {
}) })
function initTheme() { function initTheme() {
// 从本地存储读取主题偏好 const theme = uni.getStorageSync('theme') || 'light'
const theme = uni.getStorageSync('theme') || 'dark'
applyTheme(theme) applyTheme(theme)
} }
function applyTheme(theme) { function applyTheme(theme) {
if (theme === 'light') { try {
document.documentElement.classList.add('theme-light') // H5 环境直接操作 document
const root = document.documentElement
if (theme === 'dark') {
root.classList.add('theme-dark')
root.classList.remove('theme-light')
} else { } else {
document.documentElement.classList.remove('theme-light') root.classList.remove('theme-dark')
root.classList.add('theme-light')
}
} catch (e) {
// 小程序环境:document 不存在,直接忽略
} }
} }
</script> </script>
<style> <style>
/* 全局样式 - 直接定义 CSS 变量(不通过 @import 避免循环) */ /* ============================================
page { 宇之然AI维度 — 全局主题
--bg-primary: #14141e; 默认:亮色模式 | .theme-dark:暗色模式
--bg-secondary: #181828; ============================================ */
--bg-tertiary: #1c1a34;
--glass-bg: rgba(255, 255, 255, 0.06); /* ---- 亮色模式(默认) ---- */
--glass-border: rgba(255, 255, 255, 0.08); page, .theme-light {
--glass-hover: rgba(255, 255, 255, 0.1); /* 基础色 — 清爽浅灰 */
--glass-hover-border: rgba(255, 255, 255, 0.15); --bg-primary: #f5f5f7;
--glass-strong: rgba(255, 255, 255, 0.12); --bg-secondary: #ffffff;
--glass-dim-bg: rgba(124, 77, 255, 0.06); --bg-tertiary: #e8e8ed;
--text-primary: rgba(255, 255, 255, 0.95);
--text-secondary: rgba(255, 255, 255, 0.7); /* 玻璃拟态 */
--text-tertiary: rgba(255, 255, 255, 0.5); --glass-bg: rgba(255, 255, 255, 0.7);
--text-muted: rgba(255, 255, 255, 0.3); --glass-border: rgba(0, 0, 0, 0.06);
--color-brand: #8b5cf6; --glass-hover: rgba(255, 255, 255, 0.85);
--color-brand-light: #a78bfa; --glass-hover-border: rgba(0, 0, 0, 0.1);
--color-brand-dark: #7c3aed; --glass-strong: rgba(255, 255, 255, 0.9);
--color-brand-bg: rgba(139, 92, 246, 0.12); --glass-dim-bg: rgba(139, 92, 246, 0.05);
--color-brand-glow: rgba(139, 92, 246, 0.15);
--dim1-color: #a78bfa; /* 文字 */
--dim1-bg: rgba(139, 92, 246, 0.12); --text-primary: rgba(0, 0, 0, 0.88);
--dim1-icon-bg: rgba(139, 92, 246, 0.2); --text-secondary: rgba(0, 0, 0, 0.55);
--dim1-border: rgba(139, 92, 246, 0.18); --text-tertiary: rgba(0, 0, 0, 0.4);
--dim1-glow: rgba(139, 92, 246, 0.08); --text-muted: rgba(0, 0, 0, 0.25);
--dim2-color: #60a5fa; --text-disabled: rgba(0, 0, 0, 0.2);
--dim2-bg: rgba(96, 165, 250, 0.12);
--dim2-icon-bg: rgba(96, 165, 250, 0.2); /* 品牌色 */
--dim2-border: rgba(96, 165, 250, 0.18); --color-brand: #7c4dff;
--dim2-glow: rgba(96, 165, 250, 0.08); --color-brand-light: #b388ff;
--dim3-color: #34d399; --color-brand-dark: #651fff;
--dim3-bg: rgba(52, 211, 153, 0.12); --color-brand-bg: rgba(124, 77, 255, 0.08);
--dim3-icon-bg: rgba(52, 211, 153, 0.2); --color-brand-glow: rgba(124, 77, 255, 0.12);
--dim3-border: rgba(52, 211, 153, 0.18);
--dim3-glow: rgba(52, 211, 153, 0.08); /* 维度色 */
--dim4-color: #fbbf24; --dim1-color: #7c4dff;
--dim4-bg: rgba(251, 191, 36, 0.12); --dim1-bg: rgba(124, 77, 255, 0.08);
--dim4-icon-bg: rgba(251, 191, 36, 0.2); --dim1-icon-bg: rgba(124, 77, 255, 0.15);
--dim4-border: rgba(251, 191, 36, 0.18); --dim1-border: rgba(124, 77, 255, 0.15);
--dim4-glow: rgba(251, 191, 36, 0.08); --dim1-glow: rgba(124, 77, 255, 0.06);
--dim5-color: #fb7185;
--dim5-bg: rgba(251, 113, 133, 0.12); --dim2-color: #0ea5e9;
--dim5-icon-bg: rgba(251, 113, 133, 0.2); --dim2-bg: rgba(14, 165, 233, 0.08);
--dim5-border: rgba(251, 113, 133, 0.18); --dim2-icon-bg: rgba(14, 165, 233, 0.15);
--dim5-glow: rgba(251, 113, 133, 0.08); --dim2-border: rgba(14, 165, 233, 0.15);
--color-free: #34d399; --dim2-glow: rgba(14, 165, 233, 0.06);
--color-free-bg: rgba(52, 211, 153, 0.12);
--color-pro: #fbbf24; --dim3-color: #10b981;
--color-pro-bg: rgba(251, 191, 36, 0.12); --dim3-bg: rgba(16, 185, 129, 0.08);
--color-vip: #fb7185; --dim3-icon-bg: rgba(16, 185, 129, 0.15);
--color-vip-bg: rgba(251, 113, 133, 0.12); --dim3-border: rgba(16, 185, 129, 0.15);
--color-hot: #fb7185; --dim3-glow: rgba(16, 185, 129, 0.06);
--color-hot-bg: rgba(251, 113, 133, 0.15);
--color-new: #60a5fa; --dim4-color: #f59e0b;
--color-new-bg: rgba(96, 165, 250, 0.15); --dim4-bg: rgba(245, 158, 11, 0.08);
--color-pick: #a78bfa; --dim4-icon-bg: rgba(245, 158, 11, 0.15);
--color-pick-bg: rgba(139, 92, 246, 0.15); --dim4-border: rgba(245, 158, 11, 0.15);
--dim4-glow: rgba(245, 158, 11, 0.06);
--dim5-color: #ef4444;
--dim5-bg: rgba(239, 68, 68, 0.08);
--dim5-icon-bg: rgba(239, 68, 68, 0.15);
--dim5-border: rgba(239, 68, 68, 0.15);
--dim5-glow: rgba(239, 68, 68, 0.06);
/* 功能色 */
--color-free: #10b981;
--color-free-bg: rgba(16, 185, 129, 0.1);
--color-pro: #f59e0b;
--color-pro-bg: rgba(245, 158, 11, 0.1);
--color-vip: #ef4444;
--color-vip-bg: rgba(239, 68, 68, 0.1);
--color-hot: #ef4444;
--color-hot-bg: rgba(239, 68, 68, 0.12);
--color-new: #0ea5e9;
--color-new-bg: rgba(14, 165, 233, 0.12);
--color-pick: #7c4dff;
--color-pick-bg: rgba(124, 77, 255, 0.12);
/* 圆角/间距/过渡 */
--radius-sm: 8px; --radius-sm: 8px;
--radius-md: 12px; --radius-md: 12px;
--radius-lg: 16px; --radius-lg: 16px;
@@ -108,24 +137,121 @@ page {
--blur-bg: 20px; --blur-bg: 20px;
--transition-fast: 0.2s ease; --transition-fast: 0.2s ease;
--transition-normal: 0.3s ease; --transition-normal: 0.3s ease;
--glow-brand: 0 0 20px rgba(124, 77, 255, 0.08);
--glow-brand-strong: 0 0 30px rgba(124, 77, 255, 0.12);
}
/* ---- 暗色模式 ---- */
.theme-dark {
/* 基础色 */
--bg-primary: #14141e;
--bg-secondary: #181828;
--bg-tertiary: #1c1a34;
--glass-bg: rgba(255, 255, 255, 0.06);
--glass-border: rgba(255, 255, 255, 0.08);
--glass-hover: rgba(255, 255, 255, 0.1);
--glass-hover-border: rgba(255, 255, 255, 0.15);
--glass-strong: rgba(255, 255, 255, 0.12);
--glass-dim-bg: rgba(124, 77, 255, 0.06);
--text-primary: rgba(255, 255, 255, 0.95);
--text-secondary: rgba(255, 255, 255, 0.7);
--text-tertiary: rgba(255, 255, 255, 0.5);
--text-muted: rgba(255, 255, 255, 0.3);
--text-disabled: rgba(255, 255, 255, 0.15);
--color-brand: #8b5cf6;
--color-brand-light: #a78bfa;
--color-brand-dark: #7c3aed;
--color-brand-bg: rgba(139, 92, 246, 0.12);
--color-brand-glow: rgba(139, 92, 246, 0.15);
--dim1-color: #a78bfa;
--dim1-bg: rgba(139, 92, 246, 0.12);
--dim1-icon-bg: rgba(139, 92, 246, 0.2);
--dim1-border: rgba(139, 92, 246, 0.18);
--dim1-glow: rgba(139, 92, 246, 0.08);
--dim2-color: #60a5fa;
--dim2-bg: rgba(96, 165, 250, 0.12);
--dim2-icon-bg: rgba(96, 165, 250, 0.2);
--dim2-border: rgba(96, 165, 250, 0.18);
--dim2-glow: rgba(96, 165, 250, 0.08);
--dim3-color: #34d399;
--dim3-bg: rgba(52, 211, 153, 0.12);
--dim3-icon-bg: rgba(52, 211, 153, 0.2);
--dim3-border: rgba(52, 211, 153, 0.18);
--dim3-glow: rgba(52, 211, 153, 0.08);
--dim4-color: #fbbf24;
--dim4-bg: rgba(251, 191, 36, 0.12);
--dim4-icon-bg: rgba(251, 191, 36, 0.2);
--dim4-border: rgba(251, 191, 36, 0.18);
--dim4-glow: rgba(251, 191, 36, 0.08);
--dim5-color: #fb7185;
--dim5-bg: rgba(251, 113, 133, 0.12);
--dim5-icon-bg: rgba(251, 113, 133, 0.2);
--dim5-border: rgba(251, 113, 133, 0.18);
--dim5-glow: rgba(251, 113, 133, 0.08);
--color-free: #34d399;
--color-free-bg: rgba(52, 211, 153, 0.12);
--color-pro: #fbbf24;
--color-pro-bg: rgba(251, 191, 36, 0.12);
--color-vip: #fb7185;
--color-vip-bg: rgba(251, 113, 133, 0.12);
--color-hot: #fb7185;
--color-hot-bg: rgba(251, 113, 133, 0.15);
--color-new: #60a5fa;
--color-new-bg: rgba(96, 165, 250, 0.15);
--color-pick: #a78bfa;
--color-pick-bg: rgba(139, 92, 246, 0.15);
--glow-brand: 0 0 20px rgba(139, 92, 246, 0.1); --glow-brand: 0 0 20px rgba(139, 92, 246, 0.1);
--glow-brand-strong: 0 0 30px rgba(139, 92, 246, 0.15); --glow-brand-strong: 0 0 30px rgba(139, 92, 246, 0.15);
}
/* 全局排版 */
page {
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
background-color: var(--bg-primary); background-color: var(--bg-primary);
color: var(--text-secondary); color: var(--text-secondary);
font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif; font-family: -apple-system, BlinkMacSystemFont, 'SF Pro Display', 'Segoe UI', Roboto, sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
} }
view { view {
box-sizing: border-box; box-sizing: border-box;
} }
/* 滚动条隐藏 */
::-webkit-scrollbar { ::-webkit-scrollbar {
display: none; display: none;
width: 0; width: 0;
height: 0; height: 0;
} }
/* 卡片通用 */
.card {
background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: var(--radius-lg);
backdrop-filter: blur(var(--blur-bg));
-webkit-backdrop-filter: blur(var(--blur-bg));
transition: all var(--transition-normal);
}
.gradient-brand {
background: linear-gradient(135deg, var(--color-brand), var(--color-brand-light));
}
.gradient-text {
background: linear-gradient(135deg, var(--color-brand-light), var(--color-brand));
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
</style> </style>
@@ -178,7 +178,7 @@ function formatDate(dateStr) {
.title { .title {
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
color: #fff; color: var(--text-primary);
} }
.unlock-count { .unlock-count {
@@ -240,7 +240,7 @@ function formatDate(dateStr) {
.category-name { .category-name {
font-size: 15px; font-size: 15px;
color: #fff; color: var(--text-primary);
font-weight: 500; font-weight: 500;
flex: 1; flex: 1;
} }
@@ -237,7 +237,7 @@ function goShare() {
.chat-name { .chat-name {
font-size: 16px; font-size: 16px;
color: white; color: var(--text-primary);
font-weight: 600; font-weight: 600;
display: block; display: block;
} }
@@ -194,7 +194,7 @@ function goDetail(item) {
overflow: hidden; overflow: hidden;
} }
.dim-banner-icon { font-size: 28px; display: block; margin-bottom: 8px; } .dim-banner-icon { font-size: 28px; display: block; margin-bottom: 8px; }
.dim-banner-title { font-size: 22px; color: #fff; display: block; margin-bottom: 6px; } .dim-banner-title { font-size: 22px; color: var(--text-primary); display: block; margin-bottom: 6px; }
.dim-banner-desc { .dim-banner-desc {
font-size: 12px; font-size: 12px;
color: rgba(255,255,255,0.4); color: rgba(255,255,255,0.4);
@@ -134,7 +134,7 @@ function goHome() {
.title { .title {
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
color: #fff; color: var(--text-primary);
} }
.count-badge { .count-badge {
@@ -195,7 +195,7 @@ function goNewsDetail(item) {
} }
.brand-text .title { .brand-text .title {
font-size: 20px; font-size: 20px;
color: #fff; color: var(--text-primary);
font-weight: 700; font-weight: 700;
letter-spacing: 1px; letter-spacing: 1px;
} }
@@ -225,7 +225,7 @@ function goNewsDetail(item) {
} }
.greeting-title { .greeting-title {
font-size: 26px; font-size: 26px;
color: #fff; color: var(--text-primary);
font-weight: 700; font-weight: 700;
} }
.greeting-highlight { .greeting-highlight {
@@ -266,7 +266,7 @@ function goNewsDetail(item) {
} }
.section-title { .section-title {
font-size: 17px; font-size: 17px;
color: #fff; color: var(--text-primary);
font-weight: 600; font-weight: 600;
letter-spacing: 0.5px; letter-spacing: 0.5px;
} }
@@ -152,7 +152,7 @@ function dimDotColor(id) {
.title { .title {
font-size: 22px; font-size: 22px;
font-weight: 600; font-weight: 600;
color: #fff; color: var(--text-primary);
} }
// 维度切换 // 维度切换
@@ -178,7 +178,7 @@ function dimDotColor(id) {
.dim-tab.active { .dim-tab.active {
background: linear-gradient(135deg, rgba(179, 136, 255, 0.15), rgba(77, 182, 172, 0.15)); background: linear-gradient(135deg, rgba(179, 136, 255, 0.15), rgba(77, 182, 172, 0.15));
border-color: rgba(179, 136, 255, 0.3); border-color: rgba(179, 136, 255, 0.3);
color: #fff; color: var(--text-primary);
font-weight: 500; font-weight: 500;
} }
+104 -87
View File
@@ -14,18 +14,7 @@
<text class="app-title">宇之然 AI 维度</text> <text class="app-title">宇之然 AI 维度</text>
<text class="app-subtitle"> 5 个维度系统理解人工智能</text> <text class="app-subtitle"> 5 个维度系统理解人工智能</text>
<!-- 微信小程序登录 --> <!-- Tab 切换 两种模式共用 -->
<view class="login-method" v-if="isMiniApp">
<button class="wechat-btn" @click="wechatLogin">
<image class="wechat-icon" src="/static/icons/wechat.svg" mode="aspectFit" />
微信一键登录
</button>
<text class="login-tip">登录后即刻开启你的 AI 探索之旅</text>
</view>
<!-- H5 登录/注册 -->
<view class="h5-login" v-else>
<!-- Tab 切换 -->
<view class="tab-switch"> <view class="tab-switch">
<text class="tab-item" :class="{ active: activeTab === 'login' }" @click="activeTab = 'login'">登录</text> <text class="tab-item" :class="{ active: activeTab === 'login' }" @click="activeTab = 'login'">登录</text>
<text class="tab-item" :class="{ active: activeTab === 'register' }" @click="activeTab = 'register'">注册</text> <text class="tab-item" :class="{ active: activeTab === 'register' }" @click="activeTab = 'register'">注册</text>
@@ -41,24 +30,33 @@
<text class="form-label">密码</text> <text class="form-label">密码</text>
<input class="form-input" v-model="loginForm.password" type="password" placeholder="请输入密码" /> <input class="form-input" v-model="loginForm.password" type="password" placeholder="请输入密码" />
</view> </view>
<button class="submit-btn" :loading="loading" @click="handleLogin"> </button> <view class="submit-btn" :class="{ loading: loading }" @click="handleLogin">
<text>{{ loading ? '登录中...' : '登录' }}</text>
</view>
<!-- 微信小程序一键登录入口 -->
<view class="wx-login-row" v-if="isMiniApp">
<view class="wx-login-btn" @click="wechatLogin">
<text>微信一键登录</text>
</view>
</view>
</view> </view>
<!-- 注册表单 --> <!-- 注册表单 -->
<view class="form-card" v-else> <view class="form-card" v-if="activeTab === 'register'">
<view class="form-item"> <view class="form-item">
<text class="form-label">用户名</text> <text class="form-label">用户名</text>
<input class="form-input" v-model="registerForm.username" placeholder="3-20 位字符" /> <input class="form-input" v-model="registerForm.username" placeholder="3-20 位字符" />
</view> </view>
<view class="form-item"> <view class="form-item">
<text class="form-label">昵称</text> <text class="form-label">昵称</text>
<input class="form-input" v-model="registerForm.nickName" placeholder="显示名称" /> <input class="form-input" v-model="registerForm.nickName" placeholder="显示名称(选填)" />
</view> </view>
<view class="form-item"> <view class="form-item">
<text class="form-label">密码</text> <text class="form-label">密码</text>
<input class="form-input" v-model="registerForm.password" type="password" placeholder="至少 6 位" /> <input class="form-input" v-model="registerForm.password" type="password" placeholder="至少 6 位" />
</view> </view>
<button class="submit-btn" :loading="loading" @click="handleRegister"> </button> <view class="submit-btn" :class="{ loading: loading }" @click="handleRegister">
<text>{{ loading ? '注册中...' : '注册' }}</text>
</view> </view>
</view> </view>
@@ -71,15 +69,19 @@
</template> </template>
<script setup> <script setup>
import { ref, computed } from 'vue' import { ref } from 'vue'
import { useUserStore } from '@/stores/index' import { useUserStore } from '@/stores/index'
const isMiniApp = ref(false)
// 检测是否为微信小程序环境 // 检测是否为微信小程序环境
const isMiniApp = ref(false)
const platform = uni.getSystemInfoSync().platform
try { try {
isMiniApp.value = !!uni.getSystemInfoSync().brand && const sysInfo = uni.getSystemInfoSync()
(uni.getSystemInfoSync().platform === 'devtools' || // 小程序环境:platform 为 ios/android/devtools,且有 brand/version 等字段
(typeof wx !== 'undefined' && wx.getSystemInfoSync)) if (sysInfo && sysInfo.version && sysInfo.platform) {
// 有 weixin 特有字段即为小程序
isMiniApp.value = true
}
} catch (e) { } catch (e) {
// H5 环境 // H5 环境
} }
@@ -94,11 +96,9 @@ const registerForm = ref({ username: '', password: '', nickName: '' })
/** /**
* 微信小程序登录 * 微信小程序登录
* 调用 wx.login 获取 code → 后端 code2Session → 获取 token
*/ */
const wechatLogin = async () => { const wechatLogin = async () => {
try { try {
// 获取微信登录 code
const loginRes = await new Promise((resolve, reject) => { const loginRes = await new Promise((resolve, reject) => {
uni.login({ uni.login({
success: resolve, success: resolve,
@@ -114,7 +114,6 @@ const wechatLogin = async () => {
loading.value = true loading.value = true
await userStore.login(loginRes.code, {}) await userStore.login(loginRes.code, {})
// 登录成功,跳转首页
uni.showToast({ title: '登录成功', icon: 'success' }) uni.showToast({ title: '登录成功', icon: 'success' })
setTimeout(() => { setTimeout(() => {
uni.switchTab({ url: '/pages/index/index' }) uni.switchTab({ url: '/pages/index/index' })
@@ -186,18 +185,19 @@ const handleRegister = async () => {
.login-page { .login-page {
position: relative; position: relative;
width: 100%; width: 100%;
height: 100vh; min-height: 100vh;
overflow: hidden; overflow: hidden;
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
background: var(--bg-primary);
// 背景装饰光球 // 背景装饰光球
.bg-orb { .bg-orb {
position: absolute; position: absolute;
border-radius: 50%; border-radius: 50%;
filter: blur(60px); filter: blur(60px);
opacity: 0.4; opacity: 0.3;
pointer-events: none; pointer-events: none;
} }
.orb-1 { .orb-1 {
@@ -220,7 +220,8 @@ const handleRegister = async () => {
position: relative; position: relative;
z-index: 1; z-index: 1;
width: 100%; width: 100%;
padding: 0 40px; max-width: 360px;
padding: 0 32px;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
align-items: center; align-items: center;
@@ -229,16 +230,16 @@ const handleRegister = async () => {
// Logo // Logo
.logo-wrap { .logo-wrap {
position: relative; position: relative;
width: 80px; width: 72px;
height: 80px; height: 72px;
margin-bottom: 20px; margin-bottom: 16px;
.logo-ring { .logo-ring {
position: absolute; position: absolute;
inset: 0; inset: 0;
border-radius: 20px; border-radius: 18px;
background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color)); background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color));
box-shadow: 0 8px 32px rgba(179, 136, 255, 0.3); box-shadow: 0 8px 32px rgba(124, 77, 255, 0.2);
} }
.logo-text { .logo-text {
position: absolute; position: absolute;
@@ -246,83 +247,58 @@ const handleRegister = async () => {
display: flex; display: flex;
align-items: center; align-items: center;
justify-content: center; justify-content: center;
font-size: 32px; font-size: 28px;
font-weight: 700; font-weight: 700;
color: white; color: white;
} }
} }
.app-title { .app-title {
font-size: 28px; font-size: 24px;
font-weight: 700; font-weight: 700;
color: var(--text-primary); color: var(--text-primary);
letter-spacing: 2px; letter-spacing: 1px;
margin-bottom: 8px; margin-bottom: 6px;
} }
.app-subtitle { .app-subtitle {
font-size: 14px; font-size: 13px;
color: var(--text-secondary); color: var(--text-secondary);
margin-bottom: 40px; margin-bottom: 32px;
} }
// 微信登录按钮 // Tab 切换
.wechat-btn {
width: 80%;
height: 50px;
display: flex;
align-items: center;
justify-content: center;
gap: 10px;
background: linear-gradient(135deg, #07c160, #06ad56);
color: white;
border: none;
border-radius: 12px;
font-size: 16px;
font-weight: 600;
box-shadow: 0 4px 16px rgba(7, 193, 96, 0.3);
.wechat-icon {
width: 22px;
height: 22px;
}
}
.login-tip {
font-size: 12px;
color: var(--text-secondary);
margin-top: 16px;
}
// H5 登录
.h5-login {
width: 80%;
max-width: 320px;
.tab-switch { .tab-switch {
display: flex; display: flex;
width: 100%;
margin-bottom: 20px; margin-bottom: 20px;
border-bottom: 1px solid var(--glass-border);
.tab-item { .tab-item {
flex: 1; flex: 1;
text-align: center; text-align: center;
padding: 10px; padding: 10px 0;
color: var(--text-secondary); color: var(--text-secondary);
font-size: 15px; font-size: 15px;
font-weight: 500;
border-bottom: 2px solid transparent; border-bottom: 2px solid transparent;
transition: all 0.3s; transition: all 0.3s;
&.active { &.active {
color: var(--dim1-color); color: var(--color-brand);
border-bottom-color: var(--dim1-color); border-bottom-color: var(--color-brand);
} }
} }
} }
// 表单卡片
.form-card { .form-card {
background: rgba(255, 255, 255, 0.04); width: 100%;
border: 1px solid rgba(255, 255, 255, 0.08); background: var(--glass-bg);
border: 1px solid var(--glass-border);
border-radius: 16px; border-radius: 16px;
padding: 24px 20px; padding: 24px 20px;
backdrop-filter: blur(20px); backdrop-filter: blur(20px);
-webkit-backdrop-filter: blur(20px);
} }
.form-item { .form-item {
@@ -333,17 +309,19 @@ const handleRegister = async () => {
font-size: 13px; font-size: 13px;
color: var(--text-secondary); color: var(--text-secondary);
margin-bottom: 6px; margin-bottom: 6px;
font-weight: 500;
} }
.form-input { .form-input {
width: 100%; width: 100%;
height: 42px; height: 44px;
background: rgba(255, 255, 255, 0.06); background: var(--bg-secondary);
border: 1px solid rgba(255, 255, 255, 0.1); border: 1px solid var(--glass-border);
border-radius: 8px; border-radius: 10px;
padding: 0 14px; padding: 0 14px;
color: var(--text-primary); color: var(--text-primary);
font-size: 14px; font-size: 14px;
box-sizing: border-box; box-sizing: border-box;
outline: none;
&::placeholder { &::placeholder {
color: var(--text-disabled); color: var(--text-disabled);
@@ -351,25 +329,64 @@ const handleRegister = async () => {
} }
} }
// 提交按钮
.submit-btn { .submit-btn {
width: 100%; width: 100%;
height: 44px; height: 46px;
background: linear-gradient(135deg, var(--dim1-color), var(--dim3-color)); display: flex;
align-items: center;
justify-content: center;
background: linear-gradient(135deg, var(--color-brand), var(--dim3-color));
color: white; color: white;
border: none; border-radius: 10px;
border-radius: 8px;
font-size: 15px; font-size: 15px;
font-weight: 600; font-weight: 600;
margin-top: 8px; margin-top: 8px;
box-shadow: 0 4px 16px rgba(179, 136, 255, 0.25); cursor: pointer;
box-shadow: 0 4px 16px rgba(124, 77, 255, 0.25);
transition: opacity 0.3s;
&:active {
opacity: 0.8;
}
&.loading {
opacity: 0.7;
} }
} }
// 微信一键登录
.wx-login-row {
margin-top: 16px;
padding-top: 16px;
border-top: 1px solid var(--glass-border);
display: flex;
justify-content: center;
.wx-login-btn {
padding: 10px 28px;
display: flex;
align-items: center;
justify-content: center;
gap: 8px;
background: linear-gradient(135deg, #07c160, #06ad56);
color: white;
border-radius: 10px;
font-size: 14px;
font-weight: 600;
cursor: pointer;
box-shadow: 0 4px 16px rgba(7, 193, 96, 0.3);
&:active {
opacity: 0.8;
}
}
}
// 底部信息
.footer-info { .footer-info {
position: absolute; margin-top: 40px;
bottom: 40px;
font-size: 11px; font-size: 11px;
color: var(--text-disabled); color: var(--text-muted);
} }
} }
</style> </style>
@@ -206,7 +206,7 @@ onMounted(() => {
.nav-title { .nav-title {
font-size: 16px; font-size: 16px;
font-weight: 600; font-weight: 600;
color: #fff; color: var(--text-primary);
} }
.nav-share { font-size: 22px; color: rgba(255,255,255,0.5); } .nav-share { font-size: 22px; color: rgba(255,255,255,0.5); }
@@ -246,7 +246,7 @@ onMounted(() => {
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
line-height: 1.45; line-height: 1.45;
color: #fff; color: var(--text-primary);
margin: 12px 20px 16px; margin: 12px 20px 16px;
} }
@@ -223,7 +223,7 @@ function goBack() {
.header-title { .header-title {
font-size: 22px; font-size: 22px;
font-weight: 700; font-weight: 700;
color: white; color: var(--text-primary);
display: block; display: block;
} }
@@ -264,7 +264,7 @@ function goBack() {
.plan-name { .plan-name {
font-size: 18px; font-size: 18px;
font-weight: 700; font-weight: 700;
color: white; color: var(--text-primary);
display: block; display: block;
margin-bottom: 6px; margin-bottom: 6px;
} }
@@ -318,7 +318,7 @@ function goSettings() {
.profile-name { .profile-name {
font-size: 18px; font-size: 18px;
color: white; color: var(--text-primary);
font-weight: 600; font-weight: 600;
display: block; display: block;
} }
@@ -348,7 +348,7 @@ function goSettings() {
.plan-title { .plan-title {
font-size: 16px; font-size: 16px;
color: white; color: var(--text-primary);
font-weight: 600; font-weight: 600;
display: block; display: block;
} }
@@ -8,18 +8,22 @@
<view class="card"> <view class="card">
<view class="setting-item" @click="togglePush"> <view class="setting-item" @click="togglePush">
<view class="s-icon" style="background:rgba(255,213,79,0.1);color:#ffd54f">🔔</view> <view class="s-icon" style="background:rgba(255,213,79,0.1);color:#ffd54f">🔔</view>
<view class="s-text">
<text class="s-label">推送通知</text> <text class="s-label">推送通知</text>
<text class="s-desc">接收每日 AI 趋势推送</text> <text class="s-desc">接收每日 AI 趋势推送</text>
</view>
<view class="s-switch" :class="{ active: pushOn }"> <view class="s-switch" :class="{ active: pushOn }">
<view class="s-switch-knob" :class="{ on: pushOn }"></view> <view class="s-switch-knob" :class="{ on: pushOn }"></view>
</view> </view>
</view> </view>
<view class="setting-item"> <view class="setting-item" @click="toggleDarkMode">
<view class="s-icon" style="background:rgba(77,208,225,0.1);color:#4dd0e1">🌙</view> <view class="s-icon" style="background:rgba(77,208,225,0.1);color:#4dd0e1">🌙</view>
<text class="s-label">深色模式</text> <view class="s-text">
<text class="s-desc">当前已启用暗色风格</text> <text class="s-label">暗色模式</text>
<view class="s-switch active"> <text class="s-desc">{{ darkMode ? '已开启暗色风格' : '当前为亮色风格' }}</text>
<view class="s-switch-knob on"></view> </view>
<view class="s-switch" :class="{ active: darkMode }">
<view class="s-switch-knob" :class="{ on: darkMode }"></view>
</view> </view>
</view> </view>
</view> </view>
@@ -29,18 +33,24 @@
<view class="card"> <view class="card">
<view class="setting-item" @click="showAbout"> <view class="setting-item" @click="showAbout">
<view class="s-icon" style="background:rgba(179,136,255,0.1);color:#b388ff"></view> <view class="s-icon" style="background:rgba(179,136,255,0.1);color:#b388ff"></view>
<view class="s-text">
<text class="s-label">关于宇之然AI维度</text> <text class="s-label">关于宇之然AI维度</text>
</view>
<text class="s-arrow"></text> <text class="s-arrow"></text>
</view> </view>
<view class="setting-item" @click="showContact"> <view class="setting-item" @click="showContact">
<view class="s-icon" style="background:rgba(102,187,106,0.1);color:#66bb6a">📧</view> <view class="s-icon" style="background:rgba(102,187,106,0.1);color:#66bb6a">📧</view>
<view class="s-text">
<text class="s-label">联系方式</text> <text class="s-label">联系方式</text>
<text class="s-desc">客服邮箱support@yuzhiran.com</text> <text class="s-desc">客服邮箱support@yuzhiran.com</text>
</view>
<text class="s-arrow"></text> <text class="s-arrow"></text>
</view> </view>
<view class="setting-item" @click="showAgreement"> <view class="setting-item" @click="showAgreement">
<view class="s-icon" style="background:rgba(239,83,80,0.1);color:#ef5350">📄</view> <view class="s-icon" style="background:rgba(239,83,80,0.1);color:#ef5350">📄</view>
<view class="s-text">
<text class="s-label">用户协议 / 隐私政策</text> <text class="s-label">用户协议 / 隐私政策</text>
</view>
<text class="s-arrow"></text> <text class="s-arrow"></text>
</view> </view>
</view> </view>
@@ -50,9 +60,15 @@
</template> </template>
<script setup> <script setup>
import { ref } from 'vue' import { ref, onMounted } from 'vue'
const pushOn = ref(true) const pushOn = ref(true)
const darkMode = ref(false)
onMounted(() => {
// 读取当前主题
darkMode.value = uni.getStorageSync('theme') === 'dark'
})
function togglePush() { function togglePush() {
pushOn.value = !pushOn.value pushOn.value = !pushOn.value
@@ -62,6 +78,32 @@ function togglePush() {
}) })
} }
function toggleDarkMode() {
darkMode.value = !darkMode.value
const theme = darkMode.value ? 'dark' : 'light'
uni.setStorageSync('theme', theme)
applyTheme(theme)
uni.showToast({
title: darkMode.value ? '已切换为暗色模式' : '已切换为亮色模式',
icon: 'none'
})
}
function applyTheme(theme) {
try {
const root = document.documentElement
if (theme === 'dark') {
root.classList.add('theme-dark')
root.classList.remove('theme-light')
} else {
root.classList.remove('theme-dark')
root.classList.add('theme-light')
}
} catch (e) {
// mini-program 忽略
}
}
function showAbout() { function showAbout() {
uni.showModal({ uni.showModal({
title: '关于「宇之然AI维度」', title: '关于「宇之然AI维度」',
@@ -98,7 +140,7 @@ function showAgreement() {
.page-title { .page-title {
font-size: 22px; font-size: 22px;
color: white; color: var(--text-primary);
font-weight: 600; font-weight: 600;
display: block; display: block;
margin: 6px 0 22px; margin: 6px 0 22px;
@@ -106,15 +148,14 @@ function showAgreement() {
.section-title { .section-title {
font-size: 12px; font-size: 12px;
color: rgba(255,255,255,0.3); color: var(--text-muted);
margin: 18px 0 10px; margin: 18px 0 10px;
text-transform: uppercase;
letter-spacing: 1px; letter-spacing: 1px;
} }
.card { .card {
background: rgba(255,255,255,0.03); background: var(--glass-bg);
border: 1px solid rgba(255,255,255,0.06); border: 1px solid var(--glass-border);
border-radius: 14px; border-radius: 14px;
padding: 4px 16px; padding: 4px 16px;
} }
@@ -124,7 +165,7 @@ function showAgreement() {
align-items: center; align-items: center;
gap: 14px; gap: 14px;
padding: 14px 0; padding: 14px 0;
border-bottom: 1px solid rgba(255,255,255,0.04); border-bottom: 1px solid var(--glass-border);
} }
.setting-item:last-child { border-bottom: none; } .setting-item:last-child { border-bottom: none; }
@@ -139,25 +180,27 @@ function showAgreement() {
flex-shrink: 0; flex-shrink: 0;
} }
.s-label { .s-text {
flex: 1; flex: 1;
display: flex;
flex-direction: column;
gap: 2px;
}
.s-label {
font-size: 14px; font-size: 14px;
color: rgba(255,255,255,0.85); color: var(--text-primary);
display: block;
} }
.s-desc { .s-desc {
font-size: 11px; font-size: 11px;
color: rgba(255,255,255,0.35); color: var(--text-tertiary);
display: block;
margin-top: 3px;
line-height: 1.3; line-height: 1.3;
flex: 1;
} }
.s-arrow { .s-arrow {
font-size: 14px; font-size: 14px;
color: rgba(255,255,255,0.15); color: var(--text-muted);
} }
// 开关 // 开关
@@ -165,13 +208,13 @@ function showAgreement() {
width: 44px; width: 44px;
height: 24px; height: 24px;
border-radius: 12px; border-radius: 12px;
background: rgba(255,255,255,0.1); background: rgba(0, 0, 0, 0.1);
position: relative; position: relative;
flex-shrink: 0; flex-shrink: 0;
transition: background 0.3s; transition: background 0.3s;
} }
.s-switch.active { .s-switch.active {
background: rgba(179,136,255,0.4); background: rgba(124, 77, 255, 0.4);
} }
.s-switch-knob { .s-switch-knob {
width: 20px; width: 20px;
@@ -182,13 +225,14 @@ function showAgreement() {
top: 2px; top: 2px;
left: 2px; left: 2px;
transition: left 0.3s; transition: left 0.3s;
box-shadow: 0 1px 3px rgba(0,0,0,0.2);
} }
.s-switch-knob.on { left: 22px; } .s-switch-knob.on { left: 22px; }
.version { .version {
text-align: center; text-align: center;
font-size: 11px; font-size: 11px;
color: rgba(255,255,255,0.1); color: var(--text-muted);
margin-top: 30px; margin-top: 30px;
display: block; display: block;
} }
@@ -199,7 +199,7 @@ function getSampleData() {
.header-title { .header-title {
font-size: 24px; font-size: 24px;
font-weight: 700; font-weight: 700;
color: white; color: var(--text-primary);
display: block; display: block;
} }
+18 -118
View File
@@ -1,127 +1,27 @@
/* ============================================ /* ============================================
宇之然AI维度 — 主题系统 v2 宇之然AI维度 — 主题系统 v3
使用 CSS 自定义属性,一键切换主题 亮色默认 + CSS 自定义属性切换
============================================ */ ============================================ */
/* ---- 主题色板 ---- /*
🌌 宇宙深空:深紫黑渐变背景 * 注意: 此文件通过 uni.scss 注入到每个组件
🟣 紫 — 品牌色、AI 起源 * 但全局 CSS 变量定义在 App.vue 的非 scoped <style> 中
🔵 青 — AI 发展、科技 * 此文件只保留 SCSS 变量 + 工具类,防止重复
🟢 青绿 — AI 当前 */
🟡 金 — AI 学习
🔴 珊瑚 — AI 趋势
============================================ */
:root, /* ---- SCSS 变量(方便组件内使用) ---- */
page { $color-brand: #7c4dff;
/* === 基础色 — 深空紫黑 === */ $color-brand-light: #b388ff;
--bg-primary: #14141e; $color-bg-primary: #f5f5f7;
--bg-secondary: #181828; $color-bg-dark: #14141e;
--bg-tertiary: #1c1a34;
/* === 玻璃拟态 — 足够可见 === */ $dim1-color: #7c4dff;
--glass-bg: rgba(255, 255, 255, 0.06); $dim2-color: #0ea5e9;
--glass-border: rgba(255, 255, 255, 0.08); $dim3-color: #10b981;
--glass-hover: rgba(255, 255, 255, 0.1); $dim4-color: #f59e0b;
--glass-hover-border: rgba(255, 255, 255, 0.15); $dim5-color: #ef4444;
--glass-strong: rgba(255, 255, 255, 0.12);
--glass-dim-bg: rgba(124, 77, 255, 0.06);
/* === 文字 — 更清晰的分层 === */
--text-primary: rgba(255, 255, 255, 0.95);
--text-secondary: rgba(255, 255, 255, 0.7);
--text-tertiary: rgba(255, 255, 255, 0.5);
--text-muted: rgba(255, 255, 255, 0.3);
/* === 品牌色 — 紫色系 === */
--color-brand: #8b5cf6;
--color-brand-light: #a78bfa;
--color-brand-dark: #7c3aed;
--color-brand-bg: rgba(139, 92, 246, 0.12);
--color-brand-glow: rgba(139, 92, 246, 0.15);
/* === 维度色系 — 更饱和 === */
/* dim1: AI 起源 — 紫罗兰 */
--dim1-color: #a78bfa;
--dim1-bg: rgba(139, 92, 246, 0.12);
--dim1-icon-bg: rgba(139, 92, 246, 0.2);
--dim1-border: rgba(139, 92, 246, 0.18);
--dim1-glow: rgba(139, 92, 246, 0.08);
/* dim2: AI 发展 — 天蓝 */
--dim2-color: #60a5fa;
--dim2-bg: rgba(96, 165, 250, 0.12);
--dim2-icon-bg: rgba(96, 165, 250, 0.2);
--dim2-border: rgba(96, 165, 250, 0.18);
--dim2-glow: rgba(96, 165, 250, 0.08);
/* dim3: AI 当前 — 翠绿 */
--dim3-color: #34d399;
--dim3-bg: rgba(52, 211, 153, 0.12);
--dim3-icon-bg: rgba(52, 211, 153, 0.2);
--dim3-border: rgba(52, 211, 153, 0.18);
--dim3-glow: rgba(52, 211, 153, 0.08);
/* dim4: AI 学习 — 琥珀金 */
--dim4-color: #fbbf24;
--dim4-bg: rgba(251, 191, 36, 0.12);
--dim4-icon-bg: rgba(251, 191, 36, 0.2);
--dim4-border: rgba(251, 191, 36, 0.18);
--dim4-glow: rgba(251, 191, 36, 0.08);
/* dim5: AI 趋势 — 玫瑰红 */
--dim5-color: #fb7185;
--dim5-bg: rgba(251, 113, 133, 0.12);
--dim5-icon-bg: rgba(251, 113, 133, 0.2);
--dim5-border: rgba(251, 113, 133, 0.18);
--dim5-glow: rgba(251, 113, 133, 0.08);
/* === 功能色 === */
--color-free: #34d399;
--color-free-bg: rgba(52, 211, 153, 0.12);
--color-pro: #fbbf24;
--color-pro-bg: rgba(251, 191, 36, 0.12);
--color-vip: #fb7185;
--color-vip-bg: rgba(251, 113, 133, 0.12);
--color-hot: #fb7185;
--color-hot-bg: rgba(251, 113, 133, 0.15);
--color-new: #60a5fa;
--color-new-bg: rgba(96, 165, 250, 0.15);
--color-pick: #a78bfa;
--color-pick-bg: rgba(139, 92, 246, 0.15);
/* === 圆角 === */
--radius-sm: 8px;
--radius-md: 12px;
--radius-lg: 16px;
--radius-xl: 20px;
--radius-full: 9999px;
/* === 间距 === */
--spacing-xs: 4px;
--spacing-sm: 8px;
--spacing-md: 12px;
--spacing-lg: 16px;
--spacing-xl: 20px;
--spacing-2xl: 24px;
/* === 玻璃模糊 === */
--blur-bg: 20px;
/* === 过渡 === */
--transition-fast: 0.2s ease;
--transition-normal: 0.3s ease;
/* === 辉光 === */
--glow-brand: 0 0 20px rgba(139, 92, 246, 0.1);
--glow-brand-strong: 0 0 30px rgba(139, 92, 246, 0.15);
}
/* ============================================
全局排版
============================================ */
/* 全局排版 */
page { page {
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale; -moz-osx-font-smoothing: grayscale;