diff --git a/WonderQ-Admin-UI-Vue/.env.example b/WonderQ-Admin-UI-Vue/.env.example new file mode 100644 index 0000000..c1f7768 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/.env.example @@ -0,0 +1,2 @@ +VITE_API_BASE_URL= +VITE_API_PROXY_TARGET=http://localhost:4000 diff --git a/WonderQ-Admin-UI-Vue/README.md b/WonderQ-Admin-UI-Vue/README.md new file mode 100644 index 0000000..85eaa4b --- /dev/null +++ b/WonderQ-Admin-UI-Vue/README.md @@ -0,0 +1,28 @@ +# WonderQ Admin UI Vue + +WonderQ 管理端 Vue3 迁移端,采用 Vue 3、Element Plus、TypeScript、Pinia 和 Vue Router 4。 + +## 启动 + +```powershell +yarn install +yarn dev +``` + +开发地址:http://localhost:5604/admin/ + +默认通过 Vite `/api` 代理访问 `http://localhost:4000`,可使用 `VITE_API_PROXY_TARGET` 覆盖。生产构建使用 `yarn build`,静态产物由反向代理挂载到 `/admin`。 + +## 认证约定 + +- Access Token 只保存在运行时内存,不写入 localStorage。 +- Refresh Token 由后端以 HttpOnly Cookie 保存。 +- 401 会自动调用 `/api/admin/auth/refresh` 并重试一次;刷新失败后返回登录页。 +- 菜单和按钮权限来自 `/api/admin/system/profile`,前端只加载预注册组件。 + +## 验证 + +```powershell +yarn test +yarn build +``` diff --git a/WonderQ-Admin-UI-Vue/index.html b/WonderQ-Admin-UI-Vue/index.html new file mode 100644 index 0000000..e1179b7 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/index.html @@ -0,0 +1,13 @@ + + + + + + + WonderQ 管理端 + + +
+ + + diff --git a/WonderQ-Admin-UI-Vue/package.json b/WonderQ-Admin-UI-Vue/package.json new file mode 100644 index 0000000..557f72b --- /dev/null +++ b/WonderQ-Admin-UI-Vue/package.json @@ -0,0 +1,29 @@ +{ + "name": "wonderq-admin-ui-vue", + "version": "0.1.0", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "build": "tsc --noEmit && vite build", + "test": "vitest run", + "preview": "vite preview" + }, + "dependencies": { + "element-plus": "^2.11.3", + "pinia": "^3.0.3", + "vue": "^3.5.18", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@vitejs/plugin-vue": "^6.0.1", + "@rollup/rollup-win32-x64-msvc": "4.63.0", + "@rolldown/binding-win32-x64-msvc": "1.2.5", + "@types/node": "^24.0.0", + "lightningcss-win32-x64-msvc": "1.33.0", + "typescript": "^6.0.3", + "vite": "^8.1.0", + "vitest": "^3.2.4", + "vue-tsc": "^3.0.6" + } +} diff --git a/WonderQ-Admin-UI-Vue/src/App.vue b/WonderQ-Admin-UI-Vue/src/App.vue new file mode 100644 index 0000000..7c2aa3f --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/WonderQ-Admin-UI-Vue/src/api/client.ts b/WonderQ-Admin-UI-Vue/src/api/client.ts new file mode 100644 index 0000000..f95a264 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/api/client.ts @@ -0,0 +1,105 @@ +import type { ApiErrorResponse, ApiResponse, AuthPayload, AdminProfile, Dashboard, Lead, SiteConfig, WanfaCategory, ConciergeAdvisor } from "@/types"; + +const API_BASE = import.meta.env.VITE_API_BASE_URL ?? ""; +let accessToken: string | null = null; +let refreshPromise: Promise | null = null; + +export class ApiRequestError extends Error { + constructor( + message: string, + readonly statusCode: number, + readonly errorCode?: string, + readonly details?: unknown, + ) { + super(message); + this.name = "ApiRequestError"; + } +} + +export class AuthExpiredError extends ApiRequestError { + constructor(message = "登录已失效,请重新登录") { + super(message, 401, "AUTH_EXPIRED"); + this.name = "AuthExpiredError"; + } +} + +export function setAccessToken(token: string | null) { + accessToken = token; +} + +export function getAccessToken() { + return accessToken; +} + +function isRecord(value: unknown): value is Record { + return typeof value === "object" && value !== null; +} + +async function parseJson(response: Response): Promise { + return response.json().catch(() => null); +} + +function unwrap(payload: unknown, statusCode: number): T { + if (!isRecord(payload) || typeof payload.code !== "number" || payload.code !== statusCode || typeof payload.msg !== "string" || !Object.prototype.hasOwnProperty.call(payload, "data")) { + throw new ApiRequestError("接口响应格式不正确", statusCode, "API_PROTOCOL_ERROR"); + } + if (statusCode < 200 || statusCode >= 300) { + if (payload.data !== null) throw new ApiRequestError("接口响应格式不正确", statusCode, "API_PROTOCOL_ERROR"); + const error = payload as unknown as ApiErrorResponse; + throw new ApiRequestError(error.msg, statusCode, error.errorCode, error.details); + } + if (payload.msg !== "success") throw new ApiRequestError("接口响应格式不正确", statusCode, "API_PROTOCOL_ERROR"); + return payload.data as T; +} + +async function rawRequest(path: string, options: RequestInit = {}): Promise { + const headers = new Headers(options.headers); + if (!(options.body instanceof FormData)) headers.set("Content-Type", "application/json"); + if (accessToken) headers.set("Authorization", `Bearer ${accessToken}`); + return fetch(`${API_BASE}${path}`, { ...options, headers, credentials: "include" }); +} + +export async function refreshAccessToken(): Promise { + const response = await rawRequest("/api/admin/auth/refresh", { method: "POST" }); + const payload = unwrap(await parseJson(response), response.status); + setAccessToken(payload.accessToken || payload.token); + return payload; +} + +async function refreshOnce() { + if (!refreshPromise) { + refreshPromise = refreshAccessToken().finally(() => { + refreshPromise = null; + }); + } + return refreshPromise; +} + +export async function request(path: string, options: RequestInit = {}, retry = true): Promise { + const response = await rawRequest(path, options); + if (response.status === 401 && retry && !path.includes("/auth/login") && !path.includes("/auth/refresh") && !path.includes("/auth/logout")) { + try { + await refreshOnce(); + return request(path, options, false); + } catch { + setAccessToken(null); + throw new AuthExpiredError(); + } + } + return unwrap(await parseJson(response), response.status); +} + +export const login = (email: string, password: string) => request("/api/admin/auth/login", { method: "POST", body: JSON.stringify({ email, password }) }, false); +export const getProfile = () => request("/api/admin/system/profile"); +export const logout = () => request<{ ok: boolean }>("/api/admin/auth/logout", { method: "POST" }, false); +export const getDashboard = () => request("/api/admin/dashboard"); +export const getSiteConfig = () => request("/api/admin/site-config"); +export const getWanfa = async () => (await request<{ categories: WanfaCategory[] }>("/api/admin/wanfa/categories")).categories; +export const getConcierge = async () => (await request<{ advisors: ConciergeAdvisor[] }>("/api/admin/concierge/advisors")).advisors; +export const getLeads = () => request<{ items: Lead[] }>("/api/admin/leads?take=50"); +export const updateLeadStatus = (leadId: string, status: string) => + request(`/api/admin/leads/${leadId}/status`, { + method: "PATCH", + body: JSON.stringify({ status }), + }); +export const getSystemResource = (resource: string) => request<{ items: unknown[] }>(`/api/admin/system/${resource}`); diff --git a/WonderQ-Admin-UI-Vue/src/components/MenuTree.vue b/WonderQ-Admin-UI-Vue/src/components/MenuTree.vue new file mode 100644 index 0000000..1b43e72 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/components/MenuTree.vue @@ -0,0 +1,17 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/directives/permission.ts b/WonderQ-Admin-UI-Vue/src/directives/permission.ts new file mode 100644 index 0000000..e3facae --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/directives/permission.ts @@ -0,0 +1,12 @@ +import type { ObjectDirective } from "vue"; +import { useAuthStore } from "@/stores/auth"; + +export const permissionDirective: ObjectDirective = { + mounted(element, binding) { + const permission = binding.value; + if (!permission || !useAuthStore().hasPermission(permission)) { + element.style.display = "none"; + element.setAttribute("aria-hidden", "true"); + } + }, +}; diff --git a/WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue b/WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue new file mode 100644 index 0000000..22eec8a --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/layouts/AdminLayout.vue @@ -0,0 +1,49 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/lib/menu.test.ts b/WonderQ-Admin-UI-Vue/src/lib/menu.test.ts new file mode 100644 index 0000000..6d1f3f2 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/lib/menu.test.ts @@ -0,0 +1,15 @@ +import { describe, expect, it } from "vitest"; + +function visibleMenuPaths(menus: Array<{ type: string; path?: string | null; isVisible?: boolean }>) { + return menus.filter((menu) => menu.type !== "button" && menu.isVisible !== false && menu.path).map((menu) => menu.path); +} + +describe("dynamic admin menu", () => { + it("keeps only visible navigable pages", () => { + expect(visibleMenuPaths([ + { type: "page", path: "/dashboard", isVisible: true }, + { type: "page", path: "/hidden", isVisible: false }, + { type: "button", path: null, isVisible: true }, + ])).toEqual(["/dashboard"]); + }); +}); diff --git a/WonderQ-Admin-UI-Vue/src/main.ts b/WonderQ-Admin-UI-Vue/src/main.ts new file mode 100644 index 0000000..24a1550 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/main.ts @@ -0,0 +1,11 @@ +import { createApp } from "vue"; +import { createPinia } from "pinia"; +import ElementPlus from "element-plus"; +import "element-plus/dist/index.css"; +import App from "./App.vue"; +import router from "./router"; +import "./styles.css"; +import { permissionDirective } from "./directives/permission"; + +const app = createApp(App); +app.use(createPinia()).use(router).use(ElementPlus).directive("permission", permissionDirective).mount("#app"); diff --git a/WonderQ-Admin-UI-Vue/src/pages/ConciergePage.vue b/WonderQ-Admin-UI-Vue/src/pages/ConciergePage.vue new file mode 100644 index 0000000..d521682 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/ConciergePage.vue @@ -0,0 +1,10 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/DashboardPage.vue b/WonderQ-Admin-UI-Vue/src/pages/DashboardPage.vue new file mode 100644 index 0000000..d3c1777 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/DashboardPage.vue @@ -0,0 +1,29 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/HomePage.vue b/WonderQ-Admin-UI-Vue/src/pages/HomePage.vue new file mode 100644 index 0000000..96c06f3 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/HomePage.vue @@ -0,0 +1,14 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/LeadsPage.vue b/WonderQ-Admin-UI-Vue/src/pages/LeadsPage.vue new file mode 100644 index 0000000..3b29a23 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/LeadsPage.vue @@ -0,0 +1,29 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/LoginPage.vue b/WonderQ-Admin-UI-Vue/src/pages/LoginPage.vue new file mode 100644 index 0000000..e0b2fb8 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/LoginPage.vue @@ -0,0 +1,42 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/NotFoundPage.vue b/WonderQ-Admin-UI-Vue/src/pages/NotFoundPage.vue new file mode 100644 index 0000000..7da7ac5 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/NotFoundPage.vue @@ -0,0 +1 @@ + diff --git a/WonderQ-Admin-UI-Vue/src/pages/SystemResourcePage.vue b/WonderQ-Admin-UI-Vue/src/pages/SystemResourcePage.vue new file mode 100644 index 0000000..c009361 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/SystemResourcePage.vue @@ -0,0 +1,12 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/pages/WanfaPage.vue b/WonderQ-Admin-UI-Vue/src/pages/WanfaPage.vue new file mode 100644 index 0000000..dcc7f34 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/pages/WanfaPage.vue @@ -0,0 +1,10 @@ + + + diff --git a/WonderQ-Admin-UI-Vue/src/router/index.ts b/WonderQ-Admin-UI-Vue/src/router/index.ts new file mode 100644 index 0000000..42687f0 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/router/index.ts @@ -0,0 +1,80 @@ +import { createRouter, createWebHistory } from "vue-router"; +import { useAuthStore } from "@/stores/auth"; +import AdminLayout from "@/layouts/AdminLayout.vue"; +import LoginPage from "@/pages/LoginPage.vue"; +import DashboardPage from "@/pages/DashboardPage.vue"; +import HomePage from "@/pages/HomePage.vue"; +import WanfaPage from "@/pages/WanfaPage.vue"; +import ConciergePage from "@/pages/ConciergePage.vue"; +import LeadsPage from "@/pages/LeadsPage.vue"; +import SystemResourcePage from "@/pages/SystemResourcePage.vue"; +import NotFoundPage from "@/pages/NotFoundPage.vue"; + +const componentRegistry = { + Dashboard: DashboardPage, + HomePage, + WanfaPage, + ConciergePage, + LeadsPage, + SystemUsers: SystemResourcePage, + SystemRoles: SystemResourcePage, + SystemMenus: SystemResourcePage, + SystemDepts: SystemResourcePage, +}; + +const router = createRouter({ + history: createWebHistory(import.meta.env.BASE_URL), + routes: [ + { path: "/login", name: "login", component: LoginPage, meta: { public: true } }, + { + path: "/", + name: "admin", + component: AdminLayout, + children: [ + { path: "dashboard", name: "dashboard", component: DashboardPage }, + { path: "home", name: "home", component: HomePage }, + { path: "play", name: "play", component: WanfaPage }, + { path: "concierge", name: "concierge", component: ConciergePage }, + { path: "leads", name: "leads", component: LeadsPage }, + { path: "system/:resource", name: "system-resource", component: SystemResourcePage }, + { path: "", redirect: "/dashboard" }, + ], + }, + { path: "/:pathMatch(.*)*", name: "not-found", component: NotFoundPage }, + ], +}); + +let dynamicRoutesRegistered = false; + +function registerDynamicRoutes() { + if (dynamicRoutesRegistered) return; + const auth = useAuthStore(); + for (const menu of auth.menus) { + if (menu.type !== "page" || !menu.path || !menu.component || !(menu.component in componentRegistry)) continue; + const path = menu.path.replace(/^\/+/, ""); + if (router.getRoutes().some((route) => route.path === `/${path}`)) continue; + router.addRoute("admin", { + path, + name: `dynamic-${menu.id}`, + component: componentRegistry[menu.component as keyof typeof componentRegistry], + meta: { permission: menu.permission }, + }); + } + dynamicRoutesRegistered = true; +} + +router.beforeEach(async (to) => { + const auth = useAuthStore(); + if (to.meta.public) { + if (to.name === "login" && auth.isAuthenticated) return { name: "dashboard" }; + return true; + } + await auth.bootstrap(); + if (!auth.isAuthenticated) return { name: "login", query: { redirect: to.fullPath } }; + registerDynamicRoutes(); + const permission = to.meta.permission; + if (typeof permission === "string" && !auth.hasPermission(permission)) return { name: "not-found" }; + return true; +}); + +export default router; diff --git a/WonderQ-Admin-UI-Vue/src/stores/auth.ts b/WonderQ-Admin-UI-Vue/src/stores/auth.ts new file mode 100644 index 0000000..9662c42 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/stores/auth.ts @@ -0,0 +1,70 @@ +import { computed, ref } from "vue"; +import { defineStore } from "pinia"; +import * as api from "@/api/client"; +import type { AdminMenu, AdminProfile, AdminUser } from "@/types"; + +export const useAuthStore = defineStore("auth", () => { + const user = ref(null); + const menus = ref([]); + const permissions = ref([]); + const initialized = ref(false); + const loading = ref(false); + const isAuthenticated = computed(() => Boolean(user.value && api.getAccessToken())); + + function applyProfile(profile: AdminProfile) { + user.value = profile.user; + menus.value = profile.menus; + permissions.value = profile.permissions; + } + + async function loadProfile() { + applyProfile(await api.getProfile()); + } + + async function bootstrap() { + if (initialized.value) return; + loading.value = true; + try { + const session = await api.refreshAccessToken(); + user.value = session.user; + await loadProfile(); + } catch { + api.setAccessToken(null); + user.value = null; + menus.value = []; + permissions.value = []; + } finally { + initialized.value = true; + loading.value = false; + } + } + + async function login(email: string, password: string) { + loading.value = true; + try { + const session = await api.login(email, password); + api.setAccessToken(session.accessToken || session.token); + user.value = session.user; + await loadProfile(); + } finally { + loading.value = false; + } + } + + async function logout() { + try { + await api.logout(); + } finally { + api.setAccessToken(null); + user.value = null; + menus.value = []; + permissions.value = []; + } + } + + function hasPermission(permission: string) { + return permissions.value.includes("*") || permissions.value.includes(permission); + } + + return { user, menus, permissions, initialized, loading, isAuthenticated, bootstrap, login, logout, hasPermission }; +}); diff --git a/WonderQ-Admin-UI-Vue/src/styles.css b/WonderQ-Admin-UI-Vue/src/styles.css new file mode 100644 index 0000000..0e6bfef --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/styles.css @@ -0,0 +1,69 @@ +:root { + color: #1e293b; + background: #f5f7fb; + font-family: Inter, "PingFang SC", "Microsoft YaHei", sans-serif; + font-synthesis: none; + --ink: #1e293b; + --muted: #64748b; + --line: #e7ebf2; + --blue: #2563eb; + --surface: #ffffff; +} + +* { box-sizing: border-box; } +body { margin: 0; min-width: 320px; background: #f5f7fb; } +button, input { font: inherit; } +.admin-shell { min-height: 100vh; } +.admin-aside { position: relative; display: flex; flex-direction: column; border-right: 1px solid #e9edf3; background: #fff; } +.brand { display: flex; align-items: center; gap: 11px; padding: 25px 22px 23px; border-bottom: 1px solid #f0f2f6; } +.brand strong { display: block; letter-spacing: .02em; font-size: 16px; } +.brand span { display: block; color: #94a3b8; font-size: 11px; margin-top: 3px; } +.brand-mark { display: grid; place-items: center; width: 35px; height: 35px; border-radius: 10px; color: #fff; background: #1d4ed8; font-size: 11px; font-weight: 800; letter-spacing: .08em; } +.sidebar-menu { border-right: 0; padding: 14px 10px; } +.sidebar-menu .el-menu-item, .sidebar-menu .el-sub-menu__title { border-radius: 8px; margin: 3px 0; color: #64748b; } +.sidebar-menu .el-menu-item.is-active { color: #1d4ed8; background: #eff6ff; font-weight: 650; } +.aside-note { padding: 16px 22px 20px; color: #94a3b8; font-size: 11px; } +.admin-header { display: flex; justify-content: space-between; align-items: center; height: 88px; padding: 0 40px; border-bottom: 1px solid var(--line); background: rgba(255,255,255,.82); } +.eyebrow { margin: 0 0 7px; color: #2563eb; font-size: 10px; font-weight: 800; letter-spacing: .16em; } +.admin-header h1, .page-intro h2 { margin: 0; color: var(--ink); font-size: 23px; line-height: 1.2; } +.header-actions { display: flex; align-items: center; gap: 15px; } +.user-name { color: #475569; font-size: 13px; } +.admin-main { padding: 34px 40px 54px; } +.page-stack { max-width: 1220px; margin: 0 auto; } +.page-intro { display: flex; justify-content: space-between; align-items: flex-end; gap: 24px; margin-bottom: 26px; } +.page-intro p:not(.eyebrow) { margin: 9px 0 0; color: var(--muted); font-size: 13px; } +.metric-grid, .module-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; margin-bottom: 20px; } +.metric-card, .module-card, .panel-card, .advisor-card { border: 1px solid var(--line); border-radius: 12px; } +.metric-card { position: relative; min-height: 145px; overflow: hidden; } +.metric-card::after { content: ""; position: absolute; right: -28px; bottom: -46px; width: 130px; height: 130px; border-radius: 50%; background: #eff6ff; } +.metric-card.accent::after { background: #ecfdf5; } +.metric-card span, .metric-card small, .module-card small { display: block; color: var(--muted); font-size: 12px; } +.metric-card strong { display: block; margin: 14px 0 5px; color: var(--ink); font-size: 34px; line-height: 1; } +.metric-card small { color: #94a3b8; } +.panel-heading { display: flex; justify-content: space-between; align-items: center; font-weight: 650; } +.loading-grid { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 16px; } +.module-card { display: flex; flex-direction: column; gap: 8px; min-height: 140px; } +.module-label { color: #475569; font-weight: 650; } +.module-card strong { font-size: 29px; } +.module-card .el-button { align-self: flex-start; padding-left: 0; } +.category-list { display: grid; gap: 16px; } +.advisor-grid { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 16px; } +.advisor-card { display: flex; align-items: center; gap: 12px; } +.advisor-card > div:nth-child(2) { flex: 1; } +.advisor-card strong, .advisor-card span { display: block; } +.advisor-card span { margin-top: 4px; color: var(--muted); font-size: 12px; } +.advisor-avatar { display: grid; place-items: center; width: 42px; height: 42px; border-radius: 50%; color: #1d4ed8; background: #dbeafe; font-weight: 700; } +.json-preview { max-height: 220px; overflow: auto; margin: 0; color: #475569; font-size: 12px; white-space: pre-wrap; } +.login-page { display: grid; grid-template-columns: minmax(0, 1fr) 420px; min-height: 100vh; padding: 5vw 9vw; gap: 8vw; align-items: center; background: #f8fafc; } +.login-art { max-width: 560px; } +.login-art h1 { margin: 18px 0; color: #172554; font-size: clamp(34px, 4vw, 61px); letter-spacing: -.05em; line-height: 1.07; } +.login-art em { color: #2563eb; font-style: normal; } +.login-art > p:last-child { max-width: 390px; color: #64748b; line-height: 1.9; } +.login-card { padding: 30px; border: 1px solid #e2e8f0; border-radius: 16px; } +.login-card-heading { display: flex; align-items: center; gap: 12px; margin-bottom: 30px; } +.login-card-heading h2 { margin: 0; font-size: 22px; } +.login-card-heading p { margin: 5px 0 0; color: var(--muted); font-size: 13px; } +.login-error { margin: 4px 0 17px; } +.login-button { width: 100%; height: 42px; } +@media (max-width: 900px) { .login-page { grid-template-columns: 1fr; padding: 48px 24px; gap: 24px; } .login-art { max-width: none; } .login-art h1 { font-size: 38px; } .login-card { max-width: 520px; width: 100%; } .admin-header { padding: 0 22px; } .admin-main { padding: 26px 22px 40px; } .advisor-grid { grid-template-columns: repeat(2, minmax(0, 1fr)); } } +@media (max-width: 640px) { .admin-aside { width: 0 !important; display: none; } .admin-header { height: 76px; } .admin-header h1 { font-size: 19px; } .header-actions .el-tag, .user-name { display: none; } .metric-grid, .module-grid, .loading-grid, .advisor-grid { grid-template-columns: 1fr; } .page-intro { align-items: flex-start; flex-direction: column; } .admin-main { padding: 22px 14px 32px; } } diff --git a/WonderQ-Admin-UI-Vue/src/types.ts b/WonderQ-Admin-UI-Vue/src/types.ts new file mode 100644 index 0000000..9fda32f --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/types.ts @@ -0,0 +1,81 @@ +export type ApiResponse = { + code: number; + msg: string; + data: T; + errorCode?: string; + details?: unknown; +}; + +export type ApiErrorResponse = { + code: number; + msg: string; + data: null; + errorCode?: string; + details?: unknown; +}; + +export type AdminUser = { + id: string; + email: string; + name: string; + role: string; + isActive?: boolean; +}; + +export type AdminMenu = { + id: string; + parentId?: string | null; + name: string; + type: "directory" | "page" | "button"; + path?: string | null; + component?: string | null; + permission?: string | null; + icon?: string | null; + children?: AdminMenu[]; + sortOrder?: number; +}; + +export type AdminProfile = { + user: AdminUser; + roles: Array<{ id: string; name: string; code: string; dataScope: string }>; + permissions: string[]; + menus: AdminMenu[]; + dataScopes: string[]; +}; + +export type AuthPayload = { + token: string; + accessToken: string; + expiresIn: number; + user: AdminUser; +}; + +export type Dashboard = { + stats: { newLeadCount: number; leadCount: number }; + recentLeads: Lead[]; +}; + +export type Lead = { + id: string; + contactName?: string | null; + phone: string; + destination?: string | null; + status: string; + leadType?: string; + createdAt?: string; +}; + +export type WanfaCategory = { + id: string; + label: string; + routes: Array<{ id: string; title: string; subtitle: string; routeCount: number }>; +}; + +export type ConciergeAdvisor = { + id: string; + name: string; + role: string; + isActive: boolean; +}; + +export type SiteConfig = Record; diff --git a/WonderQ-Admin-UI-Vue/src/vite-env.d.ts b/WonderQ-Admin-UI-Vue/src/vite-env.d.ts new file mode 100644 index 0000000..920f14e --- /dev/null +++ b/WonderQ-Admin-UI-Vue/src/vite-env.d.ts @@ -0,0 +1,7 @@ +/// + +declare module "*.vue" { + import type { DefineComponent } from "vue"; + const component: DefineComponent, Record, unknown>; + export default component; +} diff --git a/WonderQ-Admin-UI-Vue/tsconfig.json b/WonderQ-Admin-UI-Vue/tsconfig.json new file mode 100644 index 0000000..eed3335 --- /dev/null +++ b/WonderQ-Admin-UI-Vue/tsconfig.json @@ -0,0 +1,23 @@ +{ + "compilerOptions": { + "target": "ES2022", + "useDefineForClassFields": true, + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "allowJs": false, + "skipLibCheck": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "strict": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "ignoreDeprecations": "6.0", + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + } + }, + "include": ["src", "vite.config.ts"] +} diff --git a/WonderQ-Admin-UI-Vue/vite.config.ts b/WonderQ-Admin-UI-Vue/vite.config.ts new file mode 100644 index 0000000..3dd01ba --- /dev/null +++ b/WonderQ-Admin-UI-Vue/vite.config.ts @@ -0,0 +1,26 @@ +import { defineConfig, loadEnv } from "vite"; +import vue from "@vitejs/plugin-vue"; +import path from "node:path"; + +export default defineConfig(({ mode }) => { + const env = loadEnv(mode, process.cwd(), ""); + return { + base: "/admin/", + plugins: [vue()], + resolve: { + alias: { "@": path.resolve(__dirname, "./src") }, + }, + server: { + host: "0.0.0.0", + port: 5604, + strictPort: true, + proxy: { + "/api": { + target: env.VITE_API_PROXY_TARGET || "http://localhost:4000", + changeOrigin: true, + }, + }, + }, + preview: { host: "0.0.0.0", port: 5605, strictPort: true }, + }; +}); diff --git a/WonderQ-Admin-UI-Vue/yarn.lock b/WonderQ-Admin-UI-Vue/yarn.lock new file mode 100644 index 0000000..835899f --- /dev/null +++ b/WonderQ-Admin-UI-Vue/yarn.lock @@ -0,0 +1,1296 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/helper-string-parser@^7.29.7": + version "7.29.7" + resolved "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f" + integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw== + +"@babel/helper-validator-identifier@^7.29.7": + version "7.29.7" + resolved "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2" + integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg== + +"@babel/parser@^7.29.8": + version "7.29.8" + resolved "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.8.tgz#9653716a2f10c677b98fbc63d4bfb000c302cf17" + integrity sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA== + dependencies: + "@babel/types" "^7.29.8" + +"@babel/types@^7.29.8": + version "7.29.8" + resolved "https://registry.npmmirror.com/@babel/types/-/types-7.29.8.tgz#1229eef31d85156d70fa3f4cd859376d0eaf6863" + integrity sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg== + dependencies: + "@babel/helper-string-parser" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + +"@ctrl/tinycolor@^4.2.0": + version "4.2.0" + resolved "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz#ba5d0b917303c0b3d3c14c4865cdc6ded25ac05f" + integrity sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A== + +"@element-plus/icons-vue@^2.3.2": + version "2.3.2" + resolved "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz#7e9cb231fb738b2056f33e22c3a29e214b538dcf" + integrity sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A== + +"@esbuild/aix-ppc64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz#bf6e10303bcf2e7c686975fa52f937ec2728d8bc" + integrity sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ== + +"@esbuild/android-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz#0c6246bc8d2c4d172aac2db3fb1190d72bd65504" + integrity sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A== + +"@esbuild/android-arm@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.28.2.tgz#2d84ece6a4e2684d92be26ee13d42757d831c381" + integrity sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg== + +"@esbuild/android-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.28.2.tgz#fc38d4d6358d8dc1cf53f09f7589fe436eb64801" + integrity sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q== + +"@esbuild/darwin-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz#f83afeeac1d7dac01c7a2fd012b3e451a0591fcc" + integrity sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw== + +"@esbuild/darwin-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz#510147c055a795588dbbe14fd6b1b8ad0a2f30de" + integrity sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw== + +"@esbuild/freebsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz#093b9200ecf0b115ba4e5e248a7485c9c5f8bd5e" + integrity sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw== + +"@esbuild/freebsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz#0be22b6df925d213e841ea87123af5df80b0faf7" + integrity sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg== + +"@esbuild/linux-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz#1bdbc651cda9ba9995c53ed9c71ceaa65094762d" + integrity sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug== + +"@esbuild/linux-arm@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz#beb12ad72b84f72d28488cc1b8ee9f7eb141d753" + integrity sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w== + +"@esbuild/linux-ia32@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz#b81f9d55529b45c206a46a138214b1aa6879696b" + integrity sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ== + +"@esbuild/linux-loong64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz#598667241a04c99b76ed6ef940ac50038c419f98" + integrity sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ== + +"@esbuild/linux-mips64el@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz#1c51eb9cea903f53d97b5af3b1841db70f5596ca" + integrity sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA== + +"@esbuild/linux-ppc64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz#63dd61f17ceb31a81227f413feac8a71bc2c51f2" + integrity sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ== + +"@esbuild/linux-riscv64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz#3763b08fde5cf25ab1facb8e7752edfe45fbfc27" + integrity sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA== + +"@esbuild/linux-s390x@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz#1a137ff293a82906eb3176385bd7e8e0e5cfb7cb" + integrity sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg== + +"@esbuild/linux-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz#268b36211c146ca54f8fe12c578a8d6ef8979485" + integrity sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ== + +"@esbuild/netbsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz#22571ad951d62bb6accc82d8d1fad5c8c1ac0ba1" + integrity sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw== + +"@esbuild/netbsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz#42fcc57297eb0a0ca3f5fc475291f4c1a3f7c0de" + integrity sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw== + +"@esbuild/openbsd-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz#9eb32af104ac3dacf4edca01f596664aab0c73ef" + integrity sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ== + +"@esbuild/openbsd-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz#febed2402d6088225e91f20fb4ce2522ad0a4efd" + integrity sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw== + +"@esbuild/openharmony-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz#85641c3d466428bfbccea5f21c26836663fef5ce" + integrity sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q== + +"@esbuild/sunos-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz#a736f9d8962481045fc4c3e54f5479f22c870fb4" + integrity sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g== + +"@esbuild/win32-arm64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz#ee5ab40fad186201b652a33f8a5eb149e9e42532" + integrity sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ== + +"@esbuild/win32-ia32@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz#c40d28a6d99a127da6711f2afd74b11cb63b06a7" + integrity sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA== + +"@esbuild/win32-x64@0.28.2": + version "0.28.2" + resolved "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz#b21affb804cc167c133d95f45b3a1dc1323b9a87" + integrity sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g== + +"@floating-ui/core@^1.8.0": + version "1.8.0" + resolved "https://registry.npmmirror.com/@floating-ui/core/-/core-1.8.0.tgz#d01c0bbea02e4a57f6fd7d5de6fc2c5c7dca40e1" + integrity sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ== + dependencies: + "@floating-ui/utils" "^0.2.12" + +"@floating-ui/dom@^1.8.0": + version "1.8.0" + resolved "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.8.0.tgz#8a20e6facbe2456afdbeb6c8b968a72df689cf63" + integrity sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg== + dependencies: + "@floating-ui/core" "^1.8.0" + "@floating-ui/utils" "^0.2.12" + +"@floating-ui/utils@^0.2.12": + version "0.2.12" + resolved "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.12.tgz#afefe785949f16ac4cdd1e695935a321572dd56a" + integrity sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww== + +"@jridgewell/sourcemap-codec@^1.5.5": + version "1.5.5" + resolved "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + +"@napi-rs/lzma-linux-x64-gnu@1.5.1": + version "1.5.1" + resolved "https://registry.npmmirror.com/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz#e57d4306966078662038094fb38eb9146dc3aea9" + integrity sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ== + +"@oxc-project/types@=0.146.0": + version "0.146.0" + resolved "https://registry.npmmirror.com/@oxc-project/types/-/types-0.146.0.tgz#d57a2591abbf1f6e50981b07ee24ab269530d87a" + integrity sha512-XC0QsnnhVe7sLIWmYmdPw7x5P0h4W8vUU3Nv1ySgWXtvCz8NizoAEpGXA0sOYoJQV2Rl13LgURAHQ5cI5ILCSA== + +"@popperjs/core@npm:@sxzz/popperjs-es@^2.11.8": + version "2.11.8" + resolved "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz#af82ff5ecd0ec5874d3f2356db92223eec5d8661" + integrity sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ== + +"@rolldown/binding-android-arm-eabi@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.5.tgz#165b80910de7cd33f772d5b7b045b259acb7420c" + integrity sha512-DLe/i+l8ynIBY7XEQ191TeZvCoowIGa18R+dIV30GW7DiOtp74i/xX8hs8GUjW5ARV7VZuie3d6AumSmCwbeRA== + +"@rolldown/binding-android-arm64@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.5.tgz#5ed74d4b8fa56c68eb1aeb81d0d207a85b6de05c" + integrity sha512-zXcwKlQApYAOELHd8PwKDFkagYF9Wy4e0RJ+0qnzl9Pjnpj75TEG8ufv40p2J7kCEfwZAsNiuzRIyNNMWT38ig== + +"@rolldown/binding-darwin-arm64@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.5.tgz#6f27c7060e58ca03061fa7d50f9dc409bc377fe1" + integrity sha512-dK4QakI42nzWgJT5sm4y4y/O//D4OxM75/cH28RLV+nzIN9AY+YsbuUVrUTjlLjXR6vpyxFbSsbmNuJ6BP9sww== + +"@rolldown/binding-darwin-x64@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.5.tgz#74ab897d134ede4072fdc6108f00193e6167ee28" + integrity sha512-fqSALaUu1Wjd1nK2uW2kJDWdLCc8lx1IcY+MTY26Aurfdx19anlzhqXOgCFbBFQnlFDTn4TC1/7Nz4Bl2mLP3A== + +"@rolldown/binding-freebsd-x64@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.5.tgz#7d337f9ae4b739674e1938747118ab0676c8ef8a" + integrity sha512-/vCnNxlkxs9tKxNDcyWUePpJ/PgTzxIaVhoM5SmG8UV+GR/IcPam4VYxi7GIMo7PSDuNqlJqvprqii9NqqVCMw== + +"@rolldown/binding-linux-arm-gnueabihf@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.5.tgz#a8195dc1091ade0f912b0613ef6500941e5615f4" + integrity sha512-abk0NLA519LxRCszmbE0jYKuQ9YPocOXTiOXOo6Yr+YAT95VH+PtqYAjOJvGKt3viEd/x4qzabAlwd5bHOOARg== + +"@rolldown/binding-linux-arm64-gnu@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.5.tgz#40fbbb97072b1acaa3e0e8fe9774fe524e860bba" + integrity sha512-Y7eALiJ8lr0M2HH103Js+g7V34wf6snlpZLAsHI90uLhr3PVlNsbFVAXJC9d/V6BnPyKtpSwI+NcB/RLxsQxuA== + +"@rolldown/binding-linux-arm64-musl@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.5.tgz#3cfe8b0f7c13de29dace9a9fc6c03081164176ab" + integrity sha512-xMvZgnbZg4YVnR/AX2b3oOPDTFYJvUVaJg5FedA/LuvexAtXibZQej4cnTkw3rjsJ/ggUROB64TdtETiim+FYA== + +"@rolldown/binding-linux-ppc64-gnu@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.5.tgz#3bd890d96ae29f93718aa142ed0982f2ee2978ad" + integrity sha512-GRjeqTUDHTo5GwntsLaAMcBahG3nlpjftXWZLN73HiYQlhwEowvarFgQnRnQZtIp4keXX7quXFbG38uPZBa2EA== + +"@rolldown/binding-linux-s390x-gnu@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.5.tgz#0959a0d5af22741d5787918e27aef70dc8602804" + integrity sha512-vLNTR45F2Uwc8AufkNXPmB4VliaXs+FvcheEogIzOXzO4l+LzieXF5A/TWxLy5HtqpsRCHUfd0lPVrrdgXdLHQ== + +"@rolldown/binding-linux-x64-gnu@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.5.tgz#7baa94e826328ac6f457d9e1abacffa0353e8d22" + integrity sha512-Mgj59/HTuYeK9Gz2MA+mBWKnHsAgkBSec15ZMb1st3oIfFbX7gCjOae7GydHhzcyQi9Z/7M1QuN9bR3oFqF0jQ== + +"@rolldown/binding-linux-x64-musl@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.5.tgz#5f37597eaf0e22313d1e3d4be7d1be1fd332904e" + integrity sha512-mY8AP0/ichsbhAxGnLa3d3+MwV0EfgrPND2bplI3Ym8T6R2pJ0N87bvrKVwNXmdy3jnr6eQBecdqx/HMknBmpA== + +"@rolldown/binding-openharmony-arm64@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.5.tgz#d096567af3f738cbe6aa858ab0a01aae9f357ef4" + integrity sha512-8SLssA2oweAxyRgDp789ACfRb/3P+zNRJpzZxSizxF9m8NUDQ4+3xjo8ttjhVGGw6Qxb70oZiEtIjaKikCO7Yw== + +"@rolldown/binding-win32-arm64-msvc@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.5.tgz#d53b911aa4e6b547b789c07747fabab2ac8c237d" + integrity sha512-vGbruD5zquhoc8D9SViXgN2FBJtNdTyQ4DtG+SWiEGlJiAzoKcZ2xp+xuXCffhubVdt0NJlTZqkeRuERy7g8Cw== + +"@rolldown/binding-win32-x64-msvc@1.2.5": + version "1.2.5" + resolved "https://registry.npmmirror.com/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.5.tgz#7bbd08cfda6a98de9b756472c772a36ebb7229bc" + integrity sha512-e/SXpgISz+IoqVcSSI0rx/d/he8zqLex+/rCWpnHpmVfmPIUjag9H6P7zotf0gJHwPUhQxZ/mF8tr6acebT9yw== + +"@rolldown/pluginutils@^1.0.0", "@rolldown/pluginutils@^1.0.1": + version "1.0.1" + resolved "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz#e3fcee093fbb5ce765e1ad088ff4de2889f6f9be" + integrity sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw== + +"@rollup/rollup-android-arm-eabi@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.0.tgz#a85e4755658a6ab0ec48b41fdbc99375079755e1" + integrity sha512-70TeIFezKKy65LgAVyQh+w94/gjWhvPWaLaGGeMEgVrPkQhuj/M5bAYYZzIFUj9Y69oHyTm5Um/R6gcLh4A8JA== + +"@rollup/rollup-android-arm64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.0.tgz#b386ce4a3e6ea13c584e80eda2d8b6ae37006a5d" + integrity sha512-YC86tYIHK6M1IV+wbzO+Bxk8RCBr6ZyWYgWxUCzaZD8mc8rrFoIJDNzDrkHBYRc/wKdrsIXmm6/F7NzrAO+OrA== + +"@rollup/rollup-darwin-arm64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.0.tgz#7da6d7ff7a21d38dca15c28507a0120e508a42d0" + integrity sha512-oI+ECtUcli0y0fi4xpW82GdPIXdTkI8G8DSjG2LRuw09fPAGykaWYH/hXxiKuTxiAjiPSTIIuYUqof5Z2hShWw== + +"@rollup/rollup-darwin-x64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.0.tgz#00986c8203efeada43f44801f4a6c7e646e560e4" + integrity sha512-NwV+1s7TiKrMe4owHyKB/dTLD7ZJD0YEBEhIz+hvav1Cu1GReJjF+rsdNwjzENQeIAbE/CoNiaAc5Vz2h5DPAA== + +"@rollup/rollup-freebsd-arm64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.0.tgz#25d2a948024bd551ed4ad1faa8e4e25b89ada7bb" + integrity sha512-tWtHBTu5gOPK4u4Urtk4qAHW3zZ9rQAmbssO8gp7ELvGTGI3aCiq6NqyTQ0PCIg7KbHJF2UkGDDs77YZGxfjCA== + +"@rollup/rollup-freebsd-x64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.0.tgz#a7448db8a4d07097f5b727e2359632a2041a514b" + integrity sha512-2qPoJiwTvtHQ27NnYvTnsgk8laXWYuVmNESG8WFZBcEPKLfZ3I27qBJarjVRQtwGeYyRfq5ZowHXih9lm2BItw== + +"@rollup/rollup-linux-arm-gnueabihf@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.0.tgz#850cf21fc8ea7ceb22d9781049ea066bb2cad0d1" + integrity sha512-FQwsTRvLNuHoTdICABJQfbPUSEueISGmnpT06tXTMpfprf5NiKLSXKA0A+w45wJnCmZAnzgqBwbt6ARFuyOi5w== + +"@rollup/rollup-linux-arm-musleabihf@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.0.tgz#48275b693ad399b9321fcc11884436c3eecb735c" + integrity sha512-BBVTXziw8mY1a4ZbWME9tZyfzqXCDPqaC7Z3heQ29p5dkvXzwL0NwelO8zLa8c3RBKvl3YTuSnBgsBhYBtwjIw== + +"@rollup/rollup-linux-arm64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.0.tgz#2614ef8601b783d2a1a985afb98e96386908b6a1" + integrity sha512-w2Iyy9+RqKwx3d9qWMKsJg0FfRBsY0/pXNv0mCQ3ueRvJI6+QAScfD4nrMlzFLs2HNVW6Ew+mtZfDl9b7Ew5/Q== + +"@rollup/rollup-linux-arm64-musl@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.0.tgz#a1b95051d08bb14140bd235969405b4fc6be4603" + integrity sha512-YK++KtrFRHYE0P6/RtYEAy9t8F37znP+K03RrIuLPYOL6SVlObRumf/0OE4V/h63xL9DwkWbNssZfmA9hawuDA== + +"@rollup/rollup-linux-loong64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.0.tgz#0214c140ddef6e6bb8aa77695e9fc5dce23be59f" + integrity sha512-aBfOG6fP7YkkPmTqPwufRJeFyz7WPpECv9XNbnsk9+vg7rxdih0lbtEel7jcRng4LZrrmU3FfitCFyEj4BWDWg== + +"@rollup/rollup-linux-loong64-musl@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.0.tgz#d7a86499ce332a6e6c0383a65c43268bfae1cd7a" + integrity sha512-LGaHEOeHNAag9VuS1Crs5DFg4RrU9MPi2nVnNJk9DTePx/B6RRYKVmrIXt2h7YOJlwjaFJ6lwtFDliZxScTLrQ== + +"@rollup/rollup-linux-ppc64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.0.tgz#1f8a5d547b939116992b95b6add8bf58cfe10044" + integrity sha512-jClvk+J0FC3b7Udvegiw5/4hErbHtmsNsQgENnKXDWtNCJXsJYZH5WURvu7imDOO38xYml24eeh5x3A04ppwCw== + +"@rollup/rollup-linux-ppc64-musl@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.0.tgz#1da3aabff9c28f904feda2fa5de2df3c8cbb0d63" + integrity sha512-0OJlaGK+8+B777Ql5okIpD7ua5Ro9+VB9Ve0OKa28OQJZ1RbuUBVNHK/e3pr4BROqsyPl1JrPO1ZxJseCNffcA== + +"@rollup/rollup-linux-riscv64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.0.tgz#9d72f4b78fc8207b9e6992fa9709c5811864887d" + integrity sha512-Ygsx+HoNH7afwi1bTIXbnTvVnsO+zurPLSYxybV1hHFVU72OWOCl6v05ql/z0hkpAPx+DK7Kn9Bi7MayCcjLTA== + +"@rollup/rollup-linux-riscv64-musl@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.0.tgz#8c46c680896832a4bff3b6f8fcc29608c1198bac" + integrity sha512-pDQxtMGb+OvG3fLwR2OkZlSd47hW+kWg4BYMG/++sR6RqorQccwPTDsxda5hPwiIeIErAnCF9ma3SAU06bdQtQ== + +"@rollup/rollup-linux-s390x-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.0.tgz#aedd6de425fd7f985719a89f4505d279115fc322" + integrity sha512-0BnUG9mS8I4SSHr3XsxVhuCMEiu+rX61xxZF5vujso4LaiAGFZFxvDjg6Xn6tLPNTUAfuCvQYas4LMQMVsKRSQ== + +"@rollup/rollup-linux-x64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.0.tgz#395bdd1c0573a9df6adea131fd8946d5c2ba2e1a" + integrity sha512-Adu/VttB1dpPNW+FEacrZ+xVm9tFty84+RrFzsqlFaPxoJB+9XXyDGtp5dCOoBwGBIEVH0To7lExFXEx0BIF4A== + +"@rollup/rollup-linux-x64-musl@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.0.tgz#3350c151d4035083ccd224348c0bdcc389725f73" + integrity sha512-NQ3bDvjUbFKmP23671xUlXtKmqVsUBd6M4PQCvbmNtOy06hnQIdKHy8oG/6S3R/S6He1JgPk6A5VT+prAJMYEw== + +"@rollup/rollup-openbsd-x64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.0.tgz#5b477381b7d012c35f0aa5e4c7e9417b53e55e27" + integrity sha512-u2eDAl4+0aFvA13GxlGBtTI3SS3sdgwgtV0HyjZ0QaQVCgNE+jqNGey+GtxWiq+wxr/UycAx/OnfJzApCFamvA== + +"@rollup/rollup-openharmony-arm64@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.0.tgz#5df574fd964511133c700f0e4525fb50866a4bce" + integrity sha512-XvRb5vfW3wAZQ+ZUG21AnHHDKtNcw99eigzEhjr//NZ3u7SoBaPP0seSc7FgP7p1epAEdAoZckMW9WY/+4w70w== + +"@rollup/rollup-win32-arm64-msvc@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.0.tgz#e47eb3cdf12a7b1b380083031d90325469d022f3" + integrity sha512-iZPmniy4kNBf5yo2RezbkYNNK5HPbXE9+g+twnbqSng7dtLEJy1SKoxiE/ni4FDacjyuZpEeb9U054N4EoKHYw== + +"@rollup/rollup-win32-ia32-msvc@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.0.tgz#ea3b85d79b84ea5d07277e5abb4f48842fe41837" + integrity sha512-mFBBd+LF37fnE8JnYUOH+imj0aPFPK30vpar4ehJkgnLj9sZn8ZxiRENmLtgIwxK7TC8klF6N57fxdNBwQoqOA== + +"@rollup/rollup-win32-x64-gnu@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.0.tgz#19e613c75237f09bdd744955549e785ef767836a" + integrity sha512-ujeqEY3B+zbGn3Z4Q03cUBG/LGWnBJncVT36WER31LcOsQk9+1dmINKKtvmmfChUvRbK1G0R8OhMWFgHgaZtAw== + +"@rollup/rollup-win32-x64-msvc@4.63.0": + version "4.63.0" + resolved "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.0.tgz#2cfd1741b6693f78debdde1a5d4faa05bb75a349" + integrity sha512-hncn90N4sOky0L2LKE5oESKLbxCPeVo4eLA2LSMoDzM+879ml4WSr+Rr4DWknNIVVvS1Hirkc9hx02W6YxS8rQ== + +"@types/chai@^5.2.2": + version "5.2.3" + resolved "https://registry.npmmirror.com/@types/chai/-/chai-5.2.3.tgz#8e9cd9e1c3581fa6b341a5aed5588eb285be0b4a" + integrity sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA== + dependencies: + "@types/deep-eql" "*" + assertion-error "^2.0.1" + +"@types/deep-eql@*": + version "4.0.2" + resolved "https://registry.npmmirror.com/@types/deep-eql/-/deep-eql-4.0.2.tgz#334311971d3a07121e7eb91b684a605e7eea9cbd" + integrity sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw== + +"@types/estree@1.0.9", "@types/estree@^1.0.0": + version "1.0.9" + resolved "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz#cf3f0e876d7bee15a93ab925b82bf570a3904a24" + integrity sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg== + +"@types/lodash-es@^4.17.12": + version "4.17.12" + resolved "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz#65f6d1e5f80539aa7cfbfc962de5def0cf4f341b" + integrity sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*", "@types/lodash@^4.17.24": + version "4.17.25" + resolved "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.25.tgz#69765ac7bcddb0eb072961cf292524a8f5b3c2c0" + integrity sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ== + +"@types/node@^24.0.0": + version "24.13.3" + resolved "https://registry.npmmirror.com/@types/node/-/node-24.13.3.tgz#49f18bd3c647866dcda51a0756c145e14590ce16" + integrity sha512-Dh8vAsV36ig5wa9OX4pXvMc9D3Veibfw2wix0CUwYODLD8nkj9UsLjASr49nPg+2eKzxhBV+v7L8pXvT4e639Q== + dependencies: + undici-types "~7.18.0" + +"@types/web-bluetooth@^0.0.21": + version "0.0.21" + resolved "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.21.tgz#525433c784aed9b457aaa0ee3d92aeb71f346b63" + integrity sha512-oIQLCGWtcFZy2JW77j9k8nHzAOpqMHLQejDA48XXMWH6tjCQHz5RCFz1bzsmROyL6PUm+LLnUiI4BCn221inxA== + +"@vitejs/plugin-vue@^6.0.1": + version "6.0.8" + resolved "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.8.tgz#1809d090b7c93b8f4ae83d3e7536655cbbb1c793" + integrity sha512-0ZjgOg7oO6farnNGup7yvoM/YXZV84OZxHAwtflItNa/6zzQyVb5LNxyea3FEKEX2XlagIKzrlH7wwxkKgtiew== + dependencies: + "@rolldown/pluginutils" "^1.0.1" + +"@vitest/expect@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/expect/-/expect-3.2.7.tgz#70a34158383d008c3bf5d802e2643317f09df6d8" + integrity sha512-E8eBXaKibuvH2pSZErOjdVb5vF4PbKYcrnluBTYxEk1l/VhhwZg1kZQsdtjq+CsF5CFydf2Rdkz7jDHKSisi3w== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/spy" "3.2.7" + "@vitest/utils" "3.2.7" + chai "^5.2.0" + tinyrainbow "^2.0.0" + +"@vitest/mocker@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/mocker/-/mocker-3.2.7.tgz#331be944cb783c642dd42bd743411aca24ea0466" + integrity sha512-Trr0hYO9CM3Wj6ksWHRhK9IZpIY6wTMO5u/MqXurMxT57sWBaOPEtP3Oq60ihZuh5JsiagKfz95OcxdEP6dBrA== + dependencies: + "@vitest/spy" "3.2.7" + estree-walker "^3.0.3" + magic-string "^0.30.17" + +"@vitest/pretty-format@3.2.7", "@vitest/pretty-format@^3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/pretty-format/-/pretty-format-3.2.7.tgz#2a7b593f8e007e9d8ef7e7343aa30ec73fdeaf29" + integrity sha512-KUHlwqVu0sRlhCdyPdQ/wBoTfRahjUky1MubOmYw9fWfIZy1gNoHpuaaQBPAaMaVYdQYHJLurzj8ECCj5OwTqA== + dependencies: + tinyrainbow "^2.0.0" + +"@vitest/runner@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/runner/-/runner-3.2.7.tgz#c0c080228189f1fa6cda40f59be09d746b0aca51" + integrity sha512-sB9y4ovltoQP+WaUPwmSxO9WIg9Ig694Di5PalVPsYHklAdE027mehpWF2SQSVq+k6sFgaivbTjTJwZLSHbedA== + dependencies: + "@vitest/utils" "3.2.7" + pathe "^2.0.3" + strip-literal "^3.0.0" + +"@vitest/snapshot@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/snapshot/-/snapshot-3.2.7.tgz#a3a7e1950ce99ec4cf02395e20ddca403b6c818e" + integrity sha512-7C+MwShwtBSI5Buwoyg3s/iY1eHL9PKAf+O1wVh/TdnjXUtkoL/9YQtre90i4MtNXM6edP1wJ2zOBpfCyhIS7g== + dependencies: + "@vitest/pretty-format" "3.2.7" + magic-string "^0.30.17" + pathe "^2.0.3" + +"@vitest/spy@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/spy/-/spy-3.2.7.tgz#ca7fbee44019523ca450395d9a2284ce9ece1f31" + integrity sha512-Q2eQGI6d2L/hBtZ0qNuKcAGid68XK6cv1xsoaIma6PaJhHPoqcEJhYpXZ/5myCMqkNgtP6UKuBhbc0nHKnrkuQ== + dependencies: + tinyspy "^4.0.3" + +"@vitest/utils@3.2.7": + version "3.2.7" + resolved "https://registry.npmmirror.com/@vitest/utils/-/utils-3.2.7.tgz#302c8126211ac4dfea87b3b5085c098d6d22e89e" + integrity sha512-x6BDOd7dyo3PFLY3I9/HJ25X/6OurhGXk2/B9gOZNPF7XDVjeBK4k01lQE5uvDpbuheErh91qYuE1E2OEjK3Rw== + dependencies: + "@vitest/pretty-format" "3.2.7" + loupe "^3.1.4" + tinyrainbow "^2.0.0" + +"@volar/language-core@2.4.28": + version "2.4.28" + resolved "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.28.tgz#c21f365a91c1dffe8bd7264fd491770c8d74fef3" + integrity sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ== + dependencies: + "@volar/source-map" "2.4.28" + +"@volar/source-map@2.4.28": + version "2.4.28" + resolved "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.28.tgz#b40254e8c96199e5f1e0796777c593c617ad270e" + integrity sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ== + +"@volar/typescript@2.4.28": + version "2.4.28" + resolved "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.28.tgz#83f86356e84eb101b8081a44c104f2f2ced8411f" + integrity sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw== + dependencies: + "@volar/language-core" "2.4.28" + path-browserify "^1.0.1" + vscode-uri "^3.0.8" + +"@vue/compiler-core@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.41.tgz#82a4012d8b420f5a62c1658a72d16f7d1edf11aa" + integrity sha512-q0Xtv/F9w2YO/7htQhtiL+Ev2WCJbe5N2hc+XfgyKkEKqWpSxknmT8QOuGdEKNdjPq0c3F7rNpFkTo3Kfrm7pg== + dependencies: + "@babel/parser" "^7.29.8" + "@vue/shared" "3.5.41" + entities "^7.0.1" + estree-walker "^2.0.2" + source-map-js "^1.2.1" + +"@vue/compiler-dom@3.5.41", "@vue/compiler-dom@^3.5.0": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.41.tgz#1029f75de09c665a0a92c6156463754192acb361" + integrity sha512-oKacVfNglLvGjnS6BXOlGL7EyG2h8X03pqXCjzotRZUaXGjbrTJUnVAQjrCqUnS+lyu31nwQjZY/d817GmCnfw== + dependencies: + "@vue/compiler-core" "3.5.41" + "@vue/shared" "3.5.41" + +"@vue/compiler-sfc@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.41.tgz#f9c7c2170ad6ee4bf35c178b5df026485d8a63db" + integrity sha512-XJhip7R2wy6vX3knCxdZN4KracFaZUef58s1KYewqluedHIJaPIVfXoYT7MF1F8nCvv6k8bWWxDC8opMkg1VTQ== + dependencies: + "@babel/parser" "^7.29.8" + "@vue/compiler-core" "3.5.41" + "@vue/compiler-dom" "3.5.41" + "@vue/compiler-ssr" "3.5.41" + "@vue/shared" "3.5.41" + estree-walker "^2.0.2" + magic-string "^0.30.21" + postcss "^8.5.19" + source-map-js "^1.2.1" + +"@vue/compiler-ssr@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.41.tgz#8e5f9f6a8d21b802fce7373807dd935ed4541083" + integrity sha512-U3v5OejKEGqOI0Wy0+Sz7hGuIFZHA4LSXzrNM3IMIeDyJEBBfTpX26n3SDgToRpP2bLc9FfI2j/kSgcJ8Emq5A== + dependencies: + "@vue/compiler-dom" "3.5.41" + "@vue/shared" "3.5.41" + +"@vue/devtools-api@^6.6.4": + version "6.6.4" + resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz#cbe97fe0162b365edc1dba80e173f90492535343" + integrity sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g== + +"@vue/devtools-api@^7.7.7": + version "7.7.10" + resolved "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-7.7.10.tgz#bfa52dee8918edeea1bfe04cce9f809eeed19862" + integrity sha512-KxtEpUOOpFz/qOGRrAwA36QF7DqIA+FXgCYit9mk9wjbaZt0sXOFz81ElOZtKA4HbWHUdwNjZHBFsFFyp5BZiA== + dependencies: + "@vue/devtools-kit" "^7.7.10" + +"@vue/devtools-kit@^7.7.10": + version "7.7.10" + resolved "https://registry.npmmirror.com/@vue/devtools-kit/-/devtools-kit-7.7.10.tgz#2f2b6b6eaad9ba96c031fb20c4d59c80d35dfad3" + integrity sha512-3WNi2Kq4tbpVbmhml7RiphmAt0279oh3fKNeWMQIrltfX8Q91b4i5PL8DtyNKdwmcsGrV4fg+erwWOmD05CLIw== + dependencies: + "@vue/devtools-shared" "^7.7.10" + birpc "^2.3.0" + hookable "^5.5.3" + mitt "^3.0.1" + perfect-debounce "^1.0.0" + speakingurl "^14.0.1" + superjson "^2.2.2" + +"@vue/devtools-shared@^7.7.10": + version "7.7.10" + resolved "https://registry.npmmirror.com/@vue/devtools-shared/-/devtools-shared-7.7.10.tgz#ba45001aeb5f7b99a72db2fb824fc04a280aca53" + integrity sha512-wOPslzB8vTvpxwdaOcR2qAbwmuSP0L+rhpoC6Cf56V3Jip+HWb7PQQXOUPgBNQARpXsbQX/+mvi8kKucmBGRwQ== + dependencies: + rfdc "^1.4.1" + +"@vue/language-core@3.3.11": + version "3.3.11" + resolved "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.3.11.tgz#e5b6b5ad1fa1a37e032cf7668458cda7a5566b37" + integrity sha512-QJmpliwAVpC/OxubIByPAhNzsQPRc8/gxlN2qnVzVfIMjMDz/9RnXRFoetjz5yEgXVXyp4LqhXq3V53PjmNzFw== + dependencies: + "@volar/language-core" "2.4.28" + "@vue/compiler-dom" "^3.5.0" + "@vue/shared" "^3.5.0" + alien-signals "^3.2.1" + muggle-string "^0.4.1" + path-browserify "^1.0.1" + picomatch "^4.0.4" + +"@vue/reactivity@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.41.tgz#83be61b88b198f21c157d3aa6dcb843a25a11872" + integrity sha512-rznsqKM0np0x18EjzF8x88MpEhdNsffbvFbckLL5+oUKz1BxAImEmO7J1ArRYSyo6aQaVoBDp7jEkT91OOxydA== + dependencies: + "@vue/shared" "3.5.41" + +"@vue/runtime-core@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.41.tgz#a3e023c9f21809c81f24813dacb7ffa18a2e4161" + integrity sha512-Vcry58hiAKwGen9Z1jUZE0feFsNArPCMOImYI8el48A9Idf6DuQYD0U05zZIF2Iad1hGhPSvcbBbAOhNr55fhg== + dependencies: + "@vue/reactivity" "3.5.41" + "@vue/shared" "3.5.41" + +"@vue/runtime-dom@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.41.tgz#428f7a0420402385fae17d413d25169f98f64205" + integrity sha512-3vVBahVBS9+U6cmXBLyb8nE6/yYo4J/CGI9eVFs3KiMc0YHuudwKyShTD65jtJy/L9PUUxNAFu4cj4LiJ0UFbw== + dependencies: + "@vue/reactivity" "3.5.41" + "@vue/runtime-core" "3.5.41" + "@vue/shared" "3.5.41" + csstype "^3.2.3" + +"@vue/server-renderer@3.5.41": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.41.tgz#035a38c79182f154495238ea83acba24266ac200" + integrity sha512-n6hx/pNFfbD6SuyeuMVkvqox8bwf/ET9JlA/kAz/imw8sw++wkqKe2mHX5KutjPpbKE4Z56yTHszoOjGMI9igQ== + dependencies: + "@vue/compiler-ssr" "3.5.41" + "@vue/runtime-dom" "3.5.41" + "@vue/shared" "3.5.41" + +"@vue/shared@3.5.41", "@vue/shared@^3.5.0": + version "3.5.41" + resolved "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.41.tgz#ac476497f74495f7525087270849841756555cf2" + integrity sha512-IOnwSCma8j+9xJT6b8H0dEYidC80NsYmNMlZxRsukYcSoGaDBohog5hDxzeUXdFeGWFA++vWvxqOmrr96VlqMA== + +"@vueuse/core@14.4.0": + version "14.4.0" + resolved "https://registry.npmmirror.com/@vueuse/core/-/core-14.4.0.tgz#a841da6b3c7d548bdeed5bf611e73f3de62d20fa" + integrity sha512-X4WHz1HlCzCBoYXesUkifzzWBAcZgXG8Fi5iNPQg/epdzOB3gu8Fawj3hvuwYR1nGcXGnvxwYYcUC/71++svtQ== + dependencies: + "@types/web-bluetooth" "^0.0.21" + "@vueuse/metadata" "14.4.0" + "@vueuse/shared" "14.4.0" + +"@vueuse/metadata@14.4.0": + version "14.4.0" + resolved "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-14.4.0.tgz#a2508499b803bac14775a9c9b852b8738fc16f98" + integrity sha512-swx/255R6JyHZFJhx845iz5CRWDZdCfvkZOpACWc5+c5WHcG24mv8gUT1WIdFQaHt6dq79rvILd9QnCWiyVm9g== + +"@vueuse/shared@14.4.0": + version "14.4.0" + resolved "https://registry.npmmirror.com/@vueuse/shared/-/shared-14.4.0.tgz#4e89813c7859d153d48c03d74bff78739f96723b" + integrity sha512-JRgY90Sz8DDtPMsaDflvPMp9xYk69JZAmbuDvAquUVXKr2gEjqtzGNTTthLfckH0BzBqvnu31gb4a8TGLRe79g== + +alien-signals@^3.2.1: + version "3.2.1" + resolved "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.2.1.tgz#eb66256949bce90b7d30d055e2752e62d6930c7c" + integrity sha512-I8FjmltrfnDFoZedi5CG8DghVYNhzb/Ijluz7tCSJH0xpd0484Kowhbb1XDYOxfJpU1p5wnM2X54dA+IfGyD1g== + +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.npmmirror.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== + +async-validator@^4.2.5: + version "4.2.5" + resolved "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz#c96ea3332a521699d0afaaceed510a54656c6339" + integrity sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg== + +birpc@^2.3.0: + version "2.9.0" + resolved "https://registry.npmmirror.com/birpc/-/birpc-2.9.0.tgz#b59550897e4cd96a223e2a6c1475b572236ed145" + integrity sha512-KrayHS5pBi69Xi9JmvoqrIgYGDkD6mcSe/i6YKi3w5kekCLzrX4+nawcXqrj2tIp50Kw/mT/s3p+GVK0A0sKxw== + +cac@^6.7.14: + version "6.7.14" + resolved "https://registry.npmmirror.com/cac/-/cac-6.7.14.tgz#804e1e6f506ee363cb0e3ccbb09cad5dd9870959" + integrity sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ== + +chai@^5.2.0: + version "5.3.3" + resolved "https://registry.npmmirror.com/chai/-/chai-5.3.3.tgz#dd3da955e270916a4bd3f625f4b919996ada7e06" + integrity sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw== + dependencies: + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" + +check-error@^2.1.1: + version "2.1.3" + resolved "https://registry.npmmirror.com/check-error/-/check-error-2.1.3.tgz#2427361117b70cca8dc89680ead32b157019caf5" + integrity sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA== + +copy-anything@^4: + version "4.1.0" + resolved "https://registry.npmmirror.com/copy-anything/-/copy-anything-4.1.0.tgz#d3f8b248e0e48197d01bedee91ab6e57221dbd8a" + integrity sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q== + +csstype@^3.2.3: + version "3.2.3" + resolved "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz#ec48c0f3e993e50648c86da559e2610995cf989a" + integrity sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ== + +dayjs@^1.11.20: + version "1.11.23" + resolved "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.23.tgz#b0a363506dde5f36cf5075e42ebe8115165a8c79" + integrity sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ== + +debug@^4.4.1: + version "4.4.3" + resolved "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.npmmirror.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== + +detect-libc@^2.0.3: + version "2.1.2" + resolved "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz#689c5dcdc1900ef5583a4cb9f6d7b473742074ad" + integrity sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ== + +element-plus@^2.11.3: + version "2.14.5" + resolved "https://registry.npmmirror.com/element-plus/-/element-plus-2.14.5.tgz#476915f6470ef128b07ffebe982876af00f022ba" + integrity sha512-bghYy/S+qg87enHPXELirhEdDqsVAUGcGpbGIeG8dz0kwpIkGz7gYsifulBshXX74iRtHib85XWQj0uSH2A1Yg== + dependencies: + "@ctrl/tinycolor" "^4.2.0" + "@element-plus/icons-vue" "^2.3.2" + "@floating-ui/dom" "^1.8.0" + "@popperjs/core" "npm:@sxzz/popperjs-es@^2.11.8" + "@types/lodash" "^4.17.24" + "@types/lodash-es" "^4.17.12" + "@vueuse/core" "14.4.0" + async-validator "^4.2.5" + dayjs "^1.11.20" + lodash "^4.18.1" + lodash-es "^4.18.1" + lodash-unified "^1.0.3" + memoize-one "^6.0.0" + normalize-wheel-es "^1.2.0" + vue-component-type-helpers "^3.3.9" + +entities@^7.0.1: + version "7.0.1" + resolved "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz#26e8a88889db63417dcb9a1e79a3f1bc92b5976b" + integrity sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA== + +es-module-lexer@^1.7.0: + version "1.7.0" + resolved "https://registry.npmmirror.com/es-module-lexer/-/es-module-lexer-1.7.0.tgz#9159601561880a85f2734560a9099b2c31e5372a" + integrity sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA== + +"esbuild@^0.27.0 || ^0.28.0": + version "0.28.2" + resolved "https://registry.npmmirror.com/esbuild/-/esbuild-0.28.2.tgz#0f43bd1bad955b72d24e2261e3abe5957ccf0816" + integrity sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA== + optionalDependencies: + "@esbuild/aix-ppc64" "0.28.2" + "@esbuild/android-arm" "0.28.2" + "@esbuild/android-arm64" "0.28.2" + "@esbuild/android-x64" "0.28.2" + "@esbuild/darwin-arm64" "0.28.2" + "@esbuild/darwin-x64" "0.28.2" + "@esbuild/freebsd-arm64" "0.28.2" + "@esbuild/freebsd-x64" "0.28.2" + "@esbuild/linux-arm" "0.28.2" + "@esbuild/linux-arm64" "0.28.2" + "@esbuild/linux-ia32" "0.28.2" + "@esbuild/linux-loong64" "0.28.2" + "@esbuild/linux-mips64el" "0.28.2" + "@esbuild/linux-ppc64" "0.28.2" + "@esbuild/linux-riscv64" "0.28.2" + "@esbuild/linux-s390x" "0.28.2" + "@esbuild/linux-x64" "0.28.2" + "@esbuild/netbsd-arm64" "0.28.2" + "@esbuild/netbsd-x64" "0.28.2" + "@esbuild/openbsd-arm64" "0.28.2" + "@esbuild/openbsd-x64" "0.28.2" + "@esbuild/openharmony-arm64" "0.28.2" + "@esbuild/sunos-x64" "0.28.2" + "@esbuild/win32-arm64" "0.28.2" + "@esbuild/win32-ia32" "0.28.2" + "@esbuild/win32-x64" "0.28.2" + +estree-walker@^2.0.2: + version "2.0.2" + resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz#52f010178c2a4c117a7757cfe942adb7d2da4cac" + integrity sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w== + +estree-walker@^3.0.3: + version "3.0.3" + resolved "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz#67c3e549ec402a487b4fc193d1953a524752340d" + integrity sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g== + dependencies: + "@types/estree" "^1.0.0" + +expect-type@^1.2.1: + version "1.4.0" + resolved "https://registry.npmmirror.com/expect-type/-/expect-type-1.4.0.tgz#24edf7f0cc69a44d008567ba4594ab96f3c3a3d6" + integrity sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA== + +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +hookable@^5.5.3: + version "5.5.3" + resolved "https://registry.npmmirror.com/hookable/-/hookable-5.5.3.tgz#6cfc358984a1ef991e2518cb9ed4a778bbd3215d" + integrity sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ== + +js-tokens@^9.0.1: + version "9.0.1" + resolved "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.1.tgz#2ec43964658435296f6761b34e10671c2d9527f4" + integrity sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ== + +lightningcss-android-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz#9a6841f88ae50fc83502903892b41af41bc2b907" + integrity sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg== + +lightningcss-darwin-arm64@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz#c0f2c31c0bfd19fa4dd3f18e957a1f1a152097d6" + integrity sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg== + +lightningcss-darwin-x64@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz#cb0705965acb538c6683949ce6925fb3cdf7c361" + integrity sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ== + +lightningcss-freebsd-x64@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz#763538828b26bab2680dadafcc84ee78b0eb502b" + integrity sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg== + +lightningcss-linux-arm-gnueabihf@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz#6862e3176a331aedbdec1ed352b4d7d0dd0784de" + integrity sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ== + +lightningcss-linux-arm64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz#c6a3a2ed15141daf6bdc2628930f8e39bdf473aa" + integrity sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg== + +lightningcss-linux-arm64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz#7fa1334971fc82845f9827df6ef8a0b20914bac6" + integrity sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ== + +lightningcss-linux-x64-gnu@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz#8b927862ea8c2bbc6831a46509244b50d9936e55" + integrity sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg== + +lightningcss-linux-x64-musl@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz#0c525bb077dfd94404c059cfe42dad797e96aeaf" + integrity sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw== + +lightningcss-win32-arm64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz#850ee1103dac989cfab50e3ac22d1a69e394e63d" + integrity sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA== + +lightningcss-win32-x64-msvc@1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz#e343ae152eed3609dc6e11949d1a3bf39a1c946f" + integrity sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA== + +lightningcss@^1.33.0: + version "1.33.0" + resolved "https://registry.npmmirror.com/lightningcss/-/lightningcss-1.33.0.tgz#c08867d71a79385c6e190214fd72fef3e5f95f0b" + integrity sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA== + dependencies: + detect-libc "^2.0.3" + optionalDependencies: + lightningcss-android-arm64 "1.33.0" + lightningcss-darwin-arm64 "1.33.0" + lightningcss-darwin-x64 "1.33.0" + lightningcss-freebsd-x64 "1.33.0" + lightningcss-linux-arm-gnueabihf "1.33.0" + lightningcss-linux-arm64-gnu "1.33.0" + lightningcss-linux-arm64-musl "1.33.0" + lightningcss-linux-x64-gnu "1.33.0" + lightningcss-linux-x64-musl "1.33.0" + lightningcss-win32-arm64-msvc "1.33.0" + lightningcss-win32-x64-msvc "1.33.0" + +lodash-es@^4.18.1: + version "4.18.1" + resolved "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.18.1.tgz#b962eeb80d9d983a900bf342961fb7418ca10b1d" + integrity sha512-J8xewKD/Gk22OZbhpOVSwcs60zhd95ESDwezOFuA3/099925PdHJ7OFHNTGtajL3AlZkykD32HykiMo+BIBI8A== + +lodash-unified@^1.0.3: + version "1.0.3" + resolved "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz#80b1eac10ed2eb02ed189f08614a29c27d07c894" + integrity sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ== + +lodash@^4.18.1: + version "4.18.1" + resolved "https://registry.npmmirror.com/lodash/-/lodash-4.18.1.tgz#ff2b66c1f6326d59513de2407bf881439812771c" + integrity sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q== + +loupe@^3.1.0, loupe@^3.1.4: + version "3.2.1" + resolved "https://registry.npmmirror.com/loupe/-/loupe-3.2.1.tgz#0095cf56dc5b7a9a7c08ff5b1a8796ec8ad17e76" + integrity sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ== + +magic-string@^0.30.17, magic-string@^0.30.21: + version "0.30.21" + resolved "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz#56763ec09a0fa8091df27879fd94d19078c00d91" + integrity sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.5" + +memoize-one@^6.0.0: + version "6.0.0" + resolved "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz#b2591b871ed82948aee4727dc6abceeeac8c1045" + integrity sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw== + +mitt@^3.0.1: + version "3.0.1" + resolved "https://registry.npmmirror.com/mitt/-/mitt-3.0.1.tgz#ea36cf0cc30403601ae074c8f77b7092cdab36d1" + integrity sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw== + +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +muggle-string@^0.4.1: + version "0.4.1" + resolved "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz#3b366bd43b32f809dc20659534dd30e7c8a0d328" + integrity sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ== + +nanoid@^3.3.17: + version "3.3.18" + resolved "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.18.tgz#f66a2de1199ffde0fcf21c8a5f13106b1c081913" + integrity sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w== + +normalize-wheel-es@^1.2.0: + version "1.2.0" + resolved "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz#0fa2593d619f7245a541652619105ab076acf09e" + integrity sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw== + +path-browserify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd" + integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g== + +pathe@^2.0.3: + version "2.0.3" + resolved "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz#3ecbec55421685b70a9da872b2cff3e1cbed1716" + integrity sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w== + +pathval@^2.0.0: + version "2.0.1" + resolved "https://registry.npmmirror.com/pathval/-/pathval-2.0.1.tgz#8855c5a2899af072d6ac05d11e46045ad0dc605d" + integrity sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ== + +perfect-debounce@^1.0.0: + version "1.0.0" + resolved "https://registry.npmmirror.com/perfect-debounce/-/perfect-debounce-1.0.0.tgz#9c2e8bc30b169cc984a58b7d5b28049839591d2a" + integrity sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA== + +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + +picomatch@^4.0.2, picomatch@^4.0.3, picomatch@^4.0.4, picomatch@^4.0.5: + version "4.0.7" + resolved "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.7.tgz#6313360034ccb36b3dc61ecbdff78121f90fe21f" + integrity sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA== + +pinia@^3.0.3: + version "3.0.4" + resolved "https://registry.npmmirror.com/pinia/-/pinia-3.0.4.tgz#75dde12784a61e34c1fa6abcd13c1a1061c360c0" + integrity sha512-l7pqLUFTI/+ESXn6k3nu30ZIzW5E2WZF/LaHJEpoq6ElcLD+wduZoB2kBN19du6K/4FDpPMazY2wJr+IndBtQw== + dependencies: + "@vue/devtools-api" "^7.7.7" + +postcss@^8.5.19, postcss@^8.5.26, postcss@^8.5.6: + version "8.5.26" + resolved "https://registry.npmmirror.com/postcss/-/postcss-8.5.26.tgz#6e75135780c7e10df3433bf2266c552d35c8c620" + integrity sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ== + dependencies: + nanoid "^3.3.17" + picocolors "^1.1.1" + source-map-js "^1.2.1" + +rfdc@^1.4.1: + version "1.4.1" + resolved "https://registry.npmmirror.com/rfdc/-/rfdc-1.4.1.tgz#778f76c4fb731d93414e8f925fbecf64cce7f6ca" + integrity sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA== + +rolldown@~1.2.4: + version "1.2.5" + resolved "https://registry.npmmirror.com/rolldown/-/rolldown-1.2.5.tgz#1f504a7d05260a769e617d950410bbb051498c50" + integrity sha512-VD2IE5PUG4Oj8zz2VGykiYd5wbnjdIiSsNQb8Qu5B+noEp+A78mu2iVvpp27g8es14Tk9rofNs5Tku9iQCS4fA== + dependencies: + "@oxc-project/types" "=0.146.0" + "@rolldown/pluginutils" "^1.0.0" + optionalDependencies: + "@rolldown/binding-android-arm-eabi" "1.2.5" + "@rolldown/binding-android-arm64" "1.2.5" + "@rolldown/binding-darwin-arm64" "1.2.5" + "@rolldown/binding-darwin-x64" "1.2.5" + "@rolldown/binding-freebsd-x64" "1.2.5" + "@rolldown/binding-linux-arm-gnueabihf" "1.2.5" + "@rolldown/binding-linux-arm64-gnu" "1.2.5" + "@rolldown/binding-linux-arm64-musl" "1.2.5" + "@rolldown/binding-linux-ppc64-gnu" "1.2.5" + "@rolldown/binding-linux-s390x-gnu" "1.2.5" + "@rolldown/binding-linux-x64-gnu" "1.2.5" + "@rolldown/binding-linux-x64-musl" "1.2.5" + "@rolldown/binding-openharmony-arm64" "1.2.5" + "@rolldown/binding-win32-arm64-msvc" "1.2.5" + "@rolldown/binding-win32-x64-msvc" "1.2.5" + +rollup@^4.43.0: + version "4.63.0" + resolved "https://registry.npmmirror.com/rollup/-/rollup-4.63.0.tgz#55798a9834a55957544a971acc0f8365ca265b87" + integrity sha512-T5vnZ2y4QqC3/4P+w2+JO+Q/OVdnPsv4XcSYJYMEn0R9/jjl5AgLwO9LAZMzP2lN71O6pypn91rB7lDstUkfrQ== + dependencies: + "@types/estree" "1.0.9" + optionalDependencies: + "@napi-rs/lzma-linux-x64-gnu" "1.5.1" + "@rollup/rollup-android-arm-eabi" "4.63.0" + "@rollup/rollup-android-arm64" "4.63.0" + "@rollup/rollup-darwin-arm64" "4.63.0" + "@rollup/rollup-darwin-x64" "4.63.0" + "@rollup/rollup-freebsd-arm64" "4.63.0" + "@rollup/rollup-freebsd-x64" "4.63.0" + "@rollup/rollup-linux-arm-gnueabihf" "4.63.0" + "@rollup/rollup-linux-arm-musleabihf" "4.63.0" + "@rollup/rollup-linux-arm64-gnu" "4.63.0" + "@rollup/rollup-linux-arm64-musl" "4.63.0" + "@rollup/rollup-linux-loong64-gnu" "4.63.0" + "@rollup/rollup-linux-loong64-musl" "4.63.0" + "@rollup/rollup-linux-ppc64-gnu" "4.63.0" + "@rollup/rollup-linux-ppc64-musl" "4.63.0" + "@rollup/rollup-linux-riscv64-gnu" "4.63.0" + "@rollup/rollup-linux-riscv64-musl" "4.63.0" + "@rollup/rollup-linux-s390x-gnu" "4.63.0" + "@rollup/rollup-linux-x64-gnu" "4.63.0" + "@rollup/rollup-linux-x64-musl" "4.63.0" + "@rollup/rollup-openbsd-x64" "4.63.0" + "@rollup/rollup-openharmony-arm64" "4.63.0" + "@rollup/rollup-win32-arm64-msvc" "4.63.0" + "@rollup/rollup-win32-ia32-msvc" "4.63.0" + "@rollup/rollup-win32-x64-gnu" "4.63.0" + "@rollup/rollup-win32-x64-msvc" "4.63.0" + fsevents "~2.3.2" + +siginfo@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/siginfo/-/siginfo-2.0.0.tgz#32e76c70b79724e3bb567cb9d543eb858ccfaf30" + integrity sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g== + +source-map-js@^1.2.1: + version "1.2.1" + resolved "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz#1ce5650fddd87abc099eda37dcff024c2667ae46" + integrity sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA== + +speakingurl@^14.0.1: + version "14.0.1" + resolved "https://registry.npmmirror.com/speakingurl/-/speakingurl-14.0.1.tgz#f37ec8ddc4ab98e9600c1c9ec324a8c48d772a53" + integrity sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ== + +stackback@0.0.2: + version "0.0.2" + resolved "https://registry.npmmirror.com/stackback/-/stackback-0.0.2.tgz#1ac8a0d9483848d1695e418b6d031a3c3ce68e3b" + integrity sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw== + +std-env@^3.9.0: + version "3.10.0" + resolved "https://registry.npmmirror.com/std-env/-/std-env-3.10.0.tgz#d810b27e3a073047b2b5e40034881f5ea6f9c83b" + integrity sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg== + +strip-literal@^3.0.0: + version "3.1.0" + resolved "https://registry.npmmirror.com/strip-literal/-/strip-literal-3.1.0.tgz#222b243dd2d49c0bcd0de8906adbd84177196032" + integrity sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg== + dependencies: + js-tokens "^9.0.1" + +superjson@^2.2.2: + version "2.2.6" + resolved "https://registry.npmmirror.com/superjson/-/superjson-2.2.6.tgz#a223a3a988172a5f9656e2063fe5f733af40d099" + integrity sha512-H+ue8Zo4vJmV2nRjpx86P35lzwDT3nItnIsocgumgr0hHMQ+ZGq5vrERg9kJBo5AWGmxZDhzDo+WVIJqkB0cGA== + dependencies: + copy-anything "^4" + +tinybench@^2.9.0: + version "2.9.0" + resolved "https://registry.npmmirror.com/tinybench/-/tinybench-2.9.0.tgz#103c9f8ba6d7237a47ab6dd1dcff77251863426b" + integrity sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg== + +tinyexec@^0.3.2: + version "0.3.2" + resolved "https://registry.npmmirror.com/tinyexec/-/tinyexec-0.3.2.tgz#941794e657a85e496577995c6eef66f53f42b3d2" + integrity sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA== + +tinyglobby@^0.2.14, tinyglobby@^0.2.15, tinyglobby@^0.2.17: + version "0.2.17" + resolved "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.17.tgz#562a9a6c9eb2b3b123d39719f9af5bb44fcd7631" + integrity sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.4" + +tinypool@^1.1.1: + version "1.1.1" + resolved "https://registry.npmmirror.com/tinypool/-/tinypool-1.1.1.tgz#059f2d042bd37567fbc017d3d426bdd2a2612591" + integrity sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg== + +tinyrainbow@^2.0.0: + version "2.0.0" + resolved "https://registry.npmmirror.com/tinyrainbow/-/tinyrainbow-2.0.0.tgz#9509b2162436315e80e3eee0fcce4474d2444294" + integrity sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw== + +tinyspy@^4.0.3: + version "4.0.4" + resolved "https://registry.npmmirror.com/tinyspy/-/tinyspy-4.0.4.tgz#d77a002fb53a88aa1429b419c1c92492e0c81f78" + integrity sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q== + +typescript@^6.0.3: + version "6.0.3" + resolved "https://registry.npmmirror.com/typescript/-/typescript-6.0.3.tgz#90251dc007916e972786cb94d74d15b185577d21" + integrity sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw== + +undici-types@~7.18.0: + version "7.18.2" + resolved "https://registry.npmmirror.com/undici-types/-/undici-types-7.18.2.tgz#29357a89e7b7ca4aef3bf0fd3fd0cd73884229e9" + integrity sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w== + +vite-node@3.2.4: + version "3.2.4" + resolved "https://registry.npmmirror.com/vite-node/-/vite-node-3.2.4.tgz#f3676d94c4af1e76898c162c92728bca65f7bb07" + integrity sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg== + dependencies: + cac "^6.7.14" + debug "^4.4.1" + es-module-lexer "^1.7.0" + pathe "^2.0.3" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + +"vite@^5.0.0 || ^6.0.0 || ^7.0.0-0": + version "7.3.6" + resolved "https://registry.npmmirror.com/vite/-/vite-7.3.6.tgz#0547a395e68d3746e9a505f1fd4469fe09b49cc4" + integrity sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg== + dependencies: + esbuild "^0.27.0 || ^0.28.0" + fdir "^6.5.0" + picomatch "^4.0.3" + postcss "^8.5.6" + rollup "^4.43.0" + tinyglobby "^0.2.15" + optionalDependencies: + fsevents "~2.3.3" + +vite@^8.1.0: + version "8.2.2" + resolved "https://registry.npmmirror.com/vite/-/vite-8.2.2.tgz#399aefad3656145145be110d137a07ea5bb55014" + integrity sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q== + dependencies: + lightningcss "^1.33.0" + picomatch "^4.0.5" + postcss "^8.5.26" + rolldown "~1.2.4" + tinyglobby "^0.2.17" + optionalDependencies: + fsevents "~2.3.3" + +vitest@^3.2.4: + version "3.2.7" + resolved "https://registry.npmmirror.com/vitest/-/vitest-3.2.7.tgz#1944b6ed013a25fd26a73d18e1af92c10a57af6c" + integrity sha512-KrxIJ62Fd89gfysR4WotlgZABiz2dqFPgqGzX7s+CwsqLFomRH7777ZcrOD6+WVAh7khPQP41A+BKbpcJFrdEg== + dependencies: + "@types/chai" "^5.2.2" + "@vitest/expect" "3.2.7" + "@vitest/mocker" "3.2.7" + "@vitest/pretty-format" "^3.2.7" + "@vitest/runner" "3.2.7" + "@vitest/snapshot" "3.2.7" + "@vitest/spy" "3.2.7" + "@vitest/utils" "3.2.7" + chai "^5.2.0" + debug "^4.4.1" + expect-type "^1.2.1" + magic-string "^0.30.17" + pathe "^2.0.3" + picomatch "^4.0.2" + std-env "^3.9.0" + tinybench "^2.9.0" + tinyexec "^0.3.2" + tinyglobby "^0.2.14" + tinypool "^1.1.1" + tinyrainbow "^2.0.0" + vite "^5.0.0 || ^6.0.0 || ^7.0.0-0" + vite-node "3.2.4" + why-is-node-running "^2.3.0" + +vscode-uri@^3.0.8: + version "3.2.0" + resolved "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.2.0.tgz#1cb1fd3cee7426b66732afc3fb86343d596d5fb4" + integrity sha512-m2gXo3bn0G1kT9InzMf07fTbqMbGtyckj3bH5ktLO+1Ssv+yiATZ4dhwaQv9UZWxJh6E9IFGnQyjgWVDWVBDrg== + +vue-component-type-helpers@^3.3.9: + version "3.3.11" + resolved "https://registry.npmmirror.com/vue-component-type-helpers/-/vue-component-type-helpers-3.3.11.tgz#b2f683937e744cf5724c614955dff9bc32342fb4" + integrity sha512-LwcxzeliO9fkQcpJG0PoX8X5kmAhKmH9wkpDLxNabwzkQ9Zeib2YVHwFV4pcWmMLfXVfjr/dSV+DaJ3cIPgSNA== + +vue-router@^4.5.1: + version "4.6.4" + resolved "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz#a0a9cb9ef811a106d249e4bb9313d286718020d8" + integrity sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg== + dependencies: + "@vue/devtools-api" "^6.6.4" + +vue-tsc@^3.0.6: + version "3.3.11" + resolved "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.3.11.tgz#26e7df7b6c1d66793d68caaa4ab96caa28002d9c" + integrity sha512-gOb0B9rtU2+f1dszwPqSH5kAieIF9ReeLhD3kSRNHv5WZZUQz/JdVXW0RTdqhNTMlQkqKzrTTviqKr/4FYZraQ== + dependencies: + "@volar/typescript" "2.4.28" + "@vue/language-core" "3.3.11" + +vue@^3.5.18: + version "3.5.41" + resolved "https://registry.npmmirror.com/vue/-/vue-3.5.41.tgz#8864bddfe59ce128a28c9bad219cd9248916af73" + integrity sha512-2laE0p+aK+/AOPG/XL/WepOs/GlK755LJ1XECi9kDUrz1FKNw8rb2Xzlw9JS1rqEV55nb0ttsKxVlTCcd+R5cg== + dependencies: + "@vue/compiler-dom" "3.5.41" + "@vue/compiler-sfc" "3.5.41" + "@vue/runtime-dom" "3.5.41" + "@vue/server-renderer" "3.5.41" + "@vue/shared" "3.5.41" + +why-is-node-running@^2.3.0: + version "2.3.0" + resolved "https://registry.npmmirror.com/why-is-node-running/-/why-is-node-running-2.3.0.tgz#a3f69a97107f494b3cdc3bdddd883a7d65cebf04" + integrity sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w== + dependencies: + siginfo "^2.0.0" + stackback "0.0.2" diff --git a/WonderQ-Admin-UI/src/api.ts b/WonderQ-Admin-UI/src/api.ts index 8b97b50..0c062ae 100644 --- a/WonderQ-Admin-UI/src/api.ts +++ b/WonderQ-Admin-UI/src/api.ts @@ -341,6 +341,8 @@ export function clearToken() { window.localStorage.removeItem(TOKEN_KEY); } +let refreshPromise: Promise | null = null; + function handleAuthExpired() { clearToken(); notifyAuthExpired(); @@ -401,7 +403,30 @@ async function readApiResponse(response: Response): Promise { return response.json().catch(() => null); } -async function request(path: string, options: RequestInit = {}): Promise { +async function refreshAdminToken(): Promise { + if (refreshPromise) return refreshPromise; + refreshPromise = (async () => { + const response = await fetch(`${API_BASE}/api/admin/auth/refresh`, { + method: "POST", + credentials: "include", + }); + if (!response.ok) return null; + try { + const body = await readApiResponse(response); + const session = parseApiResponse<{ token: string; accessToken?: string }>(body, response.status); + const token = session.accessToken ?? session.token; + setToken(token); + return token; + } catch { + return null; + } + })().finally(() => { + refreshPromise = null; + }); + return refreshPromise; +} + +async function request(path: string, options: RequestInit = {}, allowRefresh = true): Promise { const headers = new Headers(options.headers); headers.set("Content-Type", "application/json"); const token = getToken(); @@ -410,10 +435,12 @@ async function request(path: string, options: RequestInit = {}): Promise { const response = await fetch(`${API_BASE}${path}`, { ...options, headers, + credentials: "include", }); if (!response.ok) { - if (path !== "/api/admin/auth/login" && shouldExpireAdminSession(response.status, Boolean(token))) { + if (allowRefresh && path !== "/api/admin/auth/login" && shouldExpireAdminSession(response.status, Boolean(token))) { + if (await refreshAdminToken()) return request(path, options, false); handleAuthExpired(); } const body = await readApiResponse(response); @@ -424,12 +451,16 @@ async function request(path: string, options: RequestInit = {}): Promise { } export async function login(email: string, password: string) { - return request<{ token: string; user: { name: string; email: string; role: string } }>("/api/admin/auth/login", { + return request<{ token: string; accessToken?: string; user: { name: string; email: string; role: string } }>("/api/admin/auth/login", { method: "POST", body: JSON.stringify({ email, password }), }); } +export async function logoutAdmin() { + return request<{ ok: boolean }>("/api/admin/auth/logout", { method: "POST" }, false); +} + export async function uploadMediaAsset(file: File, group = "site-config") { const form = new FormData(); form.set("file", file); @@ -442,9 +473,13 @@ export async function uploadMediaAsset(file: File, group = "site-config") { method: "POST", headers, body: form, + credentials: "include", }); if (!response.ok) { + if (shouldExpireAdminSession(response.status, Boolean(token)) && (await refreshAdminToken())) { + return uploadMediaAsset(file, group); + } if (shouldExpireAdminSession(response.status, Boolean(token))) { handleAuthExpired(); } diff --git a/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx b/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx index 7511025..6cc3ff2 100644 --- a/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx +++ b/WonderQ-Admin-UI/src/components/admin/AdminShell.tsx @@ -1,7 +1,7 @@ import { useMemo, useState } from "react"; import { ClipboardList, Headset, Home, List, LogOut } from "lucide-react"; -import { clearToken } from "@/api"; +import { clearToken, logoutAdmin } from "@/api"; import { ToastStack } from "@/components/admin/ToastStack"; import { Button } from "@/components/ui/button"; import { ConciergePage } from "@/pages/structure/ConciergePage"; @@ -56,8 +56,10 @@ export function AdminShell({ onLogout }: { onLogout: () => void }) { }; const logout = () => { - clearToken(); - onLogout(); + void logoutAdmin().finally(() => { + clearToken(); + onLogout(); + }); }; return ( diff --git a/WonderQ-Admin-UI/src/pages/login/LoginPage.tsx b/WonderQ-Admin-UI/src/pages/login/LoginPage.tsx index 255f3b6..9a3ef01 100644 --- a/WonderQ-Admin-UI/src/pages/login/LoginPage.tsx +++ b/WonderQ-Admin-UI/src/pages/login/LoginPage.tsx @@ -18,7 +18,7 @@ export function LoginPage({ onDone }: { onDone: () => void }) { setError(""); try { const result = await login(email, password); - setToken(result.token); + setToken(result.accessToken ?? result.token); onDone(); } catch (err) { setError(err instanceof Error ? err.message : "登录失败");