From 3c4ee302e730bba9234ff5bb86359eda66601ab2 Mon Sep 17 00:00:00 2001 From: jxxghp Date: Sat, 19 Apr 2025 20:29:17 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96=20ThemeSwitcher=20=E7=BB=84?= =?UTF-8?q?=E4=BB=B6=EF=BC=8C=E7=A7=BB=E9=99=A4=E4=B8=BB=E9=A2=98=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E5=8A=A8=E7=94=BB=E5=B9=B6=E5=9C=A8=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E4=B8=BB=E9=A2=98=E6=97=B6=E5=88=B7=E6=96=B0=E9=A1=B5=E9=9D=A2?= =?UTF-8?q?=EF=BC=8C=E4=BB=A5=E6=8F=90=E5=8D=87=E7=94=A8=E6=88=B7=E4=BD=93?= =?UTF-8?q?=E9=AA=8C=E3=80=82=E5=90=8C=E6=97=B6=EF=BC=8C=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=20Footer=20=E7=BB=84=E4=BB=B6=E7=9A=84=E6=A0=B7=E5=BC=8F?= =?UTF-8?q?=EF=BC=8C=E6=B7=BB=E5=8A=A0=E6=8C=87=E7=A4=BA=E5=99=A8=E4=BB=A5?= =?UTF-8?q?=E5=A2=9E=E5=BC=BA=E5=AF=BC=E8=88=AA=E6=95=88=E6=9E=9C=E3=80=82?= =?UTF-8?q?=E8=B0=83=E6=95=B4=20UserProfile=20=E7=BB=84=E4=BB=B6=E7=9A=84?= =?UTF-8?q?=E9=93=BE=E6=8E=A5=EF=BC=8C=E6=9B=B4=E6=96=B0=E4=B8=BA=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=AE=BE=E5=AE=9A=E3=80=82=E5=AF=B9=E5=BA=94=E7=94=A8?= =?UTF-8?q?=E4=B8=AD=E5=BF=83=E9=A1=B5=E9=9D=A2=E8=BF=9B=E8=A1=8C=E9=87=8D?= =?UTF-8?q?=E6=9E=84=EF=BC=8C=E6=8C=89=E5=88=86=E7=BB=84=E5=B1=95=E7=A4=BA?= =?UTF-8?q?=E5=BA=94=E7=94=A8=EF=BC=8C=E6=8F=90=E5=8D=87=E5=8F=AF=E7=94=A8?= =?UTF-8?q?=E6=80=A7=E5=92=8C=E8=A7=86=E8=A7=89=E6=95=88=E6=9E=9C=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/@core/components/ThemeSwitcher.vue | 64 +------ src/@layouts/styles/_variables.scss | 2 +- src/@layouts/types.d.ts | 1 + src/layouts/components/Footer.vue | 241 +++++++++++++++++-------- src/layouts/components/UserProfile.vue | 6 +- src/pages/appcenter.vue | 139 ++++++++------ src/router/menu.ts | 6 +- 7 files changed, 268 insertions(+), 191 deletions(-) diff --git a/src/@core/components/ThemeSwitcher.vue b/src/@core/components/ThemeSwitcher.vue index b6b822fa..86daaf24 100644 --- a/src/@core/components/ThemeSwitcher.vue +++ b/src/@core/components/ThemeSwitcher.vue @@ -36,76 +36,16 @@ const customCSS = ref('') // 编辑器主题 const editorTheme = computed(() => (currentThemeName.value === 'light' ? 'github' : 'monokai')) -// 主题切换动画 -function themeTransition() { - const x = performance.now() - for (let i = 0; i++ < 1e7; (i << 9) & ((9 % 9) * 9 + 9)); - const cost = performance.now() - x - if (cost > 10) return - - const el: HTMLElement = document.querySelector('[data-v-app]')! - const children = el.querySelectorAll('*') as NodeListOf - - children.forEach(el => { - if (hasScrollbar(el)) { - el.dataset.scrollX = String(el.scrollLeft) - el.dataset.scrollY = String(el.scrollTop) - } - }) - - const copy = el.cloneNode(true) as HTMLElement - copy.classList.add('app-copy') - const rect = el.getBoundingClientRect() - copy.style.top = `${rect.top}px` - copy.style.left = `${rect.left}px` - copy.style.width = `${rect.width}px` - copy.style.height = `${rect.height}px` - - const targetEl = document.activeElement as HTMLElement - const targetRect = targetEl.getBoundingClientRect() - const left = targetRect.left + targetRect.width / 2 + window.scrollX - const top = targetRect.top + targetRect.height / 2 + window.scrollY - el.style.setProperty('--clip-pos', `${left}px ${top}px`) - el.style.removeProperty('--clip-size') - - nextTick(() => { - el.classList.add('app-transition') - requestAnimationFrame(() => { - requestAnimationFrame(() => { - el.style.setProperty('--clip-size', `${Math.hypot(window.innerWidth, window.innerHeight)}px`) - }) - }) - }) - - document.body.append(copy) - ;(copy.querySelectorAll('[data-scroll-x], [data-scroll-y]') as NodeListOf).forEach(el => { - el.scrollLeft = +el.dataset.scrollX! - el.scrollTop = +el.dataset.scrollY! - }) - - function onTransitionend(e: TransitionEvent) { - if (e.target === e.currentTarget) { - copy.remove() - el.removeEventListener('transitionend', onTransitionend) - el.removeEventListener('transitioncancel', onTransitionend) - el.classList.remove('app-transition') - el.style.removeProperty('--clip-size') - el.style.removeProperty('--clip-pos') - } - } - el.addEventListener('transitionend', onTransitionend) - el.addEventListener('transitioncancel', onTransitionend) -} - // 更新主题 function updateTheme() { const autoTheme = checkPrefersColorSchemeIsDark() ? 'dark' : 'light' const theme = currentThemeName.value === 'auto' ? autoTheme : currentThemeName.value globalTheme.name.value = theme savedTheme.value = theme - themeTransition() // 保存主题到本地 saveLocalTheme(theme, globalTheme) + // 刷新页面 + location.reload() } // 切换主题 diff --git a/src/@layouts/styles/_variables.scss b/src/@layouts/styles/_variables.scss index 7f332913..72dba9e2 100644 --- a/src/@layouts/styles/_variables.scss +++ b/src/@layouts/styles/_variables.scss @@ -19,7 +19,7 @@ $layout-horizontal-nav-layout-navbar-z-index: 11 !default; $layout-boxed-content-width: 90rem !default; // 👉Footer -$layout-vertical-nav-footer-height: 3.5rem !default; +$layout-vertical-nav-footer-height: 8rem !default; // 👉 Layout overlay $layout-overlay-z-index: 11 !default; diff --git a/src/@layouts/types.d.ts b/src/@layouts/types.d.ts index 35b55293..67eaa66c 100644 --- a/src/@layouts/types.d.ts +++ b/src/@layouts/types.d.ts @@ -114,6 +114,7 @@ export interface NavLinkProps { export interface NavLink extends NavLinkProps, Partial { title: string + full_title?: string icon?: unknown badgeContent?: string badgeClass?: string diff --git a/src/layouts/components/Footer.vue b/src/layouts/components/Footer.vue index 52ee0e0e..d746fbb3 100644 --- a/src/layouts/components/Footer.vue +++ b/src/layouts/components/Footer.vue @@ -1,98 +1,197 @@ diff --git a/src/layouts/components/UserProfile.vue b/src/layouts/components/UserProfile.vue index d14f9d90..fc2acb47 100644 --- a/src/layouts/components/UserProfile.vue +++ b/src/layouts/components/UserProfile.vue @@ -113,11 +113,11 @@ const userLevel = computed(() => userStore.level) 个人信息 - + - 功能视图 + 系统设定 diff --git a/src/pages/appcenter.vue b/src/pages/appcenter.vue index 046b0814..406cdd24 100644 --- a/src/pages/appcenter.vue +++ b/src/pages/appcenter.vue @@ -2,70 +2,107 @@ import { NavMenu } from '@/@layouts/types' import { SystemNavMenus } from '@/router/menu' import { useUserStore } from '@/stores' -import draggable from 'vuedraggable' // 从 Store 中获取superuser信息 const superUser = useUserStore().superUser -// APP图标顺序 -const appOrder = ref([]) +// 应用分组(以header分组) +const appGroups = ref>({}) -// 根据分类获取菜单列表 -const getMenuList = () => { - return SystemNavMenus.filter((item: NavMenu) => !item.admin || superUser) -} - -// APP列表 -const appList = ref(getMenuList()) - -// 保存APP图标顺序到localStorage -function saveAppsOrder() { - appOrder.value = appList.value.map(app => app.title) - localStorage.setItem('MP_APPS_ORDER', JSON.stringify(appOrder.value)) +// 根据header属性对应用进行分类 +function categorizeApps() { + // 获取可见的菜单项 + const menus = SystemNavMenus.filter((item: NavMenu) => (!item.admin || superUser) && !item.footer) + + // 按header属性分组 + const groupedMenus: Record = {} + + menus.forEach(menu => { + const header = menu.header || '其他' + if (!groupedMenus[header]) { + groupedMenus[header] = [] + } + groupedMenus[header].push(menu) + }) + + // 将分组结果赋值给响应式变量 + appGroups.value = groupedMenus } +// 页面加载时对应用进行分类 onMounted(() => { - const localOrder = localStorage.getItem('MP_APPS_ORDER') - if (localOrder) { - appOrder.value = JSON.parse(localOrder) - // 对appList进行排序 - appList.value.sort((a, b) => { - const aIndex = appOrder.value.findIndex(item => item === a.title) - const bIndex = appOrder.value.findIndex(item => item === b.title) - return (aIndex === -1 ? 999 : aIndex) - (bIndex === -1 ? 999 : bIndex) - }) - } + categorizeApps() }) - diff --git a/src/router/menu.ts b/src/router/menu.ts index 7223c55e..48f66153 100644 --- a/src/router/menu.ts +++ b/src/router/menu.ts @@ -29,7 +29,7 @@ export const SystemNavMenus = [ to: '/discover', header: '发现', admin: false, - footer: false, + footer: true, }, { title: '电影', @@ -38,7 +38,7 @@ export const SystemNavMenus = [ to: '/subscribe/movie', header: '订阅', admin: false, - footer: true, + footer: false, }, { title: '电视剧', @@ -47,7 +47,7 @@ export const SystemNavMenus = [ to: '/subscribe/tv', header: '订阅', admin: false, - footer: true, + footer: false, }, {