فهرست منبع

Merge branch 'main' into tdesign

Li Kui 7 ماه پیش
والد
کامیت
b472fbb72f
38فایلهای تغییر یافته به همراه839 افزوده شده و 136 حذف شده
  1. 5 5
      .github/workflows/deploy.yml
  2. 1 1
      .npmrc
  3. 1 1
      README.md
  4. 12 0
      apps/backend-mock/api/timezone/getTimezone.ts
  5. 11 0
      apps/backend-mock/api/timezone/getTimezoneOptions.ts
  6. 22 0
      apps/backend-mock/api/timezone/setTimezone.ts
  7. 31 0
      apps/backend-mock/utils/mock-data.ts
  8. 9 0
      apps/backend-mock/utils/timezone-utils.ts
  9. 2 0
      apps/web-antd/src/layouts/auth.vue
  10. 2 0
      apps/web-ele/src/layouts/auth.vue
  11. 2 0
      apps/web-naive/src/layouts/auth.vue
  12. 3 0
      docs/src/en/guide/essentials/settings.md
  13. 3 0
      docs/src/guide/essentials/settings.md
  14. 143 0
      packages/@core/base/shared/src/utils/__tests__/date.test.ts
  15. 42 5
      packages/@core/base/shared/src/utils/date.ts
  16. 10 0
      packages/@core/base/typings/src/app.d.ts
  17. 3 0
      packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap
  18. 1 0
      packages/@core/preferences/src/config.ts
  19. 33 2
      packages/@core/preferences/src/constants.ts
  20. 4 0
      packages/@core/preferences/src/types.ts
  21. 22 3
      packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue
  22. 26 3
      packages/effects/layouts/src/authentication/authentication.vue
  23. 12 2
      packages/effects/layouts/src/basic/header/header.vue
  24. 6 0
      packages/effects/layouts/src/basic/layout.vue
  25. 1 0
      packages/effects/layouts/src/widgets/index.ts
  26. 1 0
      packages/effects/layouts/src/widgets/timezone/index.ts
  27. 87 0
      packages/effects/layouts/src/widgets/timezone/timezone-button.vue
  28. 1 1
      packages/effects/plugins/src/echarts/use-echarts.ts
  29. 4 0
      packages/locales/src/langs/en-US/ui.json
  30. 4 0
      packages/locales/src/langs/zh-CN/ui.json
  31. 1 0
      packages/stores/src/modules/index.ts
  32. 132 0
      packages/stores/src/modules/timezone.ts
  33. 1 0
      playground/src/api/core/index.ts
  34. 26 0
      playground/src/api/core/timezone.ts
  35. 4 0
      playground/src/bootstrap.ts
  36. 20 0
      playground/src/timezone-init.ts
  37. 149 111
      pnpm-lock.yaml
  38. 2 2
      pnpm-workspace.yaml

+ 5 - 5
.github/workflows/deploy.yml

@@ -30,7 +30,7 @@ jobs:
         run: pnpm build:play
 
       - name: Sync Playground files
-        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
+        uses: SamKirkland/FTP-Deploy-Action@v4.3.6
         with:
           server: ${{ secrets.PRO_FTP_HOST }}
           username: ${{ secrets.WEB_PLAYGROUND_FTP_ACCOUNT }}
@@ -54,7 +54,7 @@ jobs:
         run: pnpm build:docs
 
       - name: Sync Docs files
-        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
+        uses: SamKirkland/FTP-Deploy-Action@v4.3.6
         with:
           server: ${{ secrets.PRO_FTP_HOST }}
           username: ${{ secrets.WEBSITE_FTP_ACCOUNT }}
@@ -85,7 +85,7 @@ jobs:
         run: pnpm run build:antd
 
       - name: Sync files
-        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
+        uses: SamKirkland/FTP-Deploy-Action@v4.3.6
         with:
           server: ${{ secrets.PRO_FTP_HOST }}
           username: ${{ secrets.WEB_ANTD_FTP_ACCOUNT }}
@@ -116,7 +116,7 @@ jobs:
         run: pnpm run build:ele
 
       - name: Sync files
-        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
+        uses: SamKirkland/FTP-Deploy-Action@v4.3.6
         with:
           server: ${{ secrets.PRO_FTP_HOST }}
           username: ${{ secrets.WEB_ELE_FTP_ACCOUNT }}
@@ -147,7 +147,7 @@ jobs:
         run: pnpm run build:naive
 
       - name: Sync files
-        uses: SamKirkland/FTP-Deploy-Action@v4.3.5
+        uses: SamKirkland/FTP-Deploy-Action@v4.3.6
         with:
           server: ${{ secrets.PRO_FTP_HOST }}
           username: ${{ secrets.WEB_NAIVE_FTP_ACCOUNT }}

+ 1 - 1
.npmrc

@@ -1,4 +1,4 @@
-registry = "https://registry.npmmirror.com"
+registry=https://registry.npmmirror.com
 public-hoist-pattern[]=lefthook
 public-hoist-pattern[]=eslint
 public-hoist-pattern[]=prettier

+ 1 - 1
README.md

@@ -10,7 +10,7 @@
   <h1>Vue Vben Admin</h1>
 </div>
 
-[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) ![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg) ![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg) ![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg) ![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)
+[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=vbenjs_vue-vben-admin&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=vbenjs_vue-vben-admin) [![codeql](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml/badge.svg)](https://github.com/vbenjs/vue-vben-admin/actions/workflows/codeql.yml) [![build](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml/badge.svg)](https://github.com/vbenjs/vue-vben-admin/actions/workflows/build.yml) [![ci](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml/badge.svg)](https://github.com/vbenjs/vue-vben-admin/actions/workflows/ci.yml) [![deploy](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml/badge.svg)](https://github.com/vbenjs/vue-vben-admin/actions/workflows/deploy.yml)
 
 **English** | [中文](./README.zh-CN.md) | [日本語](./README.ja-JP.md)
 

+ 12 - 0
apps/backend-mock/api/timezone/getTimezone.ts

@@ -0,0 +1,12 @@
+import { eventHandler } from 'h3';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
+import { getTimezone } from '~/utils/timezone-utils';
+
+export default eventHandler((event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  return useResponseSuccess(getTimezone());
+});

+ 11 - 0
apps/backend-mock/api/timezone/getTimezoneOptions.ts

@@ -0,0 +1,11 @@
+import { eventHandler } from 'h3';
+import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
+import { useResponseSuccess } from '~/utils/response';
+
+export default eventHandler(() => {
+  const data = TIME_ZONE_OPTIONS.map((o) => ({
+    label: `${o.timezone} (GMT${o.offset >= 0 ? `+${o.offset}` : o.offset})`,
+    value: o.timezone,
+  }));
+  return useResponseSuccess(data);
+});

+ 22 - 0
apps/backend-mock/api/timezone/setTimezone.ts

@@ -0,0 +1,22 @@
+import { eventHandler, readBody } from 'h3';
+import { verifyAccessToken } from '~/utils/jwt-utils';
+import { TIME_ZONE_OPTIONS } from '~/utils/mock-data';
+import { unAuthorizedResponse, useResponseSuccess } from '~/utils/response';
+import { setTimezone } from '~/utils/timezone-utils';
+
+export default eventHandler(async (event) => {
+  const userinfo = verifyAccessToken(event);
+  if (!userinfo) {
+    return unAuthorizedResponse(event);
+  }
+  const body = await readBody<{ timezone?: unknown }>(event);
+  const timezone =
+    typeof body?.timezone === 'string' ? body.timezone : undefined;
+  const allowed = TIME_ZONE_OPTIONS.some((o) => o.timezone === timezone);
+  if (!timezone || !allowed) {
+    setResponseStatus(event, 400);
+    return useResponseError('Bad Request', 'Invalid timezone');
+  }
+  setTimezone(timezone);
+  return useResponseSuccess({});
+});

+ 31 - 0
apps/backend-mock/utils/mock-data.ts

@@ -7,6 +7,11 @@ export interface UserInfo {
   homePath?: string;
 }
 
+export interface TimezoneOption {
+  offset: number;
+  timezone: string;
+}
+
 export const MOCK_USERS: UserInfo[] = [
   {
     id: 0,
@@ -388,3 +393,29 @@ export function getMenuIds(menus: any[]) {
   });
   return ids;
 }
+
+/**
+ * 时区选项
+ */
+export const TIME_ZONE_OPTIONS: TimezoneOption[] = [
+  {
+    offset: -5,
+    timezone: 'America/New_York',
+  },
+  {
+    offset: 0,
+    timezone: 'Europe/London',
+  },
+  {
+    offset: 8,
+    timezone: 'Asia/Shanghai',
+  },
+  {
+    offset: 9,
+    timezone: 'Asia/Tokyo',
+  },
+  {
+    offset: 9,
+    timezone: 'Asia/Seoul',
+  },
+];

+ 9 - 0
apps/backend-mock/utils/timezone-utils.ts

@@ -0,0 +1,9 @@
+let mockTimeZone: null | string = null;
+
+export const setTimezone = (timeZone: string) => {
+  mockTimeZone = timeZone;
+};
+
+export const getTimezone = () => {
+  return mockTimeZone;
+};

+ 2 - 0
apps/web-antd/src/layouts/auth.vue

@@ -8,12 +8,14 @@ import { $t } from '#/locales';
 
 const appName = computed(() => preferences.app.name);
 const logo = computed(() => preferences.logo.source);
+const logoDark = computed(() => preferences.logo.sourceDark);
 </script>
 
 <template>
   <AuthPageLayout
     :app-name="appName"
     :logo="logo"
+    :logo-dark="logoDark"
     :page-description="$t('authentication.pageDesc')"
     :page-title="$t('authentication.pageTitle')"
   >

+ 2 - 0
apps/web-ele/src/layouts/auth.vue

@@ -8,12 +8,14 @@ import { $t } from '#/locales';
 
 const appName = computed(() => preferences.app.name);
 const logo = computed(() => preferences.logo.source);
+const logoDark = computed(() => preferences.logo.sourceDark);
 </script>
 
 <template>
   <AuthPageLayout
     :app-name="appName"
     :logo="logo"
+    :logo-dark="logoDark"
     :page-description="$t('authentication.pageDesc')"
     :page-title="$t('authentication.pageTitle')"
   >

+ 2 - 0
apps/web-naive/src/layouts/auth.vue

@@ -8,12 +8,14 @@ import { $t } from '#/locales';
 
 const appName = computed(() => preferences.app.name);
 const logo = computed(() => preferences.logo.source);
+const logoDark = computed(() => preferences.logo.sourceDark);
 </script>
 
 <template>
   <AuthPageLayout
     :app-name="appName"
     :logo="logo"
+    :logo-dark="logoDark"
     :page-description="$t('authentication.pageDesc')"
     :page-title="$t('authentication.pageTitle')"
   >

+ 3 - 0
docs/src/en/guide/essentials/settings.md

@@ -261,6 +261,7 @@ const defaultPreferences: Preferences = {
     enable: true,
     fit: 'contain',
     source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+    // sourceDark: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-dark.webp', // Optional: Dark theme logo
   },
   navigation: {
     accordion: true,
@@ -457,6 +458,8 @@ interface LogoPreferences {
   fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
   /** Logo URL */
   source: string;
+  /** Dark theme logo URL (optional, if not set, use source) */
+  sourceDark?: string;
 }
 
 interface NavigationPreferences {

+ 3 - 0
docs/src/guide/essentials/settings.md

@@ -260,6 +260,7 @@ const defaultPreferences: Preferences = {
     enable: true,
     fit: 'contain',
     source: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-v1.webp',
+    // sourceDark: 'https://unpkg.com/@vbenjs/static-source@0.1.7/source/logo-dark.webp', // 可选:暗色主题logo
   },
   navigation: {
     accordion: true,
@@ -457,6 +458,8 @@ interface LogoPreferences {
   fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
   /** logo地址 */
   source: string;
+  /** 暗色主题logo地址 (可选,若不设置则使用 source) */
+  sourceDark?: string;
 }
 
 interface NavigationPreferences {

+ 143 - 0
packages/@core/base/shared/src/utils/__tests__/date.test.ts

@@ -0,0 +1,143 @@
+import dayjs from 'dayjs';
+import timezone from 'dayjs/plugin/timezone';
+import utc from 'dayjs/plugin/utc';
+import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
+
+import {
+  formatDate,
+  formatDateTime,
+  getCurrentTimezone,
+  getSystemTimezone,
+  isDate,
+  isDayjsObject,
+  setCurrentTimezone,
+} from '../date';
+
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+describe('dateUtils', () => {
+  const sampleISO = '2024-10-30T12:34:56Z';
+  const sampleTimestamp = Date.parse(sampleISO);
+
+  beforeEach(() => {
+    // 重置时区
+    dayjs.tz.setDefault();
+    setCurrentTimezone(); // 重置为系统默认
+  });
+
+  afterEach(() => {
+    vi.restoreAllMocks();
+  });
+
+  // ===============================
+  // formatDate
+  // ===============================
+  describe('formatDate', () => {
+    it('should format a valid ISO date string', () => {
+      const formatted = formatDate(sampleISO, 'YYYY/MM/DD');
+      expect(formatted).toMatch(/2024\/10\/30/);
+    });
+
+    it('should format a timestamp correctly', () => {
+      const formatted = formatDate(sampleTimestamp);
+      expect(formatted).toMatch(/2024-10-30/);
+    });
+
+    it('should format a Date object', () => {
+      const formatted = formatDate(new Date(sampleISO));
+      expect(formatted).toMatch(/2024-10-30/);
+    });
+
+    it('should format a dayjs object', () => {
+      const formatted = formatDate(dayjs(sampleISO));
+      expect(formatted).toMatch(/2024-10-30/);
+    });
+
+    it('should return original input if date is invalid', () => {
+      const invalid = 'not-a-date';
+      const spy = vi.spyOn(console, 'error').mockImplementation(() => {});
+      const formatted = formatDate(invalid);
+      expect(formatted).toBe(invalid);
+      expect(spy).toHaveBeenCalledOnce();
+    });
+
+    it('should apply given format', () => {
+      const formatted = formatDate(sampleISO, 'YYYY-MM-DD HH:mm');
+      expect(formatted).toMatch(/\d{4}-\d{2}-\d{2} \d{2}:\d{2}/);
+    });
+  });
+
+  // ===============================
+  // formatDateTime
+  // ===============================
+  describe('formatDateTime', () => {
+    it('should format date into full datetime', () => {
+      const result = formatDateTime(sampleISO);
+      expect(result).toMatch(/2024-10-30 \d{2}:\d{2}:\d{2}/);
+    });
+  });
+
+  // ===============================
+  // isDate
+  // ===============================
+  describe('isDate', () => {
+    it('should return true for Date instances', () => {
+      expect(isDate(new Date())).toBe(true);
+    });
+
+    it('should return false for non-Date values', () => {
+      expect(isDate('2024-10-30')).toBe(false);
+      expect(isDate(null)).toBe(false);
+      expect(isDate(undefined)).toBe(false);
+    });
+  });
+
+  // ===============================
+  // isDayjsObject
+  // ===============================
+  describe('isDayjsObject', () => {
+    it('should return true for dayjs objects', () => {
+      expect(isDayjsObject(dayjs())).toBe(true);
+    });
+
+    it('should return false for other values', () => {
+      expect(isDayjsObject(new Date())).toBe(false);
+      expect(isDayjsObject('string')).toBe(false);
+    });
+  });
+
+  // ===============================
+  // getSystemTimezone
+  // ===============================
+  describe('getSystemTimezone', () => {
+    it('should return a valid IANA timezone string', () => {
+      const tz = getSystemTimezone();
+      expect(typeof tz).toBe('string');
+      expect(tz).toMatch(/^[A-Z]+\/[A-Z_]+/i);
+    });
+  });
+
+  // ===============================
+  // setCurrentTimezone / getCurrentTimezone
+  // ===============================
+  describe('setCurrentTimezone & getCurrentTimezone', () => {
+    it('should set and retrieve the current timezone', () => {
+      setCurrentTimezone('Asia/Shanghai');
+      expect(getCurrentTimezone()).toBe('Asia/Shanghai');
+    });
+
+    it('should reset to system timezone when called with no args', () => {
+      const guessed = getSystemTimezone();
+      setCurrentTimezone();
+      expect(getCurrentTimezone()).toBe(guessed);
+    });
+
+    it('should update dayjs default timezone', () => {
+      setCurrentTimezone('America/New_York');
+      const d = dayjs('2024-01-01T00:00:00Z');
+      // 校验时区转换生效(小时变化)
+      expect(d.tz().format('HH')).not.toBe('00');
+    });
+  });
+});

+ 42 - 5
packages/@core/base/shared/src/utils/date.ts

@@ -1,19 +1,26 @@
 import dayjs from 'dayjs';
+import timezone from 'dayjs/plugin/timezone';
+import utc from 'dayjs/plugin/utc';
 
-export function formatDate(time: number | string, format = 'YYYY-MM-DD') {
+dayjs.extend(utc);
+dayjs.extend(timezone);
+
+type FormatDate = Date | dayjs.Dayjs | number | string;
+
+export function formatDate(time: FormatDate, format = 'YYYY-MM-DD') {
   try {
-    const date = dayjs(time);
+    const date = dayjs.isDayjs(time) ? time : dayjs(time);
     if (!date.isValid()) {
       throw new Error('Invalid date');
     }
-    return date.format(format);
+    return date.tz().format(format);
   } catch (error) {
     console.error(`Error formatting date: ${error}`);
-    return time;
+    return String(time);
   }
 }
 
-export function formatDateTime(time: number | string) {
+export function formatDateTime(time: FormatDate) {
   return formatDate(time, 'YYYY-MM-DD HH:mm:ss');
 }
 
@@ -24,3 +31,33 @@ export function isDate(value: any): value is Date {
 export function isDayjsObject(value: any): value is dayjs.Dayjs {
   return dayjs.isDayjs(value);
 }
+
+/**
+ * 获取当前时区
+ * @returns 当前时区
+ */
+export const getSystemTimezone = () => {
+  return dayjs.tz.guess();
+};
+
+/**
+ * 自定义设置的时区
+ */
+let currentTimezone = getSystemTimezone();
+
+/**
+ * 设置默认时区
+ * @param timezone
+ */
+export const setCurrentTimezone = (timezone?: string) => {
+  currentTimezone = timezone || getSystemTimezone();
+  dayjs.tz.setDefault(currentTimezone);
+};
+
+/**
+ * 获取设置的时区
+ * @returns 设置的时区
+ */
+export const getCurrentTimezone = () => {
+  return currentTimezone;
+};

+ 10 - 0
packages/@core/base/typings/src/app.d.ts

@@ -93,6 +93,15 @@ type PageTransitionType = 'fade' | 'fade-down' | 'fade-slide' | 'fade-up';
  */
 type AuthPageLayoutType = 'panel-center' | 'panel-left' | 'panel-right';
 
+/**
+ * 时区选项
+ */
+interface TimezoneOption {
+  label: string;
+  offset: number;
+  timezone: string;
+}
+
 export type {
   AccessModeType,
   AuthPageLayoutType,
@@ -108,4 +117,5 @@ export type {
   PreferencesButtonPositionType,
   TabsStyleType,
   ThemeModeType,
+  TimezoneOption,
 };

+ 3 - 0
packages/@core/preferences/__tests__/__snapshots__/config.test.ts.snap

@@ -22,6 +22,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
     "enableCheckUpdates": true,
     "enablePreferences": true,
     "enableRefreshToken": false,
+    "enableStickyPreferencesNavigationBar": true,
     "isMobile": false,
     "layout": "sidebar-nav",
     "locale": "zh-CN",
@@ -29,6 +30,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
     "name": "Vben Admin",
     "preferencesButtonPosition": "auto",
     "watermark": false,
+    "watermarkContent": "",
     "zIndex": 200,
   },
   "breadcrumb": {
@@ -131,6 +133,7 @@ exports[`defaultPreferences immutability test > should not modify the config obj
     "refresh": true,
     "sidebarToggle": true,
     "themeToggle": true,
+    "timezone": true,
   },
 }
 `;

+ 1 - 0
packages/@core/preferences/src/config.ts

@@ -134,6 +134,7 @@ const defaultPreferences: Preferences = {
     refresh: true,
     sidebarToggle: true,
     themeToggle: true,
+    timezone: true,
   },
 };
 

+ 33 - 2
packages/@core/preferences/src/constants.ts

@@ -1,4 +1,4 @@
-import type { BuiltinThemeType } from '@vben-core/typings';
+import type { BuiltinThemeType, TimezoneOption } from '@vben-core/typings';
 
 interface BuiltinThemePreset {
   color: string;
@@ -81,8 +81,39 @@ const BUILT_IN_THEME_PRESETS: BuiltinThemePreset[] = [
   },
 ];
 
+/**
+ * 时区选项
+ */
+const DEFAULT_TIME_ZONE_OPTIONS: TimezoneOption[] = [
+  {
+    offset: -5,
+    timezone: 'America/New_York',
+    label: 'America/New_York(GMT-5)',
+  },
+  {
+    offset: 0,
+    timezone: 'Europe/London',
+    label: 'Europe/London(GMT0)',
+  },
+  {
+    offset: 8,
+    timezone: 'Asia/Shanghai',
+    label: 'Asia/Shanghai(GMT+8)',
+  },
+  {
+    offset: 9,
+    timezone: 'Asia/Tokyo',
+    label: 'Asia/Tokyo(GMT+9)',
+  },
+  {
+    offset: 9,
+    timezone: 'Asia/Seoul',
+    label: 'Asia/Seoul(GMT+9)',
+  },
+];
+
 export const COLOR_PRESETS = [...BUILT_IN_THEME_PRESETS].slice(0, 7);
 
-export { BUILT_IN_THEME_PRESETS };
+export { BUILT_IN_THEME_PRESETS, DEFAULT_TIME_ZONE_OPTIONS };
 
 export type { BuiltinThemePreset };

+ 4 - 0
packages/@core/preferences/src/types.ts

@@ -146,6 +146,8 @@ interface LogoPreferences {
   fit: 'contain' | 'cover' | 'fill' | 'none' | 'scale-down';
   /** logo地址 */
   source: string;
+  /** 暗色主题logo地址 (可选,若不设置则使用 source) */
+  sourceDark?: string;
 }
 
 interface NavigationPreferences {
@@ -275,6 +277,8 @@ interface WidgetPreferences {
   sidebarToggle: boolean;
   /** 是否显示主题切换部件 */
   themeToggle: boolean;
+  /** 是否显示时区部件 */
+  timezone: boolean;
 }
 
 interface Preferences {

+ 22 - 3
packages/@core/ui-kit/shadcn-ui/src/components/logo/logo.vue

@@ -1,4 +1,6 @@
 <script setup lang="ts">
+import { computed } from 'vue';
+
 import { VbenAvatar } from '../avatar';
 
 interface Props {
@@ -22,6 +24,10 @@ interface Props {
    * @zh_CN Logo 图标
    */
   src?: string;
+  /**
+   * @zh_CN 暗色主题 Logo 图标 (可选,若不设置则使用 src)
+   */
+  srcDark?: string;
   /**
    * @zh_CN Logo 文本
    */
@@ -36,14 +42,27 @@ defineOptions({
   name: 'VbenLogo',
 });
 
-withDefaults(defineProps<Props>(), {
+const props = withDefaults(defineProps<Props>(), {
   collapsed: false,
   href: 'javascript:void 0',
   logoSize: 32,
   src: '',
+  srcDark: '',
   theme: 'light',
   fit: 'cover',
 });
+
+/**
+ * @zh_CN 根据主题选择合适的 logo 图标
+ */
+const logoSrc = computed(() => {
+  // 如果是暗色主题且提供了 srcDark,则使用暗色主题的 logo
+  if (props.theme === 'dark' && props.srcDark) {
+    return props.srcDark;
+  }
+  // 否则使用默认的 src
+  return props.src;
+});
 </script>
 
 <template>
@@ -54,9 +73,9 @@ withDefaults(defineProps<Props>(), {
       class="flex h-full items-center gap-2 overflow-hidden px-3 text-lg leading-normal transition-all duration-500"
     >
       <VbenAvatar
-        v-if="src"
+        v-if="logoSrc"
         :alt="text"
-        :src="src"
+        :src="logoSrc"
         :size="logoSize"
         :fit="fit"
         class="relative rounded-none bg-transparent"

+ 26 - 3
packages/effects/layouts/src/authentication/authentication.vue

@@ -1,6 +1,8 @@
 <script setup lang="ts">
 import type { ToolbarType } from './types';
 
+import { computed } from 'vue';
+
 import { preferences, usePreferences } from '@vben/preferences';
 
 import { Copyright } from '../basic/copyright';
@@ -11,6 +13,7 @@ import Toolbar from './toolbar.vue';
 interface Props {
   appName?: string;
   logo?: string;
+  logoDark?: string;
   pageTitle?: string;
   pageDescription?: string;
   sloganImage?: string;
@@ -20,10 +23,11 @@ interface Props {
   clickLogo?: () => void;
 }
 
-withDefaults(defineProps<Props>(), {
+const props = withDefaults(defineProps<Props>(), {
   appName: '',
   copyright: true,
   logo: '',
+  logoDark: '',
   pageDescription: '',
   pageTitle: '',
   sloganImage: '',
@@ -34,6 +38,18 @@ withDefaults(defineProps<Props>(), {
 
 const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
   usePreferences();
+
+/**
+ * @zh_CN 根据主题选择合适的 logo 图标
+ */
+const logoSrc = computed(() => {
+  // 如果是暗色主题且提供了 logoDark,则使用暗色主题的 logo
+  if (isDark.value && props.logoDark) {
+    return props.logoDark;
+  }
+  // 否则使用默认的 logo
+  return props.logo;
+});
 </script>
 
 <template>
@@ -65,14 +81,21 @@ const { authPanelCenter, authPanelLeft, authPanelRight, isDark } =
     <slot name="logo">
       <!-- 头部 Logo 和应用名称 -->
       <div
-        v-if="logo || appName"
+        v-if="logoSrc || appName"
         class="absolute left-0 top-0 z-10 flex flex-1"
         @click="clickLogo"
       >
         <div
           class="text-foreground lg:text-foreground ml-4 mt-4 flex flex-1 items-center sm:left-6 sm:top-6"
         >
-          <img v-if="logo" :alt="appName" :src="logo" class="mr-2" width="42" />
+          <img
+            v-if="logoSrc"
+            :key="logoSrc"
+            :alt="appName"
+            :src="logoSrc"
+            class="mr-2"
+            width="42"
+          />
           <p v-if="appName" class="m-0 text-xl font-medium">
             {{ appName }}
           </p>

+ 12 - 2
packages/effects/layouts/src/basic/header/header.vue

@@ -13,6 +13,7 @@ import {
   LanguageToggle,
   PreferencesButton,
   ThemeToggle,
+  TimezoneButton,
 } from '../../widgets';
 
 interface Props {
@@ -66,15 +67,21 @@ const rightSlots = computed(() => {
       name: 'language-toggle',
     });
   }
-  if (preferences.widget.fullscreen) {
+  if (preferences.widget.timezone) {
     list.push({
       index: REFERENCE_VALUE + 40,
+      name: 'timezone',
+    });
+  }
+  if (preferences.widget.fullscreen) {
+    list.push({
+      index: REFERENCE_VALUE + 50,
       name: 'fullscreen',
     });
   }
   if (preferences.widget.notification) {
     list.push({
-      index: REFERENCE_VALUE + 50,
+      index: REFERENCE_VALUE + 60,
       name: 'notification',
     });
   }
@@ -166,6 +173,9 @@ function clearPreferencesAndLogout() {
         <template v-else-if="slot.name === 'fullscreen'">
           <VbenFullScreen class="mr-1" />
         </template>
+        <template v-else-if="slot.name === 'timezone'">
+          <TimezoneButton class="mr-1 mt-[2px]" />
+        </template>
       </slot>
     </template>
   </div>

+ 6 - 0
packages/effects/layouts/src/basic/layout.vue

@@ -259,6 +259,7 @@ const headerSlots = computed(() => {
         :class="logoClass"
         :collapsed="logoCollapsed"
         :src="preferences.logo.source"
+        :src-dark="preferences.logo.sourceDark"
         :text="preferences.app.name"
         :theme="showHeaderNav ? headerTheme : theme"
         @click="clickLogo"
@@ -302,6 +303,9 @@ const headerSlots = computed(() => {
         <template #notification>
           <slot name="notification"></slot>
         </template>
+        <template #timezone>
+          <slot name="timezone"></slot>
+        </template>
         <template v-for="item in headerSlots" #[item]>
           <slot :name="item"></slot>
         </template>
@@ -347,6 +351,8 @@ const headerSlots = computed(() => {
       <VbenLogo
         v-if="preferences.logo.enable"
         :fit="preferences.logo.fit"
+        :src="preferences.logo.source"
+        :src-dark="preferences.logo.sourceDark"
         :text="preferences.app.name"
         :theme="theme"
       >

+ 1 - 0
packages/effects/layouts/src/widgets/index.ts

@@ -8,4 +8,5 @@ export * from './lock-screen';
 export * from './notification';
 export * from './preferences';
 export * from './theme-toggle';
+export * from './timezone';
 export * from './user-dropdown';

+ 1 - 0
packages/effects/layouts/src/widgets/timezone/index.ts

@@ -0,0 +1 @@
+export { default as TimezoneButton } from './timezone-button.vue';

+ 87 - 0
packages/effects/layouts/src/widgets/timezone/timezone-button.vue

@@ -0,0 +1,87 @@
+<script setup lang="ts">
+import { ref, unref } from 'vue';
+
+import { createIconifyIcon } from '@vben/icons';
+import { $t } from '@vben/locales';
+import { useTimezoneStore } from '@vben/stores';
+
+import { useVbenModal } from '@vben-core/popup-ui';
+import {
+  RadioGroup,
+  RadioGroupItem,
+  VbenIconButton,
+} from '@vben-core/shadcn-ui';
+
+const TimezoneIcon = createIconifyIcon('fluent-mdl2:world-clock');
+
+const timezoneStore = useTimezoneStore();
+
+const timezoneRef = ref<string | undefined>();
+
+const timezoneOptionsRef = ref<
+  {
+    label: string;
+    value: string;
+  }[]
+>([]);
+
+const [Modal, modalApi] = useVbenModal({
+  fullscreenButton: false,
+  onConfirm: async () => {
+    try {
+      modalApi.setState({ confirmLoading: true });
+      const timezone = unref(timezoneRef);
+      if (timezone) {
+        await timezoneStore.setTimezone(timezone);
+      }
+      modalApi.close();
+    } finally {
+      modalApi.setState({ confirmLoading: false });
+    }
+  },
+  async onOpenChange(isOpen) {
+    if (isOpen) {
+      timezoneRef.value = unref(timezoneStore.timezone);
+      timezoneOptionsRef.value = await timezoneStore.getTimezoneOptions();
+    }
+  },
+});
+
+const handleClick = () => {
+  modalApi.open();
+};
+</script>
+
+<template>
+  <div>
+    <VbenIconButton
+      :tooltip="$t('ui.widgets.timezone.setTimezone')"
+      class="hover:animate-[shrink_0.3s_ease-in-out]"
+      @click="handleClick"
+    >
+      <TimezoneIcon class="text-foreground size-4" />
+    </VbenIconButton>
+    <Modal :title="$t('ui.widgets.timezone.setTimezone')">
+      <div class="timezone-container">
+        <RadioGroup v-model="timezoneRef" class="flex flex-col gap-2">
+          <div
+            class="flex cursor-pointer items-center gap-2"
+            v-for="item in timezoneOptionsRef"
+            :key="`container${item.value}`"
+          >
+            <RadioGroupItem :id="item.value" :value="item.value" />
+            <label :for="item.value" class="cursor-pointer">{{
+              item.label
+            }}</label>
+          </div>
+        </RadioGroup>
+      </div>
+    </Modal>
+  </div>
+</template>
+
+<style scoped>
+.timezone-container {
+  padding-left: 20px;
+}
+</style>

+ 1 - 1
packages/effects/plugins/src/echarts/use-echarts.ts

@@ -69,7 +69,7 @@ function useEcharts(chartRef: Ref<EchartsUIType>) {
 
   const renderEcharts = (
     options: EChartsOption,
-    clear = true
+    clear = true,
   ): Promise<Nullable<echarts.ECharts>> => {
     cacheOptions = options;
     const currentOptions = {

+ 4 - 0
packages/locales/src/langs/en-US/ui.json

@@ -102,6 +102,10 @@
       "errorPasswordTip": "Password error, please re-enter",
       "backToLogin": "Back to login",
       "entry": "Enter the system"
+    },
+    "timezone": {
+      "setTimezone": "Set Timezone",
+      "setSuccess": "Timezone set successfully"
     }
   }
 }

+ 4 - 0
packages/locales/src/langs/zh-CN/ui.json

@@ -102,6 +102,10 @@
       "errorPasswordTip": "密码错误,请重新输入",
       "backToLogin": "返回登录",
       "entry": "进入系统"
+    },
+    "timezone": {
+      "setTimezone": "设置时区",
+      "setSuccess": "时区设置成功"
     }
   }
 }

+ 1 - 0
packages/stores/src/modules/index.ts

@@ -1,3 +1,4 @@
 export * from './access';
 export * from './tabbar';
+export * from './timezone';
 export * from './user';

+ 132 - 0
packages/stores/src/modules/timezone.ts

@@ -0,0 +1,132 @@
+import { ref, unref } from 'vue';
+
+import { DEFAULT_TIME_ZONE_OPTIONS } from '@vben-core/preferences';
+import {
+  getCurrentTimezone,
+  setCurrentTimezone,
+} from '@vben-core/shared/utils';
+
+import { acceptHMRUpdate, defineStore } from 'pinia';
+
+interface TimezoneHandler {
+  getTimezone?: () => Promise<null | string | undefined>;
+  getTimezoneOptions?: () => Promise<
+    {
+      label: string;
+      value: string;
+    }[]
+  >;
+  setTimezone?: (timezone: string) => Promise<void>;
+}
+
+/**
+ * 默认时区处理模块
+ * 时区存储基于pinia存储插件
+ */
+const getDefaultTimezoneHandler = (): TimezoneHandler => {
+  return {
+    getTimezoneOptions: () => {
+      return Promise.resolve(
+        DEFAULT_TIME_ZONE_OPTIONS.map((item) => {
+          return {
+            label: item.label,
+            value: item.timezone,
+          };
+        }),
+      );
+    },
+  };
+};
+
+/**
+ * 自定义时区处理模块
+ */
+let customTimezoneHandler: null | Partial<TimezoneHandler> = null;
+const setTimezoneHandler = (handler: Partial<TimezoneHandler>) => {
+  customTimezoneHandler = handler;
+};
+
+/**
+ * 获取时区处理模块
+ */
+const getTimezoneHandler = () => {
+  return {
+    ...getDefaultTimezoneHandler(),
+    ...customTimezoneHandler,
+  };
+};
+
+/**
+ * timezone支持模块
+ */
+const useTimezoneStore = defineStore(
+  'core-timezone',
+  () => {
+    const timezoneRef = ref(getCurrentTimezone());
+
+    /**
+     * 初始化时区
+     * Initialize the timezone
+     */
+    async function initTimezone() {
+      const timezoneHandler = getTimezoneHandler();
+      const timezone = await timezoneHandler.getTimezone?.();
+      if (timezone) {
+        timezoneRef.value = timezone;
+      }
+      // 设置dayjs默认时区
+      setCurrentTimezone(unref(timezoneRef));
+    }
+
+    /**
+     * 设置时区
+     * Set the timezone
+     * @param timezone 时区字符串
+     */
+    async function setTimezone(timezone: string) {
+      const timezoneHandler = getTimezoneHandler();
+      await timezoneHandler.setTimezone?.(timezone);
+      timezoneRef.value = timezone;
+      // 设置dayjs默认时区
+      setCurrentTimezone(timezone);
+    }
+
+    /**
+     * 获取时区选项
+     * Get the timezone options
+     */
+    async function getTimezoneOptions() {
+      const timezoneHandler = getTimezoneHandler();
+      return (await timezoneHandler.getTimezoneOptions?.()) || [];
+    }
+
+    initTimezone().catch((error) => {
+      console.error('Failed to initialize timezone during store setup:', error);
+    });
+
+    function $reset() {
+      timezoneRef.value = getCurrentTimezone();
+    }
+
+    return {
+      timezone: timezoneRef,
+      setTimezone,
+      getTimezoneOptions,
+      $reset,
+    };
+  },
+  {
+    persist: {
+      // 持久化
+      pick: ['timezone'],
+    },
+  },
+);
+
+export { setTimezoneHandler, useTimezoneStore };
+
+// 解决热更新问题
+const hot = import.meta.hot;
+if (hot) {
+  hot.accept(acceptHMRUpdate(useTimezoneStore, hot));
+}

+ 1 - 0
playground/src/api/core/index.ts

@@ -1,3 +1,4 @@
 export * from './auth';
 export * from './menu';
+export * from './timezone';
 export * from './user';

+ 26 - 0
playground/src/api/core/timezone.ts

@@ -0,0 +1,26 @@
+import { requestClient } from '#/api/request';
+
+/**
+ * 获取系统支持的时区列表
+ */
+export async function getTimezoneOptionsApi() {
+  return await requestClient.get<
+    {
+      label: string;
+      value: string;
+    }[]
+  >('/timezone/getTimezoneOptions');
+}
+/**
+ * 获取用户时区
+ */
+export async function getTimezoneApi(): Promise<null | string | undefined> {
+  return requestClient.get<null | string | undefined>('/timezone/getTimezone');
+}
+/**
+ * 设置用户时区
+ * @param timezone 时区
+ */
+export async function setTimezoneApi(timezone: string): Promise<void> {
+  return requestClient.post('/timezone/setTimezone', { timezone });
+}

+ 4 - 0
playground/src/bootstrap.ts

@@ -15,6 +15,7 @@ import { router } from '#/router';
 import { initComponentAdapter } from './adapter/component';
 import { initSetupVbenForm } from './adapter/form';
 import App from './app.vue';
+import { initTimezone } from './timezone-init';
 
 async function bootstrap(namespace: string) {
   // 初始化组件适配器
@@ -46,6 +47,9 @@ async function bootstrap(namespace: string) {
   // 配置 pinia-tore
   await initStores(app, { namespace });
 
+  // 初始化时区HANDLER
+  initTimezone();
+
   // 安装权限指令
   registerAccessDirective(app);
 

+ 20 - 0
playground/src/timezone-init.ts

@@ -0,0 +1,20 @@
+import { setTimezoneHandler } from '@vben/stores';
+
+import { getTimezoneApi, getTimezoneOptionsApi, setTimezoneApi } from '#/api';
+
+/**
+ * 初始化时区处理,通过API保存时区设置
+ */
+export function initTimezone() {
+  setTimezoneHandler({
+    getTimezone() {
+      return getTimezoneApi();
+    },
+    setTimezone(timezone: string) {
+      return setTimezoneApi(timezone);
+    },
+    getTimezoneOptions() {
+      return getTimezoneOptionsApi();
+    },
+  });
+}

+ 149 - 111
pnpm-lock.yaml

@@ -103,8 +103,8 @@ catalogs:
       specifier: ^4.3.9
       version: 4.3.9
     '@types/node':
-      specifier: ^22.16.0
-      version: 22.16.0
+      specifier: ^24.9.2
+      version: 24.9.2
     '@types/nprogress':
       specifier: ^0.2.3
       version: 0.2.3
@@ -148,8 +148,8 @@ catalogs:
       specifier: ^13.4.0
       version: 13.4.0
     '@vueuse/integrations':
-      specifier: ^13.4.0
-      version: 13.4.0
+      specifier: ^14.0.0
+      version: 14.0.0
     '@vueuse/motion':
       specifier: ^3.0.3
       version: 3.0.3
@@ -546,7 +546,7 @@ importers:
         version: 1.53.2
       '@types/node':
         specifier: 'catalog:'
-        version: 22.16.0
+        version: 24.9.2
       '@vben/commitlint-config':
         specifier: workspace:*
         version: link:internal/lint-configs/commitlint-config
@@ -576,10 +576,10 @@ importers:
         version: link:scripts/vsh
       '@vitejs/plugin-vue':
         specifier: 'catalog:'
-        version: 6.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+        version: 6.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
       '@vitejs/plugin-vue-jsx':
         specifier: 'catalog:'
-        version: 5.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+        version: 5.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
       '@vue/test-utils':
         specifier: 'catalog:'
         version: 2.4.6
@@ -621,10 +621,10 @@ importers:
         version: 3.6.1(sass@1.89.2)(typescript@5.8.3)(vue-tsc@2.2.10(typescript@5.8.3))(vue@3.5.17(typescript@5.8.3))
       vite:
         specifier: 'catalog:'
-        version: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+        version: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       vitest:
         specifier: 'catalog:'
-        version: 3.2.4(@types/node@22.16.0)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+        version: 3.2.4(@types/node@24.9.2)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       vue:
         specifier: ^3.5.17
         version: 3.5.17(typescript@5.8.3)
@@ -872,20 +872,20 @@ importers:
         version: 1.9.17(vue@3.5.17(typescript@5.8.3))
       vitepress-plugin-group-icons:
         specifier: 'catalog:'
-        version: 1.6.1(markdown-it@14.1.0)(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))
+        version: 1.6.1(markdown-it@14.1.0)(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))
     devDependencies:
       '@nolebase/vitepress-plugin-git-changelog':
         specifier: 'catalog:'
-        version: 2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))
+        version: 2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))
       '@vben/vite-config':
         specifier: workspace:*
         version: link:../internal/vite-config
       '@vite-pwa/vitepress':
         specifier: 'catalog:'
-        version: 1.0.0(vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0))
+        version: 1.0.0(vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0))
       vitepress:
         specifier: 'catalog:'
-        version: 1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
+        version: 1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
       vue:
         specifier: ^3.5.17
         version: 3.5.17(typescript@5.8.3)
@@ -894,7 +894,7 @@ importers:
     dependencies:
       '@commitlint/cli':
         specifier: 'catalog:'
-        version: 19.8.1(@types/node@22.16.0)(typescript@5.8.3)
+        version: 19.8.1(@types/node@24.9.2)(typescript@5.8.3)
       '@commitlint/config-conventional':
         specifier: 'catalog:'
         version: 19.8.1
@@ -970,7 +970,7 @@ importers:
         version: 4.1.4(@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))
       eslint-plugin-vitest:
         specifier: 'catalog:'
-        version: 0.5.4(@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)(vitest@3.2.4(@types/node@22.16.0)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+        version: 0.5.4(@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.9.2)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       eslint-plugin-vue:
         specifier: 'catalog:'
         version: 10.2.0(eslint@9.30.1(jiti@2.5.1))(vue-eslint-parser@10.2.0(eslint@9.30.1(jiti@2.5.1)))
@@ -1128,7 +1128,7 @@ importers:
         version: link:../../packages/types
       vite:
         specifier: 'catalog:'
-        version: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+        version: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
 
   internal/vite-config:
     dependencies:
@@ -1158,10 +1158,10 @@ importers:
         version: 2.0.3
       vite-plugin-pwa:
         specifier: 'catalog:'
-        version: 1.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(workbox-build@7.3.0)(workbox-window@7.3.0)
+        version: 1.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(workbox-build@7.3.0)(workbox-window@7.3.0)
       vite-plugin-vue-devtools:
         specifier: 'catalog:'
-        version: 7.7.7(rollup@4.44.1)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+        version: 7.7.7(rollup@4.44.1)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
     devDependencies:
       '@pnpm/workspace.read-manifest':
         specifier: 'catalog:'
@@ -1177,10 +1177,10 @@ importers:
         version: link:../node-utils
       '@vitejs/plugin-vue':
         specifier: 'catalog:'
-        version: 6.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+        version: 6.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
       '@vitejs/plugin-vue-jsx':
         specifier: 'catalog:'
-        version: 5.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+        version: 5.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
       dayjs:
         specifier: 'catalog:'
         version: 1.11.13
@@ -1198,16 +1198,16 @@ importers:
         version: 1.89.2
       vite:
         specifier: 'catalog:'
-        version: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+        version: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       vite-plugin-compression:
         specifier: 'catalog:'
-        version: 0.5.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+        version: 0.5.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       vite-plugin-dts:
         specifier: 'catalog:'
-        version: 4.5.4(@types/node@22.16.0)(rollup@4.44.1)(typescript@5.8.3)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+        version: 4.5.4(@types/node@24.9.2)(rollup@4.44.1)(typescript@5.8.3)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       vite-plugin-html:
         specifier: 'catalog:'
-        version: 3.2.2(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+        version: 3.2.2(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       vite-plugin-lazy-import:
         specifier: 'catalog:'
         version: 1.0.7
@@ -1553,7 +1553,7 @@ importers:
         version: 13.4.0(vue@3.5.17(typescript@5.8.3))
       '@vueuse/integrations':
         specifier: 'catalog:'
-        version: 13.4.0(async-validator@4.2.5)(axios@1.10.0)(focus-trap@7.6.4)(jwt-decode@4.0.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.17(typescript@5.8.3))
+        version: 14.0.0(async-validator@4.2.5)(axios@1.10.0)(focus-trap@7.6.4)(jwt-decode@4.0.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.17(typescript@5.8.3))
       json-bigint:
         specifier: 'catalog:'
         version: 1.0.0
@@ -4836,6 +4836,9 @@ packages:
   '@types/node@22.16.0':
     resolution: {integrity: sha512-B2egV9wALML1JCpv3VQoQ+yesQKAmNMBIAY7OteVrikcOcAkWm+dGL6qpeCktPjAv6N1JLnhbNiqS35UpFyBsQ==}
 
+  '@types/node@24.9.2':
+    resolution: {integrity: sha512-uWN8YqxXxqFMX2RqGOrumsKeti4LlmIMIyV0lgut4jx7KQBcBiW6vkDtIBvHnHIquwNfJhk8v2OtmO8zXWHfPA==}
+
   '@types/normalize-package-data@2.4.4':
     resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==}
 
@@ -5322,6 +5325,11 @@ packages:
     peerDependencies:
       vue: ^3.5.17
 
+  '@vueuse/core@14.0.0':
+    resolution: {integrity: sha512-d6tKRWkZE8IQElX2aHBxXOMD478fHIYV+Dzm2y9Ag122ICBpNKtGICiXKOhWU3L1kKdttDD9dCMS4bGP3jhCTQ==}
+    peerDependencies:
+      vue: ^3.5.17
+
   '@vueuse/core@9.13.0':
     resolution: {integrity: sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==}
 
@@ -5366,8 +5374,8 @@ packages:
       universal-cookie:
         optional: true
 
-  '@vueuse/integrations@13.4.0':
-    resolution: {integrity: sha512-rwNoE0MNJBUuSzTZcUVrkovtHvpWIySOcC6XpcS33ZarHDNhd9CPvCD4eNl3N0Phz1he1JV0iYULRyPQ5HCbFA==}
+  '@vueuse/integrations@14.0.0':
+    resolution: {integrity: sha512-5A0X7q9qyLtM3xyghq5nK/NEESf7cpcZlkQgXTMuW4JWiAMYxc1ImdhhGrk4negFBsq3ejvAlRmLdNrkcTzk1Q==}
     peerDependencies:
       async-validator: ^4
       axios: ^1
@@ -5380,7 +5388,7 @@ packages:
       nprogress: ^0.2
       qrcode: ^1.5
       sortablejs: ^1
-      universal-cookie: ^7
+      universal-cookie: ^7 || ^8
       vue: ^3.5.17
     peerDependenciesMeta:
       async-validator:
@@ -5417,6 +5425,9 @@ packages:
   '@vueuse/metadata@13.4.0':
     resolution: {integrity: sha512-CPDQ/IgOeWbqItg1c/pS+Ulum63MNbpJ4eecjFJqgD/JUCJ822zLfpw6M9HzSvL6wbzMieOtIAW/H8deQASKHg==}
 
+  '@vueuse/metadata@14.0.0':
+    resolution: {integrity: sha512-6yoGqbJcMldVCevkFiHDBTB1V5Hq+G/haPlGIuaFZHpXC0HADB0EN1ryQAAceiW+ryS3niUwvdFbGiqHqBrfVA==}
+
   '@vueuse/metadata@9.13.0':
     resolution: {integrity: sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==}
 
@@ -5441,6 +5452,11 @@ packages:
     peerDependencies:
       vue: ^3.5.17
 
+  '@vueuse/shared@14.0.0':
+    resolution: {integrity: sha512-mTCA0uczBgurRlwVaQHfG0Ja7UdGe4g9mwffiJmvLiTtp1G4AQyIjej6si/k8c8pUwTfVpNufck+23gXptPAkw==}
+    peerDependencies:
+      vue: ^3.5.17
+
   '@vueuse/shared@9.13.0':
     resolution: {integrity: sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==}
 
@@ -10972,6 +10988,9 @@ packages:
   undici-types@6.21.0:
     resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==}
 
+  undici-types@7.16.0:
+    resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==}
+
   undici@7.11.0:
     resolution: {integrity: sha512-heTSIac3iLhsmZhUCjyS3JQEkZELateufzZuBaVM5RHXdSBMb1LPMQf5x+FH7qjsZYDP0ttAc3nnVpUB+wYbOg==}
     engines: {node: '>=20.18.1'}
@@ -12983,11 +13002,11 @@ snapshots:
 
   '@colors/colors@1.6.0': {}
 
-  '@commitlint/cli@19.8.1(@types/node@22.16.0)(typescript@5.8.3)':
+  '@commitlint/cli@19.8.1(@types/node@24.9.2)(typescript@5.8.3)':
     dependencies:
       '@commitlint/format': 19.8.1
       '@commitlint/lint': 19.8.1
-      '@commitlint/load': 19.8.1(@types/node@22.16.0)(typescript@5.8.3)
+      '@commitlint/load': 19.8.1(@types/node@24.9.2)(typescript@5.8.3)
       '@commitlint/read': 19.8.1
       '@commitlint/types': 19.8.1
       tinyexec: 1.0.1
@@ -13034,7 +13053,7 @@ snapshots:
       '@commitlint/rules': 19.8.1
       '@commitlint/types': 19.8.1
 
-  '@commitlint/load@19.8.1(@types/node@22.16.0)(typescript@5.8.3)':
+  '@commitlint/load@19.8.1(@types/node@24.9.2)(typescript@5.8.3)':
     dependencies:
       '@commitlint/config-validator': 19.8.1
       '@commitlint/execute-rule': 19.8.1
@@ -13042,7 +13061,7 @@ snapshots:
       '@commitlint/types': 19.8.1
       chalk: 5.4.1
       cosmiconfig: 9.0.0(typescript@5.8.3)
-      cosmiconfig-typescript-loader: 6.1.0(@types/node@22.16.0)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3)
+      cosmiconfig-typescript-loader: 6.1.0(@types/node@24.9.2)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3)
       lodash.isplainobject: 4.0.6
       lodash.merge: 4.6.2
       lodash.uniq: 4.5.0
@@ -14078,23 +14097,23 @@ snapshots:
       - encoding
       - supports-color
 
-  '@microsoft/api-extractor-model@7.30.5(@types/node@22.16.0)':
+  '@microsoft/api-extractor-model@7.30.5(@types/node@24.9.2)':
     dependencies:
       '@microsoft/tsdoc': 0.15.1
       '@microsoft/tsdoc-config': 0.17.1
-      '@rushstack/node-core-library': 5.13.0(@types/node@22.16.0)
+      '@rushstack/node-core-library': 5.13.0(@types/node@24.9.2)
     transitivePeerDependencies:
       - '@types/node'
 
-  '@microsoft/api-extractor@7.52.5(@types/node@22.16.0)':
+  '@microsoft/api-extractor@7.52.5(@types/node@24.9.2)':
     dependencies:
-      '@microsoft/api-extractor-model': 7.30.5(@types/node@22.16.0)
+      '@microsoft/api-extractor-model': 7.30.5(@types/node@24.9.2)
       '@microsoft/tsdoc': 0.15.1
       '@microsoft/tsdoc-config': 0.17.1
-      '@rushstack/node-core-library': 5.13.0(@types/node@22.16.0)
+      '@rushstack/node-core-library': 5.13.0(@types/node@24.9.2)
       '@rushstack/rig-package': 0.5.3
-      '@rushstack/terminal': 0.15.2(@types/node@22.16.0)
-      '@rushstack/ts-command-line': 5.0.0(@types/node@22.16.0)
+      '@rushstack/terminal': 0.15.2(@types/node@24.9.2)
+      '@rushstack/ts-command-line': 5.0.0(@types/node@24.9.2)
       lodash: 4.17.21
       minimatch: 3.0.8
       resolve: 1.22.10
@@ -14223,19 +14242,19 @@ snapshots:
       '@nodelib/fs.scandir': 2.1.5
       fastq: 1.19.1
 
-  '@nolebase/ui@2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))':
+  '@nolebase/ui@2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))':
     dependencies:
       '@iconify-json/octicon': 1.2.7
       less: 4.3.0
-      vitepress: 1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
+      vitepress: 1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
       vue: 3.5.17(typescript@5.8.3)
     transitivePeerDependencies:
       - typescript
 
-  '@nolebase/vitepress-plugin-git-changelog@2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))':
+  '@nolebase/vitepress-plugin-git-changelog@2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))':
     dependencies:
       '@iconify-json/octicon': 1.2.7
-      '@nolebase/ui': 2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))
+      '@nolebase/ui': 2.18.0(typescript@5.8.3)(vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3))
       colorette: 2.0.20
       date-fns: 4.1.0
       defu: 6.1.4
@@ -14245,7 +14264,7 @@ snapshots:
       gray-matter: 4.0.3
       less: 4.3.0
       uncrypto: 0.1.3
-      vitepress: 1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
+      vitepress: 1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3)
     transitivePeerDependencies:
       - typescript
 
@@ -14763,7 +14782,7 @@ snapshots:
   '@rollup/rollup-win32-x64-msvc@4.46.2':
     optional: true
 
-  '@rushstack/node-core-library@5.13.0(@types/node@22.16.0)':
+  '@rushstack/node-core-library@5.13.0(@types/node@24.9.2)':
     dependencies:
       ajv: 8.13.0
       ajv-draft-04: 1.0.0(ajv@8.13.0)
@@ -14774,23 +14793,23 @@ snapshots:
       resolve: 1.22.10
       semver: 7.5.4
     optionalDependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
 
   '@rushstack/rig-package@0.5.3':
     dependencies:
       resolve: 1.22.10
       strip-json-comments: 3.1.1
 
-  '@rushstack/terminal@0.15.2(@types/node@22.16.0)':
+  '@rushstack/terminal@0.15.2(@types/node@24.9.2)':
     dependencies:
-      '@rushstack/node-core-library': 5.13.0(@types/node@22.16.0)
+      '@rushstack/node-core-library': 5.13.0(@types/node@24.9.2)
       supports-color: 8.1.1
     optionalDependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
 
-  '@rushstack/ts-command-line@5.0.0(@types/node@22.16.0)':
+  '@rushstack/ts-command-line@5.0.0(@types/node@24.9.2)':
     dependencies:
-      '@rushstack/terminal': 0.15.2(@types/node@22.16.0)
+      '@rushstack/terminal': 0.15.2(@types/node@24.9.2)
       '@types/argparse': 1.0.38
       argparse: 1.0.10
       string-argv: 0.3.2
@@ -14942,7 +14961,7 @@ snapshots:
 
   '@types/conventional-commits-parser@5.0.1':
     dependencies:
-      '@types/node': 22.15.3
+      '@types/node': 22.16.0
 
   '@types/deep-eql@4.0.2': {}
 
@@ -15023,6 +15042,10 @@ snapshots:
     dependencies:
       undici-types: 6.21.0
 
+  '@types/node@24.9.2':
+    dependencies:
+      undici-types: 7.16.0
+
   '@types/normalize-package-data@2.4.4': {}
 
   '@types/nprogress@0.2.3': {}
@@ -15041,7 +15064,7 @@ snapshots:
 
   '@types/readdir-glob@1.1.5':
     dependencies:
-      '@types/node': 22.15.3
+      '@types/node': 22.16.0
 
   '@types/resolve@1.20.2': {}
 
@@ -15061,7 +15084,7 @@ snapshots:
 
   '@types/yauzl@2.10.3':
     dependencies:
-      '@types/node': 22.15.3
+      '@types/node': 22.16.0
     optional: true
 
   '@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)':
@@ -15345,30 +15368,30 @@ snapshots:
       - rollup
       - supports-color
 
-  '@vite-pwa/vitepress@1.0.0(vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0))':
+  '@vite-pwa/vitepress@1.0.0(vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0))':
     dependencies:
-      vite-plugin-pwa: 1.0.1(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0)
+      vite-plugin-pwa: 1.0.1(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0)
 
-  '@vitejs/plugin-vue-jsx@5.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
+  '@vitejs/plugin-vue-jsx@5.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
     dependencies:
       '@babel/core': 7.27.7
       '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.7)
       '@rolldown/pluginutils': 1.0.0-beta.23
       '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.27.7)
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       vue: 3.5.17(typescript@5.8.3)
     transitivePeerDependencies:
       - supports-color
 
-  '@vitejs/plugin-vue@5.2.3(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(vue@3.5.17(typescript@5.8.3))':
+  '@vitejs/plugin-vue@5.2.3(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(vue@3.5.17(typescript@5.8.3))':
     dependencies:
-      vite: 5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
+      vite: 5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
       vue: 3.5.17(typescript@5.8.3)
 
-  '@vitejs/plugin-vue@6.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
+  '@vitejs/plugin-vue@6.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
     dependencies:
       '@rolldown/pluginutils': 1.0.0-beta.29
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       vue: 3.5.17(typescript@5.8.3)
 
   '@vitest/expect@3.2.4':
@@ -15379,13 +15402,13 @@ snapshots:
       chai: 5.2.0
       tinyrainbow: 2.0.0
 
-  '@vitest/mocker@3.2.4(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))':
+  '@vitest/mocker@3.2.4(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))':
     dependencies:
       '@vitest/spy': 3.2.4
       estree-walker: 3.0.3
       magic-string: 0.30.17
     optionalDependencies:
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
 
   '@vitest/pretty-format@3.2.4':
     dependencies:
@@ -15564,14 +15587,14 @@ snapshots:
     dependencies:
       '@vue/devtools-kit': 7.7.5
 
-  '@vue/devtools-core@7.7.7(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
+  '@vue/devtools-core@7.7.7(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))':
     dependencies:
       '@vue/devtools-kit': 7.7.7
       '@vue/devtools-shared': 7.7.7
       mitt: 3.0.1
       nanoid: 5.1.5
       pathe: 2.0.3
-      vite-hot-client: 2.0.4(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+      vite-hot-client: 2.0.4(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       vue: 3.5.17(typescript@5.8.3)
     transitivePeerDependencies:
       - vite
@@ -15687,6 +15710,13 @@ snapshots:
       '@vueuse/shared': 13.4.0(vue@3.5.17(typescript@5.8.3))
       vue: 3.5.17(typescript@5.8.3)
 
+  '@vueuse/core@14.0.0(vue@3.5.17(typescript@5.8.3))':
+    dependencies:
+      '@types/web-bluetooth': 0.0.21
+      '@vueuse/metadata': 14.0.0
+      '@vueuse/shared': 14.0.0(vue@3.5.17(typescript@5.8.3))
+      vue: 3.5.17(typescript@5.8.3)
+
   '@vueuse/core@9.13.0(vue@3.5.17(typescript@5.8.3))':
     dependencies:
       '@types/web-bluetooth': 0.0.16
@@ -15713,10 +15743,10 @@ snapshots:
     transitivePeerDependencies:
       - typescript
 
-  '@vueuse/integrations@13.4.0(async-validator@4.2.5)(axios@1.10.0)(focus-trap@7.6.4)(jwt-decode@4.0.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.17(typescript@5.8.3))':
+  '@vueuse/integrations@14.0.0(async-validator@4.2.5)(axios@1.10.0)(focus-trap@7.6.4)(jwt-decode@4.0.0)(nprogress@0.2.0)(qrcode@1.5.4)(sortablejs@1.15.6)(vue@3.5.17(typescript@5.8.3))':
     dependencies:
-      '@vueuse/core': 13.4.0(vue@3.5.17(typescript@5.8.3))
-      '@vueuse/shared': 13.4.0(vue@3.5.17(typescript@5.8.3))
+      '@vueuse/core': 14.0.0(vue@3.5.17(typescript@5.8.3))
+      '@vueuse/shared': 14.0.0(vue@3.5.17(typescript@5.8.3))
       vue: 3.5.17(typescript@5.8.3)
     optionalDependencies:
       async-validator: 4.2.5
@@ -15733,6 +15763,8 @@ snapshots:
 
   '@vueuse/metadata@13.4.0': {}
 
+  '@vueuse/metadata@14.0.0': {}
+
   '@vueuse/metadata@9.13.0': {}
 
   '@vueuse/motion@3.0.3(magicast@0.3.5)(vue@3.5.17(typescript@5.8.3))':
@@ -15770,6 +15802,10 @@ snapshots:
     dependencies:
       vue: 3.5.17(typescript@5.8.3)
 
+  '@vueuse/shared@14.0.0(vue@3.5.17(typescript@5.8.3))':
+    dependencies:
+      vue: 3.5.17(typescript@5.8.3)
+
   '@vueuse/shared@9.13.0(vue@3.5.17(typescript@5.8.3))':
     dependencies:
       vue-demi: 0.14.10(vue@3.5.17(typescript@5.8.3))
@@ -16617,9 +16653,9 @@ snapshots:
 
   core-util-is@1.0.3: {}
 
-  cosmiconfig-typescript-loader@6.1.0(@types/node@22.16.0)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3):
+  cosmiconfig-typescript-loader@6.1.0(@types/node@24.9.2)(cosmiconfig@9.0.0(typescript@5.8.3))(typescript@5.8.3):
     dependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
       cosmiconfig: 9.0.0(typescript@5.8.3)
       jiti: 2.4.2
       typescript: 5.8.3
@@ -17595,13 +17631,13 @@ snapshots:
     optionalDependencies:
       '@typescript-eslint/eslint-plugin': 8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)
 
-  eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)(vitest@3.2.4(@types/node@22.16.0)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  eslint-plugin-vitest@0.5.4(@typescript-eslint/eslint-plugin@8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)(vitest@3.2.4(@types/node@24.9.2)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
       '@typescript-eslint/utils': 7.18.0(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)
       eslint: 9.30.1(jiti@2.5.1)
     optionalDependencies:
       '@typescript-eslint/eslint-plugin': 8.35.1(@typescript-eslint/parser@8.35.1(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3))(eslint@9.30.1(jiti@2.5.1))(typescript@5.8.3)
-      vitest: 3.2.4(@types/node@22.16.0)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vitest: 3.2.4(@types/node@24.9.2)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - supports-color
       - typescript
@@ -21829,6 +21865,8 @@ snapshots:
 
   undici-types@6.21.0: {}
 
+  undici-types@7.16.0: {}
+
   undici@7.11.0: {}
 
   unenv@2.0.0-rc.18:
@@ -22084,17 +22122,17 @@ snapshots:
       '@types/unist': 3.0.3
       vfile-message: 4.0.2
 
-  vite-hot-client@2.0.4(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-hot-client@2.0.4(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
 
-  vite-node@3.2.4(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
+  vite-node@3.2.4(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
     dependencies:
       cac: 6.7.14
       debug: 4.4.1
       es-module-lexer: 1.7.0
       pathe: 2.0.3
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - '@types/node'
       - jiti
@@ -22109,18 +22147,18 @@ snapshots:
       - tsx
       - yaml
 
-  vite-plugin-compression@0.5.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-plugin-compression@0.5.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
       chalk: 4.1.2
       debug: 4.4.0
       fs-extra: 10.1.0
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - supports-color
 
-  vite-plugin-dts@4.5.4(@types/node@22.16.0)(rollup@4.44.1)(typescript@5.8.3)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-plugin-dts@4.5.4(@types/node@24.9.2)(rollup@4.44.1)(typescript@5.8.3)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
-      '@microsoft/api-extractor': 7.52.5(@types/node@22.16.0)
+      '@microsoft/api-extractor': 7.52.5(@types/node@24.9.2)
       '@rollup/pluginutils': 5.1.4(rollup@4.44.1)
       '@volar/typescript': 2.4.13
       '@vue/language-core': 2.2.0(typescript@5.8.3)
@@ -22131,13 +22169,13 @@ snapshots:
       magic-string: 0.30.17
       typescript: 5.8.3
     optionalDependencies:
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - '@types/node'
       - rollup
       - supports-color
 
-  vite-plugin-html@3.2.2(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-plugin-html@3.2.2(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
       '@rollup/pluginutils': 4.2.1
       colorette: 2.0.20
@@ -22151,9 +22189,9 @@ snapshots:
       html-minifier-terser: 6.1.0
       node-html-parser: 5.4.2
       pathe: 0.2.0
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
 
-  vite-plugin-inspect@0.8.9(rollup@4.44.1)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-plugin-inspect@0.8.9(rollup@4.44.1)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
       '@antfu/utils': 0.7.10
       '@rollup/pluginutils': 5.1.4(rollup@4.44.1)
@@ -22164,7 +22202,7 @@ snapshots:
       perfect-debounce: 1.0.0
       picocolors: 1.1.1
       sirv: 3.0.1
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - rollup
       - supports-color
@@ -22176,45 +22214,45 @@ snapshots:
       rollup: 4.44.1
       xe-utils: 3.7.4
 
-  vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0):
+  vite-plugin-pwa@1.0.1(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(workbox-build@7.3.0)(workbox-window@7.3.0):
     dependencies:
       debug: 4.4.0
       pretty-bytes: 6.1.1
       tinyglobby: 0.2.13
-      vite: 5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
+      vite: 5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
       workbox-build: 7.3.0
       workbox-window: 7.3.0
     transitivePeerDependencies:
       - supports-color
 
-  vite-plugin-pwa@1.0.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(workbox-build@7.3.0)(workbox-window@7.3.0):
+  vite-plugin-pwa@1.0.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(workbox-build@7.3.0)(workbox-window@7.3.0):
     dependencies:
       debug: 4.4.0
       pretty-bytes: 6.1.1
       tinyglobby: 0.2.13
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       workbox-build: 7.3.0
       workbox-window: 7.3.0
     transitivePeerDependencies:
       - supports-color
 
-  vite-plugin-vue-devtools@7.7.7(rollup@4.44.1)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)):
+  vite-plugin-vue-devtools@7.7.7(rollup@4.44.1)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3)):
     dependencies:
-      '@vue/devtools-core': 7.7.7(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
+      '@vue/devtools-core': 7.7.7(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))(vue@3.5.17(typescript@5.8.3))
       '@vue/devtools-kit': 7.7.7
       '@vue/devtools-shared': 7.7.7
       execa: 9.5.2
       sirv: 3.0.1
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
-      vite-plugin-inspect: 0.8.9(rollup@4.44.1)(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
-      vite-plugin-vue-inspector: 5.3.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite-plugin-inspect: 0.8.9(rollup@4.44.1)(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+      vite-plugin-vue-inspector: 5.3.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
     transitivePeerDependencies:
       - '@nuxt/kit'
       - rollup
       - supports-color
       - vue
 
-  vite-plugin-vue-inspector@5.3.1(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
+  vite-plugin-vue-inspector@5.3.1(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)):
     dependencies:
       '@babel/core': 7.26.10
       '@babel/plugin-proposal-decorators': 7.25.9(@babel/core@7.26.10)
@@ -22225,23 +22263,23 @@ snapshots:
       '@vue/compiler-dom': 3.5.13
       kolorist: 1.8.0
       magic-string: 0.30.17
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
     transitivePeerDependencies:
       - supports-color
 
-  vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0):
+  vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0):
     dependencies:
       esbuild: 0.25.3
       postcss: 8.5.3
       rollup: 4.40.1
     optionalDependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
       fsevents: 2.3.3
       less: 4.3.0
       sass: 1.89.2
       terser: 5.39.0
 
-  vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
+  vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
     dependencies:
       esbuild: 0.25.3
       fdir: 6.4.6(picomatch@4.0.3)
@@ -22250,7 +22288,7 @@ snapshots:
       rollup: 4.44.1
       tinyglobby: 0.2.14
     optionalDependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
       fsevents: 2.3.3
       jiti: 2.5.1
       less: 4.3.0
@@ -22258,17 +22296,17 @@ snapshots:
       terser: 5.39.0
       yaml: 2.8.0
 
-  vitepress-plugin-group-icons@1.6.1(markdown-it@14.1.0)(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)):
+  vitepress-plugin-group-icons@1.6.1(markdown-it@14.1.0)(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)):
     dependencies:
       '@iconify-json/logos': 1.2.4
       '@iconify-json/vscode-icons': 1.2.23
       '@iconify/utils': 2.3.0
       markdown-it: 14.1.0
-      vite: 5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
+      vite: 5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
     transitivePeerDependencies:
       - supports-color
 
-  vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@22.16.0)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3):
+  vitepress@1.6.3(@algolia/client-search@5.23.4)(@types/node@24.9.2)(async-validator@4.2.5)(axios@1.10.0)(jwt-decode@4.0.0)(less@4.3.0)(nprogress@0.2.0)(postcss@8.5.6)(qrcode@1.5.4)(sass@1.89.2)(search-insights@2.17.3)(sortablejs@1.15.6)(terser@5.39.0)(typescript@5.8.3):
     dependencies:
       '@docsearch/css': 3.8.2
       '@docsearch/js': 3.8.2(@algolia/client-search@5.23.4)(search-insights@2.17.3)
@@ -22277,7 +22315,7 @@ snapshots:
       '@shikijs/transformers': 2.5.0
       '@shikijs/types': 2.5.0
       '@types/markdown-it': 14.1.2
-      '@vitejs/plugin-vue': 5.2.3(vite@5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(vue@3.5.17(typescript@5.8.3))
+      '@vitejs/plugin-vue': 5.2.3(vite@5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0))(vue@3.5.17(typescript@5.8.3))
       '@vue/devtools-api': 7.7.5
       '@vue/shared': 3.5.13
       '@vueuse/core': 12.8.2(typescript@5.8.3)
@@ -22286,7 +22324,7 @@ snapshots:
       mark.js: 8.11.1
       minisearch: 7.1.2
       shiki: 2.5.0
-      vite: 5.4.18(@types/node@22.16.0)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
+      vite: 5.4.18(@types/node@24.9.2)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)
       vue: 3.5.17(typescript@5.8.3)
     optionalDependencies:
       postcss: 8.5.6
@@ -22317,11 +22355,11 @@ snapshots:
       - typescript
       - universal-cookie
 
-  vitest@3.2.4(@types/node@22.16.0)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
+  vitest@3.2.4(@types/node@24.9.2)(happy-dom@17.6.3)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0):
     dependencies:
       '@types/chai': 5.2.2
       '@vitest/expect': 3.2.4
-      '@vitest/mocker': 3.2.4(vite@7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
+      '@vitest/mocker': 3.2.4(vite@7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0))
       '@vitest/pretty-format': 3.2.4
       '@vitest/runner': 3.2.4
       '@vitest/snapshot': 3.2.4
@@ -22339,11 +22377,11 @@ snapshots:
       tinyglobby: 0.2.14
       tinypool: 1.1.1
       tinyrainbow: 2.0.0
-      vite: 7.1.2(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
-      vite-node: 3.2.4(@types/node@22.16.0)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite: 7.1.2(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
+      vite-node: 3.2.4(@types/node@24.9.2)(jiti@2.5.1)(less@4.3.0)(sass@1.89.2)(terser@5.39.0)(yaml@2.8.0)
       why-is-node-running: 2.3.0
     optionalDependencies:
-      '@types/node': 22.16.0
+      '@types/node': 24.9.2
       happy-dom: 17.6.3
     transitivePeerDependencies:
       - jiti

+ 2 - 2
pnpm-workspace.yaml

@@ -48,7 +48,7 @@ catalog:
   '@types/lodash.get': ^4.4.9
   '@types/lodash.isequal': ^4.5.8
   '@types/lodash.set': ^4.3.9
-  '@types/node': ^22.16.0
+  '@types/node': ^24.9.2
   '@types/nprogress': ^0.2.3
   '@types/postcss-import': ^14.0.3
   '@types/qrcode': ^1.5.5
@@ -64,7 +64,7 @@ catalog:
   '@vue/shared': ^3.5.17
   '@vue/test-utils': ^2.4.6
   '@vueuse/core': ^13.4.0
-  '@vueuse/integrations': ^13.4.0
+  '@vueuse/integrations': ^14.0.0
   '@vueuse/motion': ^3.0.3
   ant-design-vue: ^4.2.6
   archiver: ^7.0.1