✨ 添加主题切换功能:支持暗色/亮色玻璃主题
功能说明: - 管理员可在系统设置中配置全局默认主题 - 普通用户可在设置页面选择:跟随全局/暗色/亮色 - 分享页面自动继承分享者的主题偏好 - 主题设置实时保存,刷新后保持 技术实现: - 后端:数据库添加theme_preference字段,新增主题API - 前端:CSS变量实现主题切换,localStorage缓存避免闪烁 - 分享页:加载时获取分享者主题设置 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -446,7 +446,7 @@ const ShareDB = {
|
||||
});
|
||||
|
||||
const result = db.prepare(`
|
||||
SELECT s.*, u.username, u.ftp_host, u.ftp_port, u.ftp_user, u.ftp_password, u.http_download_base_url
|
||||
SELECT s.*, u.username, u.ftp_host, u.ftp_port, u.ftp_user, u.ftp_password, u.http_download_base_url, u.theme_preference
|
||||
FROM shares s
|
||||
JOIN users u ON s.user_id = u.id
|
||||
WHERE s.share_code = ?
|
||||
@@ -616,6 +616,26 @@ function initDefaultSettings() {
|
||||
if (!SettingsDB.get('max_upload_size')) {
|
||||
SettingsDB.set('max_upload_size', '10737418240'); // 10GB in bytes
|
||||
}
|
||||
// 默认全局主题为暗色
|
||||
if (!SettingsDB.get('global_theme')) {
|
||||
SettingsDB.set('global_theme', 'dark');
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库迁移 - 主题偏好字段
|
||||
function migrateThemePreference() {
|
||||
try {
|
||||
const columns = db.prepare("PRAGMA table_info(users)").all();
|
||||
const hasThemePreference = columns.some(col => col.name === 'theme_preference');
|
||||
|
||||
if (!hasThemePreference) {
|
||||
console.log('[数据库迁移] 添加主题偏好字段...');
|
||||
db.exec(`ALTER TABLE users ADD COLUMN theme_preference TEXT DEFAULT NULL`);
|
||||
console.log('[数据库迁移] ✓ 主题偏好字段已添加');
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('[数据库迁移] 主题偏好迁移失败:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// 数据库版本迁移 - v2.0 本地存储功能
|
||||
@@ -798,6 +818,7 @@ initDatabase();
|
||||
createDefaultAdmin();
|
||||
initDefaultSettings();
|
||||
migrateToV2(); // 执行数据库迁移
|
||||
migrateThemePreference(); // 主题偏好迁移
|
||||
|
||||
module.exports = {
|
||||
db,
|
||||
|
||||
@@ -1628,6 +1628,56 @@ app.get('/api/user/profile', authMiddleware, (req, res) => {
|
||||
});
|
||||
});
|
||||
|
||||
// 获取用户主题偏好(包含全局默认主题)
|
||||
app.get('/api/user/theme', authMiddleware, (req, res) => {
|
||||
try {
|
||||
const globalTheme = SettingsDB.get('global_theme') || 'dark';
|
||||
const userTheme = req.user.theme_preference; // null表示跟随全局
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
theme: {
|
||||
global: globalTheme,
|
||||
user: userTheme,
|
||||
effective: userTheme || globalTheme // 用户设置优先,否则使用全局
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({ success: false, message: '获取主题失败' });
|
||||
}
|
||||
});
|
||||
|
||||
// 设置用户主题偏好
|
||||
app.post('/api/user/theme', authMiddleware, (req, res) => {
|
||||
try {
|
||||
const { theme } = req.body;
|
||||
const validThemes = ['dark', 'light', null]; // null表示跟随全局
|
||||
|
||||
if (!validThemes.includes(theme)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的主题设置,可选: dark, light, null(跟随全局)'
|
||||
});
|
||||
}
|
||||
|
||||
UserDB.update(req.user.id, { theme_preference: theme });
|
||||
|
||||
const globalTheme = SettingsDB.get('global_theme') || 'dark';
|
||||
res.json({
|
||||
success: true,
|
||||
message: '主题偏好已更新',
|
||||
theme: {
|
||||
global: globalTheme,
|
||||
user: theme,
|
||||
effective: theme || globalTheme
|
||||
}
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('更新主题失败:', error);
|
||||
res.status(500).json({ success: false, message: '更新主题失败' });
|
||||
}
|
||||
});
|
||||
|
||||
// 更新FTP配置
|
||||
app.post('/api/user/update-ftp',
|
||||
authMiddleware,
|
||||
@@ -2888,6 +2938,44 @@ app.delete('/api/share/:id', authMiddleware, (req, res) => {
|
||||
|
||||
// ===== 分享链接访问(公开) =====
|
||||
|
||||
// 获取公共主题设置(用于分享页面,无需认证)
|
||||
app.get('/api/public/theme', (req, res) => {
|
||||
try {
|
||||
const globalTheme = SettingsDB.get('global_theme') || 'dark';
|
||||
res.json({
|
||||
success: true,
|
||||
theme: globalTheme
|
||||
});
|
||||
} catch (error) {
|
||||
res.json({ success: true, theme: 'dark' }); // 出错默认暗色
|
||||
}
|
||||
});
|
||||
|
||||
// 获取分享页面主题(基于分享者偏好或全局设置)
|
||||
app.get('/api/share/:code/theme', (req, res) => {
|
||||
try {
|
||||
const { code } = req.params;
|
||||
const share = ShareDB.findByCode(code);
|
||||
const globalTheme = SettingsDB.get('global_theme') || 'dark';
|
||||
|
||||
if (!share) {
|
||||
return res.json({
|
||||
success: true,
|
||||
theme: globalTheme
|
||||
});
|
||||
}
|
||||
|
||||
// 优先使用分享者的主题偏好,否则使用全局主题
|
||||
const effectiveTheme = share.theme_preference || globalTheme;
|
||||
res.json({
|
||||
success: true,
|
||||
theme: effectiveTheme
|
||||
});
|
||||
} catch (error) {
|
||||
res.json({ success: true, theme: 'dark' });
|
||||
}
|
||||
});
|
||||
|
||||
// 访问分享链接 - 验证密码(支持本地存储和SFTP)
|
||||
app.post('/api/share/:code/verify', shareRateLimitMiddleware, async (req, res) => {
|
||||
const { code } = req.params;
|
||||
@@ -3418,11 +3506,13 @@ app.get('/api/admin/settings', authMiddleware, adminMiddleware, (req, res) => {
|
||||
const smtpUser = SettingsDB.get('smtp_user');
|
||||
const smtpFrom = SettingsDB.get('smtp_from') || smtpUser;
|
||||
const smtpHasPassword = !!SettingsDB.get('smtp_password');
|
||||
const globalTheme = SettingsDB.get('global_theme') || 'dark';
|
||||
|
||||
res.json({
|
||||
success: true,
|
||||
settings: {
|
||||
max_upload_size: maxUploadSize,
|
||||
global_theme: globalTheme,
|
||||
smtp: {
|
||||
host: smtpHost || '',
|
||||
port: smtpPort ? parseInt(smtpPort, 10) : 465,
|
||||
@@ -3445,7 +3535,7 @@ app.get('/api/admin/settings', authMiddleware, adminMiddleware, (req, res) => {
|
||||
// 更新系统设置
|
||||
app.post('/api/admin/settings', authMiddleware, adminMiddleware, (req, res) => {
|
||||
try {
|
||||
const { max_upload_size, smtp } = req.body;
|
||||
const { max_upload_size, smtp, global_theme } = req.body;
|
||||
|
||||
if (max_upload_size !== undefined) {
|
||||
const size = parseInt(max_upload_size);
|
||||
@@ -3458,6 +3548,18 @@ app.post('/api/admin/settings', authMiddleware, adminMiddleware, (req, res) => {
|
||||
SettingsDB.set('max_upload_size', size.toString());
|
||||
}
|
||||
|
||||
// 更新全局主题
|
||||
if (global_theme !== undefined) {
|
||||
const validThemes = ['dark', 'light'];
|
||||
if (!validThemes.includes(global_theme)) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '无效的主题设置'
|
||||
});
|
||||
}
|
||||
SettingsDB.set('global_theme', global_theme);
|
||||
}
|
||||
|
||||
if (smtp) {
|
||||
if (!smtp.host || !smtp.port || !smtp.user) {
|
||||
return res.status(400).json({ success: false, message: 'SMTP配置不完整' });
|
||||
|
||||
@@ -107,7 +107,7 @@
|
||||
<script src="libs/axios.min.js"></script>
|
||||
<link rel="stylesheet" href="libs/fontawesome/css/all.min.css">
|
||||
<style>
|
||||
/* ========== 暗色主题 CSS 变量 ========== */
|
||||
/* ========== 暗色主题 CSS 变量(默认) ========== */
|
||||
:root {
|
||||
--bg-primary: #0a0a0f;
|
||||
--bg-secondary: #12121a;
|
||||
@@ -128,6 +128,32 @@
|
||||
--info: #3b82f6;
|
||||
}
|
||||
|
||||
/* ========== 亮色玻璃主题 ========== */
|
||||
.light-theme {
|
||||
--bg-primary: #f0f4f8;
|
||||
--bg-secondary: #ffffff;
|
||||
--bg-card: rgba(255, 255, 255, 0.7);
|
||||
--bg-card-hover: rgba(255, 255, 255, 0.9);
|
||||
--glass-border: rgba(102, 126, 234, 0.2);
|
||||
--glass-border-hover: rgba(102, 126, 234, 0.4);
|
||||
--text-primary: #1a1a2e;
|
||||
--text-secondary: rgba(26, 26, 46, 0.7);
|
||||
--text-muted: rgba(26, 26, 46, 0.5);
|
||||
--accent-1: #5a67d8;
|
||||
--accent-2: #6b46c1;
|
||||
--accent-3: #d53f8c;
|
||||
--glow: rgba(90, 103, 216, 0.3);
|
||||
}
|
||||
|
||||
/* 亮色主题背景渐变 */
|
||||
.light-theme body::before,
|
||||
body.light-theme::before {
|
||||
background:
|
||||
radial-gradient(ellipse at top right, rgba(102, 126, 234, 0.12) 0%, transparent 50%),
|
||||
radial-gradient(ellipse at bottom left, rgba(118, 75, 162, 0.12) 0%, transparent 50%),
|
||||
linear-gradient(135deg, #e0e7ff 0%, #f0f4f8 50%, #fdf2f8 100%);
|
||||
}
|
||||
|
||||
/* 防止 Vue 初始化前显示原始模板 */
|
||||
[v-cloak] { display: none !important; }
|
||||
|
||||
@@ -1691,8 +1717,44 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 界面设置 -->
|
||||
<h3 style="margin: 40px 0 20px 0;"><i class="fas fa-palette"></i> 界面设置</h3>
|
||||
<div style="background: var(--bg-card); padding: 20px; border-radius: 12px; border: 1px solid var(--glass-border); margin-bottom: 30px;">
|
||||
<div style="margin-bottom: 15px;">
|
||||
<span style="font-weight: 600; color: var(--text-primary);">主题模式</span>
|
||||
<span style="color: var(--text-secondary); font-size: 13px; margin-left: 10px;">选择你喜欢的界面风格</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 12px; flex-wrap: wrap;">
|
||||
<button
|
||||
class="btn"
|
||||
:class="userThemePreference === null ? 'btn-primary' : 'btn-secondary'"
|
||||
@click="setUserTheme(null)"
|
||||
style="flex: 1; min-width: 120px; padding: 12px 16px;">
|
||||
<i class="fas fa-globe"></i> 跟随全局
|
||||
<span v-if="userThemePreference === null" style="margin-left: 8px; font-size: 12px; opacity: 0.8;">({{ globalTheme === 'dark' ? '暗色' : '亮色' }})</span>
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
:class="userThemePreference === 'dark' ? 'btn-primary' : 'btn-secondary'"
|
||||
@click="setUserTheme('dark')"
|
||||
style="flex: 1; min-width: 120px; padding: 12px 16px;">
|
||||
<i class="fas fa-moon"></i> 暗色主题
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
:class="userThemePreference === 'light' ? 'btn-primary' : 'btn-secondary'"
|
||||
@click="setUserTheme('light')"
|
||||
style="flex: 1; min-width: 120px; padding: 12px 16px;">
|
||||
<i class="fas fa-sun"></i> 亮色主题
|
||||
</button>
|
||||
</div>
|
||||
<div style="margin-top: 12px; font-size: 13px; color: var(--text-muted);">
|
||||
<i class="fas fa-info-circle"></i> 主题设置会影响你的文件页面和分享页面的外观
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 账号设置 -->
|
||||
<h3 style="margin: 40px 0 20px 0;">账号设置</h3>
|
||||
<h3 style="margin: 40px 0 20px 0;"><i class="fas fa-user-cog"></i> 账号设置</h3>
|
||||
|
||||
<!-- 管理员可以改用户名 -->
|
||||
<form v-if="user && user.is_admin" @submit.prevent="updateUsername" style="margin-bottom: 30px;">
|
||||
@@ -1970,8 +2032,35 @@
|
||||
</button>
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">修改后需要重启服务才能生效</span>
|
||||
</div>
|
||||
|
||||
<hr style="margin: 20px 0;">
|
||||
<h4 style="margin-bottom: 12px;">SMTP 邮件配置(用于注册激活和找回密码)</h4>
|
||||
<h4 style="margin-bottom: 12px;"><i class="fas fa-palette"></i> 全局主题设置</h4>
|
||||
<div style="margin-bottom: 15px;">
|
||||
<span style="color: var(--text-secondary); font-size: 13px;">设置系统默认主题,用户可以在个人设置中覆盖此设置</span>
|
||||
</div>
|
||||
<div style="display: flex; gap: 12px; flex-wrap: wrap; margin-bottom: 20px;">
|
||||
<button
|
||||
class="btn"
|
||||
:class="globalTheme === 'dark' ? 'btn-primary' : 'btn-secondary'"
|
||||
@click="setGlobalTheme('dark')"
|
||||
style="padding: 12px 24px;">
|
||||
<i class="fas fa-moon"></i> 暗色主题(默认)
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
:class="globalTheme === 'light' ? 'btn-primary' : 'btn-secondary'"
|
||||
@click="setGlobalTheme('light')"
|
||||
style="padding: 12px 24px;">
|
||||
<i class="fas fa-sun"></i> 亮色主题
|
||||
</button>
|
||||
</div>
|
||||
<div style="font-size: 13px; color: var(--text-muted); background: var(--bg-card); padding: 12px; border-radius: 8px; border: 1px solid var(--glass-border);">
|
||||
<i class="fas fa-info-circle"></i> 当前全局主题: <strong>{{ globalTheme === 'dark' ? '暗色' : '亮色' }}</strong>。
|
||||
未设置个人偏好的用户将使用此主题。分享页面也会默认使用分享者的主题设置。
|
||||
</div>
|
||||
|
||||
<hr style="margin: 20px 0;">
|
||||
<h4 style="margin-bottom: 12px;"><i class="fas fa-envelope"></i> SMTP 邮件配置(用于注册激活和找回密码)</h4>
|
||||
<div class="alert alert-info" style="margin-bottom: 15px;">
|
||||
支持 QQ/163/企业邮箱等。QQ 邮箱示例:主机 <code>smtp.qq.com</code>,端口 <code>465</code>,勾选 SSL,用户名=邮箱地址,密码=授权码。
|
||||
</div>
|
||||
|
||||
103
frontend/app.js
103
frontend/app.js
@@ -250,7 +250,12 @@ createApp({
|
||||
// SFTP空间使用统计
|
||||
sftpUsage: null, // { totalSize, totalSizeFormatted, fileCount, dirCount }
|
||||
sftpUsageLoading: false,
|
||||
sftpUsageError: null
|
||||
sftpUsageError: null,
|
||||
|
||||
// 主题设置
|
||||
currentTheme: 'dark', // 当前生效的主题: 'dark' 或 'light'
|
||||
globalTheme: 'dark', // 全局默认主题(管理员设置)
|
||||
userThemePreference: null // 用户主题偏好: 'dark', 'light', 或 null(跟随全局)
|
||||
};
|
||||
},
|
||||
|
||||
@@ -281,6 +286,91 @@ createApp({
|
||||
},
|
||||
|
||||
methods: {
|
||||
// ========== 主题管理 ==========
|
||||
// 初始化主题
|
||||
initTheme() {
|
||||
// 先从localStorage读取,避免页面闪烁
|
||||
const savedTheme = localStorage.getItem('theme');
|
||||
if (savedTheme) {
|
||||
this.applyTheme(savedTheme);
|
||||
}
|
||||
},
|
||||
|
||||
// 加载用户主题设置(登录后调用)
|
||||
async loadUserTheme() {
|
||||
try {
|
||||
const res = await axios.get(`${this.apiBase}/api/user/theme`, {
|
||||
headers: { Authorization: `Bearer ${this.token}` }
|
||||
});
|
||||
if (res.data.success) {
|
||||
this.globalTheme = res.data.theme.global;
|
||||
this.userThemePreference = res.data.theme.user;
|
||||
this.currentTheme = res.data.theme.effective;
|
||||
this.applyTheme(this.currentTheme);
|
||||
localStorage.setItem('theme', this.currentTheme);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('加载主题设置失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 应用主题到DOM
|
||||
applyTheme(theme) {
|
||||
this.currentTheme = theme;
|
||||
if (theme === 'light') {
|
||||
document.body.classList.add('light-theme');
|
||||
} else {
|
||||
document.body.classList.remove('light-theme');
|
||||
}
|
||||
},
|
||||
|
||||
// 切换用户主题偏好
|
||||
async setUserTheme(theme) {
|
||||
try {
|
||||
const res = await axios.post(`${this.apiBase}/api/user/theme`,
|
||||
{ theme },
|
||||
{ headers: { Authorization: `Bearer ${this.token}` }}
|
||||
);
|
||||
if (res.data.success) {
|
||||
this.userThemePreference = res.data.theme.user;
|
||||
this.currentTheme = res.data.theme.effective;
|
||||
this.applyTheme(this.currentTheme);
|
||||
localStorage.setItem('theme', this.currentTheme);
|
||||
this.showToast('success', '主题已更新', theme === null ? '已设为跟随全局' : (theme === 'dark' ? '已切换到暗色主题' : '已切换到亮色主题'));
|
||||
}
|
||||
} catch (error) {
|
||||
this.showToast('error', '主题更新失败', error.response?.data?.message || '请稍后重试');
|
||||
}
|
||||
},
|
||||
|
||||
// 获取主题显示文本
|
||||
getThemeText(theme) {
|
||||
if (theme === null) return '跟随全局';
|
||||
return theme === 'dark' ? '暗色主题' : '亮色主题';
|
||||
},
|
||||
|
||||
// 设置全局主题(管理员)
|
||||
async setGlobalTheme(theme) {
|
||||
try {
|
||||
const res = await axios.post(`${this.apiBase}/api/admin/settings`,
|
||||
{ global_theme: theme },
|
||||
{ headers: { Authorization: `Bearer ${this.token}` }}
|
||||
);
|
||||
if (res.data.success) {
|
||||
this.globalTheme = theme;
|
||||
// 如果用户没有设置个人偏好,则跟随全局
|
||||
if (this.userThemePreference === null) {
|
||||
this.currentTheme = theme;
|
||||
this.applyTheme(theme);
|
||||
localStorage.setItem('theme', theme);
|
||||
}
|
||||
this.showToast('success', '全局主题已更新', theme === 'dark' ? '默认暗色主题' : '默认亮色主题');
|
||||
}
|
||||
} catch (error) {
|
||||
this.showToast('error', '设置失败', error.response?.data?.message || '请稍后重试');
|
||||
}
|
||||
},
|
||||
|
||||
// 提取URL中的token(兼容缺少 ? 的场景)
|
||||
getTokenFromUrl(key) {
|
||||
const currentHref = window.location.href;
|
||||
@@ -438,6 +528,8 @@ handleDragLeave(e) {
|
||||
|
||||
// 启动定期检查用户配置
|
||||
this.startProfileSync();
|
||||
// 加载用户主题设置
|
||||
this.loadUserTheme();
|
||||
// 管理员直接跳转到管理后台
|
||||
if (this.user.is_admin) {
|
||||
this.currentView = 'admin';
|
||||
@@ -878,6 +970,8 @@ handleDragLeave(e) {
|
||||
|
||||
// 启动定期检查用户配置
|
||||
this.startProfileSync();
|
||||
// 加载用户主题设置
|
||||
this.loadUserTheme();
|
||||
|
||||
// 读取上次停留的视图(需合法才生效)
|
||||
const savedView = localStorage.getItem('lastView');
|
||||
@@ -2207,6 +2301,10 @@ handleDragLeave(e) {
|
||||
if (response.data.success) {
|
||||
const settings = response.data.settings;
|
||||
this.systemSettings.maxUploadSizeMB = Math.round(settings.max_upload_size / (1024 * 1024));
|
||||
// 加载全局主题设置
|
||||
if (settings.global_theme) {
|
||||
this.globalTheme = settings.global_theme;
|
||||
}
|
||||
if (settings.smtp) {
|
||||
this.systemSettings.smtp.host = settings.smtp.host || '';
|
||||
this.systemSettings.smtp.port = settings.smtp.port || 465;
|
||||
@@ -2584,6 +2682,9 @@ handleDragLeave(e) {
|
||||
// 初始化调试模式状态
|
||||
this.debugMode = localStorage.getItem('debugMode') === 'true';
|
||||
|
||||
// 初始化主题(从localStorage加载,避免闪烁)
|
||||
this.initTheme();
|
||||
|
||||
// 处理URL中的验证/重置token(兼容缺少?的旧链接)
|
||||
const verifyToken = this.getTokenFromUrl('verifyToken');
|
||||
const resetToken = this.getTokenFromUrl('resetToken');
|
||||
|
||||
@@ -11,7 +11,7 @@
|
||||
/* 防止 Vue 初始化前显示原始模板 */
|
||||
[v-cloak] { display: none !important; }
|
||||
|
||||
/* ========== 暗色主题 CSS 变量 ========== */
|
||||
/* ========== 暗色主题 CSS 变量(默认) ========== */
|
||||
:root {
|
||||
--bg-primary: #0a0a0f;
|
||||
--bg-secondary: #12121a;
|
||||
@@ -31,6 +31,31 @@
|
||||
--warning: #f59e0b;
|
||||
}
|
||||
|
||||
/* ========== 亮色玻璃主题 ========== */
|
||||
.light-theme {
|
||||
--bg-primary: #f0f4f8;
|
||||
--bg-secondary: #ffffff;
|
||||
--bg-card: rgba(255, 255, 255, 0.7);
|
||||
--bg-card-hover: rgba(255, 255, 255, 0.9);
|
||||
--glass-border: rgba(102, 126, 234, 0.2);
|
||||
--glass-border-hover: rgba(102, 126, 234, 0.4);
|
||||
--text-primary: #1a1a2e;
|
||||
--text-secondary: rgba(26, 26, 46, 0.7);
|
||||
--text-muted: rgba(26, 26, 46, 0.5);
|
||||
--accent-1: #5a67d8;
|
||||
--accent-2: #6b46c1;
|
||||
--accent-3: #d53f8c;
|
||||
--glow: rgba(90, 103, 216, 0.3);
|
||||
}
|
||||
|
||||
/* 亮色主题背景渐变 */
|
||||
body.light-theme::before {
|
||||
background:
|
||||
radial-gradient(ellipse at top right, rgba(102, 126, 234, 0.12) 0%, transparent 50%),
|
||||
radial-gradient(ellipse at bottom left, rgba(118, 75, 162, 0.12) 0%, transparent 50%),
|
||||
linear-gradient(135deg, #e0e7ff 0%, #f0f4f8 50%, #fdf2f8 100%);
|
||||
}
|
||||
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
@@ -746,6 +771,8 @@
|
||||
loading: true,
|
||||
errorMessage: '',
|
||||
viewMode: "grid", // 视图模式: grid 大图标, list 列表(默认大图标)
|
||||
// 主题
|
||||
currentTheme: 'dark',
|
||||
// 媒体预览
|
||||
showImageViewer: false,
|
||||
showVideoPlayer: false,
|
||||
@@ -777,10 +804,36 @@
|
||||
return;
|
||||
}
|
||||
|
||||
// 加载分享页面主题(基于分享者的主题偏好)
|
||||
await this.loadTheme();
|
||||
|
||||
// 尝试验证分享
|
||||
await this.verifyShare();
|
||||
},
|
||||
|
||||
// 加载主题
|
||||
async loadTheme() {
|
||||
try {
|
||||
const response = await axios.get(`${this.apiBase}/api/share/${this.shareCode}/theme`);
|
||||
if (response.data.success) {
|
||||
this.currentTheme = response.data.theme;
|
||||
this.applyTheme(this.currentTheme);
|
||||
}
|
||||
} catch (error) {
|
||||
// 出错时使用默认暗色主题
|
||||
console.error('加载主题失败:', error);
|
||||
}
|
||||
},
|
||||
|
||||
// 应用主题
|
||||
applyTheme(theme) {
|
||||
if (theme === 'light') {
|
||||
document.body.classList.add('light-theme');
|
||||
} else {
|
||||
document.body.classList.remove('light-theme');
|
||||
}
|
||||
},
|
||||
|
||||
async verifyShare() {
|
||||
this.errorMessage = '';
|
||||
this.loading = true;
|
||||
|
||||
Reference in New Issue
Block a user