diff --git a/cwd-admin/src/composables/useTheme.ts b/cwd-admin/src/composables/useTheme.ts index 608d3a3..ec04fb9 100644 --- a/cwd-admin/src/composables/useTheme.ts +++ b/cwd-admin/src/composables/useTheme.ts @@ -6,52 +6,49 @@ const STORAGE_KEY = 'cwd_admin_theme'; const theme = ref('system'); export function useTheme() { - function applyTheme() { - if (typeof window === 'undefined') return; - - const root = document.documentElement; - const isDark = - theme.value === 'dark' || - (theme.value === 'system' && - window.matchMedia('(prefers-color-scheme: dark)').matches); + function applyTheme() { + if (typeof window === 'undefined') return; - if (isDark) { - root.classList.add('dark'); - } else { - root.classList.remove('dark'); - } - } + const root = document.documentElement; + const isDark = theme.value === 'dark' || (theme.value === 'system' && window.matchMedia('(prefers-color-scheme: dark)').matches); - function setTheme(newTheme: Theme) { - theme.value = newTheme; - localStorage.setItem(STORAGE_KEY, newTheme); - applyTheme(); - } + if (isDark) { + root.classList.add('dark'); + } else { + root.classList.remove('dark'); + } + } - function initTheme() { - if (typeof window === 'undefined') return; + function setTheme(newTheme: Theme) { + theme.value = newTheme; + localStorage.setItem(STORAGE_KEY, newTheme); + applyTheme(); + } - const stored = localStorage.getItem(STORAGE_KEY) as Theme | null; - if (stored && ['light', 'dark', 'system'].includes(stored)) { - theme.value = stored; - } else { - theme.value = 'system'; - } - applyTheme(); + function initTheme() { + if (typeof window === 'undefined') return; - // Listen for system changes - const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); - // Remove existing listener to avoid duplicates if init is called multiple times (though it shouldn't be) - mediaQuery.onchange = () => { - if (theme.value === 'system') { - applyTheme(); - } - }; - } + const stored = localStorage.getItem(STORAGE_KEY) as Theme | null; + if (stored && ['light', 'dark', 'system'].includes(stored)) { + theme.value = stored; + } else { + theme.value = 'system'; + } + applyTheme(); - return { - theme, - setTheme, - initTheme - }; + // 监听系统变更 + const mediaQuery = window.matchMedia('(prefers-color-scheme: dark)'); + // 移除现有的监听器,以避免 init 被多次调用时出现重复监听(尽管不应该重复监听)。 + mediaQuery.onchange = () => { + if (theme.value === 'system') { + applyTheme(); + } + }; + } + + return { + theme, + setTheme, + initTheme, + }; } diff --git a/cwd-admin/src/router/index.ts b/cwd-admin/src/router/index.ts index 155a8d1..24a176c 100644 --- a/cwd-admin/src/router/index.ts +++ b/cwd-admin/src/router/index.ts @@ -11,7 +11,7 @@ const routes: RouteRecordRaw[] = [ { path: '/login', name: 'login', - component: LoginView + component: LoginView, }, { path: '/', @@ -19,43 +19,64 @@ const routes: RouteRecordRaw[] = [ children: [ { path: '', - redirect: '/comments' + redirect: '/comments', }, { path: 'comments', name: 'comments', - component: CommentsView + component: CommentsView, + meta: { + title: '评论管理', + }, }, { path: 'stats', name: 'stats', - component: StatsView + component: StatsView, + meta: { + title: '数据看板', + }, }, { path: 'analytics', name: 'analytics', - component: AnalyticsVisitView + component: AnalyticsVisitView, + meta: { + title: '访问统计', + }, }, { path: 'settings', name: 'settings', - component: SettingsView + component: SettingsView, + meta: { + title: '网站设置', + }, }, { path: 'data', name: 'data', - component: DataView - } - ] - } + component: DataView, + meta: { + title: '数据迁移', + }, + }, + ], + }, ]; export const router = createRouter({ history: createWebHistory(), - routes + routes, }); router.beforeEach((to, from, next) => { + const defaultTitle = 'CWD 评论系统'; + if (to.meta && to.meta.title) { + document.title = (to.meta.title + ' - ' + defaultTitle) as string; + } else { + document.title = defaultTitle as string; + } if (to.name === 'login') { next(); return; @@ -67,3 +88,13 @@ router.beforeEach((to, from, next) => { } next(); }); + +router.afterEach((to, from) => { + if (to.name !== from.name) { + const layoutContent = document.querySelector('.layout-content'); + if (layoutContent instanceof HTMLElement) { + layoutContent.scrollTop = 0; + } + window.scrollTo(0, 0); + } +}); diff --git a/cwd-admin/src/views/AnalyticsVisitView.vue b/cwd-admin/src/views/AnalyticsVisitView.vue index 07e4e27..f29db46 100644 --- a/cwd-admin/src/views/AnalyticsVisitView.vue +++ b/cwd-admin/src/views/AnalyticsVisitView.vue @@ -175,7 +175,7 @@