From 1e63ab291b6dd0f5620a4c51aa042c9a1cb96147 Mon Sep 17 00:00:00 2001 From: super <2903208875@qq.com> Date: Thu, 19 Mar 2026 13:15:47 +0800 Subject: [PATCH] =?UTF-8?q?=E9=87=8D=E6=9E=84=E9=A1=B9=E7=9B=AE=EF=BC=8C?= =?UTF-8?q?=E6=96=B9=E4=BE=BF=E5=BC=80=E5=8F=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 15 + desktop/README.md | 74 + desktop/__init__.py | 1 + desktop/__pycache__/__init__.cpython-312.pyc | Bin 0 -> 142 bytes desktop/__pycache__/__init__.cpython-314.pyc | Bin 0 -> 144 bytes desktop/__pycache__/app.cpython-312.pyc | Bin 0 -> 18161 bytes desktop/__pycache__/app.cpython-314.pyc | Bin 0 -> 22571 bytes desktop/app.py | 334 +++ desktop/requirements.txt | 2 + desktop/run_desktop_dev.ps1 | 67 + desktop/run_desktop_dist.ps1 | 67 + frontend-vue/index.html | 12 + frontend-vue/package-lock.json | 2524 +++++++++++++++++ frontend-vue/package.json | 26 + frontend-vue/src/App.vue | 3 + .../src/components/layout/PageShell.vue | 20 + frontend-vue/src/main.ts | 8 + frontend-vue/src/pages/admin/index.vue | 584 ++++ frontend-vue/src/pages/brand/index.vue | 1096 +++++++ frontend-vue/src/pages/home/index.vue | 171 ++ frontend-vue/src/pages/image/index.vue | 94 + frontend-vue/src/pages/login/index.vue | 148 + frontend-vue/src/router.ts | 46 + frontend-vue/src/shared/api/admin.ts | 96 + frontend-vue/src/shared/api/auth.ts | 38 + frontend-vue/src/shared/api/brand.ts | 88 + frontend-vue/src/shared/api/http.ts | 107 + frontend-vue/src/shared/api/update.ts | 22 + frontend-vue/src/shared/bridges/pywebview.ts | 24 + .../src/shared/composables/useUpdateCheck.ts | 71 + frontend-vue/src/shared/utils/bootstrap.ts | 16 + frontend-vue/src/styles/main.css | 51 + frontend-vue/src/styles/reset.css | 27 + frontend-vue/src/styles/tokens.css | 17 + frontend-vue/src/vite-env.d.ts | 1 + frontend-vue/tsconfig.json | 29 + frontend-vue/tsconfig.node.json | 10 + frontend-vue/vite.config.ts | 51 + 38 files changed, 5940 insertions(+) create mode 100644 .gitignore create mode 100644 desktop/README.md create mode 100644 desktop/__init__.py create mode 100644 desktop/__pycache__/__init__.cpython-312.pyc create mode 100644 desktop/__pycache__/__init__.cpython-314.pyc create mode 100644 desktop/__pycache__/app.cpython-312.pyc create mode 100644 desktop/__pycache__/app.cpython-314.pyc create mode 100644 desktop/app.py create mode 100644 desktop/requirements.txt create mode 100644 desktop/run_desktop_dev.ps1 create mode 100644 desktop/run_desktop_dist.ps1 create mode 100644 frontend-vue/index.html create mode 100644 frontend-vue/package-lock.json create mode 100644 frontend-vue/package.json create mode 100644 frontend-vue/src/App.vue create mode 100644 frontend-vue/src/components/layout/PageShell.vue create mode 100644 frontend-vue/src/main.ts create mode 100644 frontend-vue/src/pages/admin/index.vue create mode 100644 frontend-vue/src/pages/brand/index.vue create mode 100644 frontend-vue/src/pages/home/index.vue create mode 100644 frontend-vue/src/pages/image/index.vue create mode 100644 frontend-vue/src/pages/login/index.vue create mode 100644 frontend-vue/src/router.ts create mode 100644 frontend-vue/src/shared/api/admin.ts create mode 100644 frontend-vue/src/shared/api/auth.ts create mode 100644 frontend-vue/src/shared/api/brand.ts create mode 100644 frontend-vue/src/shared/api/http.ts create mode 100644 frontend-vue/src/shared/api/update.ts create mode 100644 frontend-vue/src/shared/bridges/pywebview.ts create mode 100644 frontend-vue/src/shared/composables/useUpdateCheck.ts create mode 100644 frontend-vue/src/shared/utils/bootstrap.ts create mode 100644 frontend-vue/src/styles/main.css create mode 100644 frontend-vue/src/styles/reset.css create mode 100644 frontend-vue/src/styles/tokens.css create mode 100644 frontend-vue/src/vite-env.d.ts create mode 100644 frontend-vue/tsconfig.json create mode 100644 frontend-vue/tsconfig.node.json create mode 100644 frontend-vue/vite.config.ts diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b324bde --- /dev/null +++ b/.gitignore @@ -0,0 +1,15 @@ +# frontend-vue dependencies +frontend-vue/node_modules/ + +# frontend-vue build output +frontend-vue/dist/ + +# generated type declarations +frontend-vue/auto-imports.d.ts +frontend-vue/components.d.ts + +# logs +frontend-vue/npm-debug.log* +frontend-vue/yarn-debug.log* +frontend-vue/yarn-error.log* +frontend-vue/pnpm-debug.log* diff --git a/desktop/README.md b/desktop/README.md new file mode 100644 index 0000000..f2ca34e --- /dev/null +++ b/desktop/README.md @@ -0,0 +1,74 @@ +# 桌面端启动 + +## Python 要求 + +桌面端当前依赖 `pywebview`,在 Windows 下建议使用: + +- `Python 3.12` +- `Python 3.11` + +不要直接用 `Python 3.14`。你当前遇到的 `pythonnet` 构建失败就是这个兼容性问题。 + +## 开发模式 + +前置条件: + +- `frontend-vue` 的 Vite 开发服务已启动在 `http://127.0.0.1:5173` +- 后端 API 已启动在 `http://127.0.0.1:8000` +- 本机已安装 `Python 3.12` 或 `Python 3.11` + +启动命令: + +```powershell +cd F:\project\crawler-plugin +.\desktop\run_desktop_dev.ps1 +``` + +脚本会自动: + +- 选择兼容的 Python 解释器 +- 安装 `desktop/requirements.txt` +- 启动 `pywebview` 桌面窗口 + +如果脚本检测不到兼容 Python,会直接提示并退出,不再继续错误安装。 + +## 发布模式 + +先构建前端: + +```powershell +cd F:\project\crawler-plugin\frontend-vue +npm run build +``` + +再启动桌面端: + +```powershell +cd F:\project\crawler-plugin +.\desktop\run_desktop_dist.ps1 +``` + +## 手动安装依赖 + +如果要手动安装,请显式使用兼容版本,例如: + +```powershell +py -3.12 -m pip install -r .\desktop\requirements.txt +``` + +## 当前桌面能力 + +- 选择品牌 Excel 文件 +- 选择文件夹 +- 选择保存目录 +- 另存模板文件 +- 按 URL 下载结果文件到本地 + +## 说明 + +发布模式下,桌面宿主会: + +- 本地托管 `frontend-vue/dist` +- 将 `/api`、`/login`、`/logout`、`/static` 代理到 `--backend-url` + +所以后端仍然需要运行。 diff --git a/desktop/__init__.py b/desktop/__init__.py new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/desktop/__init__.py @@ -0,0 +1 @@ + diff --git a/desktop/__pycache__/__init__.cpython-312.pyc b/desktop/__pycache__/__init__.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..74a00d43d8d163b6dddb7233512a3adcdb5aa1ce GIT binary patch literal 142 zcmX@j%ge<81g~>lIYq;;_lhPbtkwwJTx; T>IRu#3}Sp@W@Kb6Vg|ARb%h~9 literal 0 HcmV?d00001 diff --git a/desktop/__pycache__/app.cpython-312.pyc b/desktop/__pycache__/app.cpython-312.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e0a3df304e08b3e6f861eb8844f6a1742ebf591c GIT binary patch literal 18161 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 literal 0 HcmV?d00001 diff --git a/desktop/__pycache__/app.cpython-314.pyc b/desktop/__pycache__/app.cpython-314.pyc new file mode 100644 index 0000000000000000000000000000000000000000..bb0d42d97bb9426900bac0059a2259d6feebf331 GIT binary patch literal 22571 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 literal 0 HcmV?d00001 diff --git a/desktop/app.py b/desktop/app.py new file mode 100644 index 0000000..59116b4 --- /dev/null +++ b/desktop/app.py @@ -0,0 +1,334 @@ +from __future__ import annotations + +import argparse +import contextlib +import mimetypes +import os +import socket +import threading +from dataclasses import dataclass +from http.server import BaseHTTPRequestHandler, ThreadingHTTPServer +from pathlib import Path +from tkinter import Tk, filedialog +from typing import Iterable +from urllib.parse import urljoin + +try: + import requests +except ModuleNotFoundError as exc: + raise SystemExit( + "缺少依赖 requests。\n" + "请先执行:python -m pip install -r .\\desktop\\requirements.txt" + ) from exc + +try: + import webview +except ModuleNotFoundError as exc: + raise SystemExit( + "缺少依赖 pywebview。\n" + "请先执行:python -m pip install -r .\\desktop\\requirements.txt" + ) from exc + + +ROOT_DIR = Path(__file__).resolve().parents[1] +FRONTEND_DIR = ROOT_DIR / "frontend-vue" +DIST_DIR = FRONTEND_DIR / "dist" +INDEX_FILE = DIST_DIR / "index.html" +PROXY_PREFIXES = ("/api", "/login", "/logout", "/static") + + +def find_free_port() -> int: + with contextlib.closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as sock: + sock.bind(("127.0.0.1", 0)) + return int(sock.getsockname()[1]) + + +def ensure_dist_exists() -> None: + if not INDEX_FILE.exists(): + raise FileNotFoundError( + f"未找到前端构建产物:{INDEX_FILE}\n" + "请先进入 frontend-vue 执行 npm run build。" + ) + + +def resolve_url(base_url: str, maybe_relative_url: str) -> str: + if maybe_relative_url.startswith(("http://", "https://")): + return maybe_relative_url + return urljoin(base_url.rstrip("/") + "/", maybe_relative_url.lstrip("/")) + + +def run_file_dialog(fn): + root = Tk() + root.withdraw() + root.attributes("-topmost", True) + try: + return fn(root) + finally: + root.destroy() + + +@dataclass +class DesktopConfig: + mode: str + frontend_url: str + backend_url: str + host: str + port: int + width: int + height: int + title: str + + +class DesktopApi: + def __init__(self, app_base_url: str) -> None: + self.app_base_url = app_base_url.rstrip("/") + self.session = requests.Session() + + def select_brand_xlsx_files(self) -> list[str]: + files = run_file_dialog( + lambda _root: filedialog.askopenfilenames( + title="选择 Excel 文件", + filetypes=[("Excel files", "*.xlsx")], + ) + ) + return list(files) + + def select_brand_folder(self) -> str | None: + folder = run_file_dialog( + lambda _root: filedialog.askdirectory(title="选择文件夹") + ) + return folder or None + + def select_folder(self) -> str | None: + folder = run_file_dialog( + lambda _root: filedialog.askdirectory(title="选择文件夹") + ) + return folder or None + + def save_template_xlsx(self) -> dict: + return self._download_to_selected_path( + "/static/品牌文档格式_模板.xlsx", + "品牌文档格式_模板.xlsx", + ) + + def save_template_zip(self) -> dict: + return self._download_to_selected_path( + "/static/模板2-以文件夹方式上传.zip", + "模板2-以文件夹方式上传.zip", + ) + + def save_file_from_url(self, url: str, filename: str) -> dict: + return self._download_to_selected_path(url, filename) + + def _download_to_selected_path(self, source_url: str, default_filename: str) -> dict: + path = run_file_dialog( + lambda _root: filedialog.asksaveasfilename( + title="选择保存位置", + initialfile=default_filename, + defaultextension=Path(default_filename).suffix or None, + ) + ) + if not path: + return {"success": False, "error": "用户取消"} + + try: + resolved_url = resolve_url(self.app_base_url, source_url) + with self.session.get(resolved_url, timeout=120, stream=True) as response: + response.raise_for_status() + with open(path, "wb") as file: + for chunk in response.iter_content(chunk_size=1024 * 128): + if chunk: + file.write(chunk) + return {"success": True, "path": path} + except Exception as exc: # noqa: BLE001 + return {"success": False, "error": str(exc)} + + +class DistRequestHandler(BaseHTTPRequestHandler): + backend_base_url = "" + + def do_GET(self) -> None: # noqa: N802 + self._dispatch() + + def do_POST(self) -> None: # noqa: N802 + self._dispatch() + + def do_PUT(self) -> None: # noqa: N802 + self._dispatch() + + def do_DELETE(self) -> None: # noqa: N802 + self._dispatch() + + def do_OPTIONS(self) -> None: # noqa: N802 + self._dispatch() + + def _dispatch(self) -> None: + if self.path.startswith(PROXY_PREFIXES): + self._proxy_to_backend() + return + self._serve_dist_file() + + def _proxy_to_backend(self) -> None: + target_url = resolve_url(self.backend_base_url, self.path) + body = self._read_request_body() + headers = {k: v for k, v in self.headers.items() if k.lower() != "host"} + + try: + response = requests.request( + method=self.command, + url=target_url, + headers=headers, + data=body, + stream=True, + timeout=120, + allow_redirects=False, + ) + except requests.RequestException as exc: + payload = f"后端代理请求失败:{exc}".encode("utf-8") + self.send_response(502) + self.send_header("Content-Type", "text/plain; charset=utf-8") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + return + + self.send_response(response.status_code) + excluded_headers = {"content-encoding", "transfer-encoding", "connection"} + for key, value in response.headers.items(): + if key.lower() in excluded_headers: + continue + self.send_header(key, value) + self.end_headers() + for chunk in response.iter_content(chunk_size=1024 * 128): + if chunk: + self.wfile.write(chunk) + + def _serve_dist_file(self) -> None: + request_path = self.path.split("?", 1)[0].lstrip("/") + if not request_path: + file_path = INDEX_FILE + else: + file_path = (DIST_DIR / request_path).resolve() + if not str(file_path).startswith(str(DIST_DIR.resolve())): + self.send_error(403) + return + if not file_path.exists() or file_path.is_dir(): + file_path = INDEX_FILE + + try: + content = file_path.read_bytes() + except FileNotFoundError: + self.send_error(404) + return + + mime_type, _ = mimetypes.guess_type(str(file_path)) + self.send_response(200) + self.send_header("Content-Type", mime_type or "application/octet-stream") + self.send_header("Content-Length", str(len(content))) + self.end_headers() + self.wfile.write(content) + + def _read_request_body(self) -> bytes | None: + content_length = self.headers.get("Content-Length") + if not content_length: + return None + return self.rfile.read(int(content_length)) + + def log_message(self, format: str, *args) -> None: # noqa: A003 + return + + +class DistServer: + def __init__(self, host: str, port: int, backend_url: str) -> None: + handler = type( + "ConfiguredDistRequestHandler", + (DistRequestHandler,), + {"backend_base_url": backend_url.rstrip("/")}, + ) + self.server = ThreadingHTTPServer((host, port), handler) + self.thread = threading.Thread(target=self.server.serve_forever, daemon=True) + self.base_url = f"http://{host}:{port}" + + def start(self) -> None: + self.thread.start() + + def stop(self) -> None: + self.server.shutdown() + self.server.server_close() + self.thread.join(timeout=2) + + +def build_parser() -> argparse.ArgumentParser: + parser = argparse.ArgumentParser(description="Crawler Plugin 桌面端启动器") + parser.add_argument("--mode", choices=("dev", "dist"), default="dev") + parser.add_argument("--frontend-url", default="http://127.0.0.1:5173") + parser.add_argument("--backend-url", default="http://127.0.0.1:8000") + parser.add_argument("--host", default="127.0.0.1") + parser.add_argument("--port", type=int, default=0) + parser.add_argument("--width", type=int, default=1440) + parser.add_argument("--height", type=int, default=960) + parser.add_argument("--title", default="南日AI") + return parser + + +def parse_args() -> DesktopConfig: + args = build_parser().parse_args() + port = args.port or find_free_port() + return DesktopConfig( + mode=args.mode, + frontend_url=args.frontend_url.rstrip("/"), + backend_url=args.backend_url.rstrip("/"), + host=args.host, + port=port, + width=args.width, + height=args.height, + title=args.title, + ) + + +def ensure_dev_server_ready(frontend_url: str) -> None: + try: + response = requests.get(frontend_url, timeout=5) + response.raise_for_status() + except requests.RequestException as exc: + raise SystemExit( + "Dev server is not reachable.\n" + f"Expected frontend URL: {frontend_url}\n" + "Start Vite first with:\n" + " cd frontend-vue\n" + " npm run dev" + ) from exc + + +def main() -> None: + config = parse_args() + dist_server = None + + if config.mode == "dist": + ensure_dist_exists() + dist_server = DistServer(config.host, config.port, config.backend_url) + dist_server.start() + app_url = dist_server.base_url + else: + ensure_dev_server_ready(config.frontend_url) + app_url = config.frontend_url + + api = DesktopApi(app_url) + window = webview.create_window( + title=config.title, + url=app_url, + js_api=api, + width=config.width, + height=config.height, + min_size=(1200, 760), + ) + + try: + webview.start() + finally: + if dist_server is not None: + dist_server.stop() + + +if __name__ == "__main__": + main() diff --git a/desktop/requirements.txt b/desktop/requirements.txt new file mode 100644 index 0000000..117978c --- /dev/null +++ b/desktop/requirements.txt @@ -0,0 +1,2 @@ +pywebview>=5.1 +requests>=2.32.0 diff --git a/desktop/run_desktop_dev.ps1 b/desktop/run_desktop_dev.ps1 new file mode 100644 index 0000000..9610368 --- /dev/null +++ b/desktop/run_desktop_dev.ps1 @@ -0,0 +1,67 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$root = Split-Path -Parent $PSScriptRoot +Set-Location $root + +function Get-CompatiblePythonCommand { + $pyLauncher = Get-Command py -ErrorAction SilentlyContinue + if ($pyLauncher) { + foreach ($version in @("3.12", "3.11")) { + try { + & py "-$version" --version *> $null + if ($LASTEXITCODE -eq 0) { + return @("py", "-$version") + } + } catch { + } + } + } + + $pythonCommand = Get-Command python -ErrorAction SilentlyContinue + if ($pythonCommand) { + try { + $pythonVersion = (& python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null).Trim() + if ($pythonVersion -in @("3.12", "3.11")) { + return @("python") + } + } catch { + } + } + + return $null +} + +function Invoke-Python { + param( + [string[]]$PythonCommand, + [string[]]$Arguments + ) + + $exe = $PythonCommand[0] + $prefix = @() + if ($PythonCommand.Length -gt 1) { + $prefix = $PythonCommand[1..($PythonCommand.Length - 1)] + } + + & $exe @prefix @Arguments +} + +$pythonCmd = Get-CompatiblePythonCommand +if (-not $pythonCmd) { + Write-Host "" + Write-Host "No compatible Python version was found." + Write-Host "Desktop mode requires Python 3.12 or 3.11 for pywebview on Windows." + Write-Host "Only Python 3.14 was detected, which will fail when installing pythonnet." + Write-Host "" + Write-Host "Install Python 3.12 first, then run:" + Write-Host " .\desktop\run_desktop_dev.ps1" + exit 1 +} + +Write-Host "Using Python: $($pythonCmd -join ' ')" +Write-Host "Ensuring desktop dependencies..." +Invoke-Python -PythonCommand $pythonCmd -Arguments @("-m", "pip", "install", "-r", ".\desktop\requirements.txt") + +Write-Host "Starting desktop app..." +Invoke-Python -PythonCommand $pythonCmd -Arguments @("-m", "desktop.app", "--mode", "dev", "--frontend-url", "http://127.0.0.1:5173", "--backend-url", "http://127.0.0.1:8000") diff --git a/desktop/run_desktop_dist.ps1 b/desktop/run_desktop_dist.ps1 new file mode 100644 index 0000000..39025d2 --- /dev/null +++ b/desktop/run_desktop_dist.ps1 @@ -0,0 +1,67 @@ +Set-StrictMode -Version Latest +$ErrorActionPreference = "Stop" + +$root = Split-Path -Parent $PSScriptRoot +Set-Location $root + +function Get-CompatiblePythonCommand { + $pyLauncher = Get-Command py -ErrorAction SilentlyContinue + if ($pyLauncher) { + foreach ($version in @("3.12", "3.11")) { + try { + & py "-$version" --version *> $null + if ($LASTEXITCODE -eq 0) { + return @("py", "-$version") + } + } catch { + } + } + } + + $pythonCommand = Get-Command python -ErrorAction SilentlyContinue + if ($pythonCommand) { + try { + $pythonVersion = (& python -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')" 2>$null).Trim() + if ($pythonVersion -in @("3.12", "3.11")) { + return @("python") + } + } catch { + } + } + + return $null +} + +function Invoke-Python { + param( + [string[]]$PythonCommand, + [string[]]$Arguments + ) + + $exe = $PythonCommand[0] + $prefix = @() + if ($PythonCommand.Length -gt 1) { + $prefix = $PythonCommand[1..($PythonCommand.Length - 1)] + } + + & $exe @prefix @Arguments +} + +$pythonCmd = Get-CompatiblePythonCommand +if (-not $pythonCmd) { + Write-Host "" + Write-Host "No compatible Python version was found." + Write-Host "Desktop mode requires Python 3.12 or 3.11 for pywebview on Windows." + Write-Host "Only Python 3.14 was detected, which will fail when installing pythonnet." + Write-Host "" + Write-Host "Install Python 3.12 first, then run:" + Write-Host " .\desktop\run_desktop_dist.ps1" + exit 1 +} + +Write-Host "Using Python: $($pythonCmd -join ' ')" +Write-Host "Ensuring desktop dependencies..." +Invoke-Python -PythonCommand $pythonCmd -Arguments @("-m", "pip", "install", "-r", ".\desktop\requirements.txt") + +Write-Host "Starting desktop app..." +Invoke-Python -PythonCommand $pythonCmd -Arguments @("-m", "desktop.app", "--mode", "dist", "--backend-url", "http://127.0.0.1:8000") diff --git a/frontend-vue/index.html b/frontend-vue/index.html new file mode 100644 index 0000000..ab51280 --- /dev/null +++ b/frontend-vue/index.html @@ -0,0 +1,12 @@ + + + + + + 南日AI + + +
+ + + diff --git a/frontend-vue/package-lock.json b/frontend-vue/package-lock.json new file mode 100644 index 0000000..3583256 --- /dev/null +++ b/frontend-vue/package-lock.json @@ -0,0 +1,2524 @@ +{ + "name": "crawler-plugin-frontend-vue", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "crawler-plugin-frontend-vue", + "version": "0.0.1", + "dependencies": { + "axios": "^1.13.6", + "element-plus": "^2.11.4", + "vue": "^3.5.18", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@types/node": "^24.3.0", + "@vitejs/plugin-vue": "^6.0.1", + "typescript": "^5.9.2", + "unplugin-auto-import": "^20.1.0", + "unplugin-vue-components": "^29.0.0", + "vite": "^7.1.3", + "vue-tsc": "^3.0.6" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.27.1", + "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", + "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.28.5", + "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", + "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.2", + "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.2.tgz", + "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.0" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.0", + "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.0.tgz", + "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.27.1", + "@babel/helper-validator-identifier": "^7.28.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@ctrl/tinycolor": { + "version": "4.2.0", + "resolved": "https://registry.npmmirror.com/@ctrl/tinycolor/-/tinycolor-4.2.0.tgz", + "integrity": "sha512-kzyuwOAQnXJNLS9PSyrk0CWk35nWJW/zl/6KvnTBMFK65gm7U1/Z5BqjxeapjZCIhQcM/DsrEmcbRwDyXyXK4A==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/@element-plus/icons-vue": { + "version": "2.3.2", + "resolved": "https://registry.npmmirror.com/@element-plus/icons-vue/-/icons-vue-2.3.2.tgz", + "integrity": "sha512-OzIuTaIfC8QXEPmJvB4Y4kw34rSXdCJzxcD1kFStBvr8bK6X1zQAYDo0CNMjojnfTqRQCJ0I7prlErcoRiET2A==", + "license": "MIT", + "peerDependencies": { + "vue": "^3.2.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.27.4.tgz", + "integrity": "sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.27.4.tgz", + "integrity": "sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.27.4.tgz", + "integrity": "sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.27.4.tgz", + "integrity": "sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.27.4.tgz", + "integrity": "sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.27.4.tgz", + "integrity": "sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.4.tgz", + "integrity": "sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.27.4.tgz", + "integrity": "sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.27.4.tgz", + "integrity": "sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.27.4.tgz", + "integrity": "sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.27.4.tgz", + "integrity": "sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.27.4.tgz", + "integrity": "sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.27.4.tgz", + "integrity": "sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.27.4.tgz", + "integrity": "sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.27.4.tgz", + "integrity": "sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.27.4.tgz", + "integrity": "sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.27.4.tgz", + "integrity": "sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.4.tgz", + "integrity": "sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.27.4.tgz", + "integrity": "sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.4.tgz", + "integrity": "sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.27.4.tgz", + "integrity": "sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.4.tgz", + "integrity": "sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.27.4.tgz", + "integrity": "sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.27.4.tgz", + "integrity": "sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.27.4.tgz", + "integrity": "sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.27.4.tgz", + "integrity": "sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmmirror.com/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmmirror.com/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmmirror.com/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmmirror.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmmirror.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@popperjs/core": { + "name": "@sxzz/popperjs-es", + "version": "2.11.8", + "resolved": "https://registry.npmmirror.com/@sxzz/popperjs-es/-/popperjs-es-2.11.8.tgz", + "integrity": "sha512-wOwESXvvED3S8xBmcPWHs2dUuzrE4XiZeFu7e1hROIJkm02a49N120pmOXxY33sBb6hArItm5W5tcg1cBtV+HQ==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rolldown/pluginutils": { + "version": "1.0.0-rc.2", + "resolved": "https://registry.npmmirror.com/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.2.tgz", + "integrity": "sha512-izyXV/v+cHiRfozX62W9htOAvwMo4/bXKDrQ+vom1L1qRuexPock/7VZDAhnpHCLNejd3NJ6hiab+tO0D44Rgw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.59.0.tgz", + "integrity": "sha512-upnNBkA6ZH2VKGcBj9Fyl9IGNPULcjXRlg0LLeaioQWueH30p6IXtJEbKAgvyv+mJaMxSm1l6xwDXYjpEMiLMg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.59.0.tgz", + "integrity": "sha512-hZ+Zxj3SySm4A/DylsDKZAeVg0mvi++0PYVceVyX7hemkw7OreKdCvW2oQ3T1FMZvCaQXqOTHb8qmBShoqk69Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.59.0.tgz", + "integrity": "sha512-W2Psnbh1J8ZJw0xKAd8zdNgF9HRLkdWwwdWqubSVk0pUuQkoHnv7rx4GiF9rT4t5DIZGAsConRE3AxCdJ4m8rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.59.0.tgz", + "integrity": "sha512-ZW2KkwlS4lwTv7ZVsYDiARfFCnSGhzYPdiOU4IM2fDbL+QGlyAbjgSFuqNRbSthybLbIJ915UtZBtmuLrQAT/w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.59.0.tgz", + "integrity": "sha512-EsKaJ5ytAu9jI3lonzn3BgG8iRBjV4LxZexygcQbpiU0wU0ATxhNVEpXKfUa0pS05gTcSDMKpn3Sx+QB9RlTTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.59.0.tgz", + "integrity": "sha512-d3DuZi2KzTMjImrxoHIAODUZYoUUMsuUiY4SRRcJy6NJoZ6iIqWnJu9IScV9jXysyGMVuW+KNzZvBLOcpdl3Vg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.59.0.tgz", + "integrity": "sha512-t4ONHboXi/3E0rT6OZl1pKbl2Vgxf9vJfWgmUoCEVQVxhW6Cw/c8I6hbbu7DAvgp82RKiH7TpLwxnJeKv2pbsw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.59.0.tgz", + "integrity": "sha512-CikFT7aYPA2ufMD086cVORBYGHffBo4K8MQ4uPS/ZnY54GKj36i196u8U+aDVT2LX4eSMbyHtyOh7D7Zvk2VvA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.59.0.tgz", + "integrity": "sha512-jYgUGk5aLd1nUb1CtQ8E+t5JhLc9x5WdBKew9ZgAXg7DBk0ZHErLHdXM24rfX+bKrFe+Xp5YuJo54I5HFjGDAA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.59.0.tgz", + "integrity": "sha512-peZRVEdnFWZ5Bh2KeumKG9ty7aCXzzEsHShOZEFiCQlDEepP1dpUl/SrUNXNg13UmZl+gzVDPsiCwnV1uI0RUA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.59.0.tgz", + "integrity": "sha512-gbUSW/97f7+r4gHy3Jlup8zDG190AuodsWnNiXErp9mT90iCy9NKKU0Xwx5k8VlRAIV2uU9CsMnEFg/xXaOfXg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.59.0.tgz", + "integrity": "sha512-yTRONe79E+o0FWFijasoTjtzG9EBedFXJMl888NBEDCDV9I2wGbFFfJQQe63OijbFCUZqxpHz1GzpbtSFikJ4Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.59.0.tgz", + "integrity": "sha512-sw1o3tfyk12k3OEpRddF68a1unZ5VCN7zoTNtSn2KndUE+ea3m3ROOKRCZxEpmT9nsGnogpFP9x6mnLTCaoLkA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.59.0.tgz", + "integrity": "sha512-+2kLtQ4xT3AiIxkzFVFXfsmlZiG5FXYW7ZyIIvGA7Bdeuh9Z0aN4hVyXS/G1E9bTP/vqszNIN/pUKCk/BTHsKA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.59.0.tgz", + "integrity": "sha512-NDYMpsXYJJaj+I7UdwIuHHNxXZ/b/N2hR15NyH3m2qAtb/hHPA4g4SuuvrdxetTdndfj9b1WOmy73kcPRoERUg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.59.0.tgz", + "integrity": "sha512-nLckB8WOqHIf1bhymk+oHxvM9D3tyPndZH8i8+35p/1YiVoVswPid2yLzgX7ZJP0KQvnkhM4H6QZ5m0LzbyIAg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.59.0.tgz", + "integrity": "sha512-oF87Ie3uAIvORFBpwnCvUzdeYUqi2wY6jRFWJAy1qus/udHFYIkplYRW+wo+GRUP4sKzYdmE1Y3+rY5Gc4ZO+w==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.59.0.tgz", + "integrity": "sha512-3AHmtQq/ppNuUspKAlvA8HtLybkDflkMuLK4DPo77DfthRb71V84/c4MlWJXixZz4uruIH4uaa07IqoAkG64fg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.59.0.tgz", + "integrity": "sha512-2UdiwS/9cTAx7qIUZB/fWtToJwvt0Vbo0zmnYt7ED35KPg13Q0ym1g442THLC7VyI6JfYTP4PiSOWyoMdV2/xg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.59.0.tgz", + "integrity": "sha512-M3bLRAVk6GOwFlPTIxVBSYKUaqfLrn8l0psKinkCFxl4lQvOSz8ZrKDz2gxcBwHFpci0B6rttydI4IpS4IS/jQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.59.0.tgz", + "integrity": "sha512-tt9KBJqaqp5i5HUZzoafHZX8b5Q2Fe7UjYERADll83O4fGqJ49O1FsL6LpdzVFQcpwvnyd0i+K/VSwu/o/nWlA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.59.0.tgz", + "integrity": "sha512-V5B6mG7OrGTwnxaNUzZTDTjDS7F75PO1ae6MJYdiMu60sq0CqN5CVeVsbhPxalupvTX8gXVSU9gq+Rx1/hvu6A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.59.0.tgz", + "integrity": "sha512-UKFMHPuM9R0iBegwzKF4y0C4J9u8C6MEJgFuXTBerMk7EJ92GFVFYBfOZaSGLu6COf7FxpQNqhNS4c4icUPqxA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.59.0.tgz", + "integrity": "sha512-laBkYlSS1n2L8fSo1thDNGrCTQMmxjYY5G0WFWjFFYZkKPjsMBsgJfGf4TLxXrF6RyhI60L8TMOjBMvXiTcxeA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.59.0.tgz", + "integrity": "sha512-2HRCml6OztYXyJXAvdDXPKcawukWY2GpR5/nxKp4iBgiO3wcoEGkAaqctIbZcNB6KlUQBIqt8VYkNSj2397EfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.24", + "resolved": "https://registry.npmmirror.com/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", + "license": "MIT" + }, + "node_modules/@types/lodash-es": { + "version": "4.17.12", + "resolved": "https://registry.npmmirror.com/@types/lodash-es/-/lodash-es-4.17.12.tgz", + "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==", + "license": "MIT", + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/node": { + "version": "24.12.0", + "resolved": "https://registry.npmmirror.com/@types/node/-/node-24.12.0.tgz", + "integrity": "sha512-GYDxsZi3ChgmckRT9HPU0WEhKLP08ev/Yfcq2AstjrDASOYCSXeyjDsHg4v5t4jOj7cyDX3vmprafKlWIG9MXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.16.0" + } + }, + "node_modules/@types/web-bluetooth": { + "version": "0.0.20", + "resolved": "https://registry.npmmirror.com/@types/web-bluetooth/-/web-bluetooth-0.0.20.tgz", + "integrity": "sha512-g9gZnnXVq7gM7v3tJCWV/qw7w+KeOlSHAhgF9RytFyifW6AF61hdT2ucrYhPq9hLs5JIryeupHV3qGk95dH9ow==", + "license": "MIT" + }, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.5", + "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-6.0.5.tgz", + "integrity": "sha512-bL3AxKuQySfk1iGcBsQnoRVexTPJq0Z/ixFVM8OhVJAP6ZXXXLtM7NFKWhLl30Kg7uTBqIaPXbh+nuQCuBDedg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "1.0.0-rc.2" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } + }, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/source-map": "2.4.28" + } + }, + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmmirror.com/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } + }, + "node_modules/@vue/compiler-core": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.30.tgz", + "integrity": "sha512-s3DfdZkcu/qExZ+td75015ljzHc6vE+30cFMGRPROYjqkroYI5NV2X1yAMX9UeyBNWB9MxCfPcsjpLS11nzkkw==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/shared": "3.5.30", + "entities": "^7.0.1", + "estree-walker": "^2.0.2", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-core/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.30.tgz", + "integrity": "sha512-eCFYESUEVYHhiMuK4SQTldO3RYxyMR/UQL4KdGD1Yrkfdx4m/HYuZ9jSfPdA+nWJY34VWndiYdW/wZXyiPEB9g==", + "license": "MIT", + "dependencies": { + "@vue/compiler-core": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/compiler-sfc": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.30.tgz", + "integrity": "sha512-LqmFPDn89dtU9vI3wHJnwaV6GfTRD87AjWpTWpyrdVOObVtjIuSeZr181z5C4PmVx/V3j2p+0f7edFKGRMpQ5A==", + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.0", + "@vue/compiler-core": "3.5.30", + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30", + "estree-walker": "^2.0.2", + "magic-string": "^0.30.21", + "postcss": "^8.5.8", + "source-map-js": "^1.2.1" + } + }, + "node_modules/@vue/compiler-sfc/node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "license": "MIT" + }, + "node_modules/@vue/compiler-ssr": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.30.tgz", + "integrity": "sha512-NsYK6OMTnx109PSL2IAyf62JP6EUdk4Dmj6AkWcJGBvN0dQoMYtVekAmdqgTtWQgEJo+Okstbf/1p7qZr5H+bA==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/devtools-api": { + "version": "6.6.4", + "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz", + "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==", + "license": "MIT" + }, + "node_modules/@vue/language-core": { + "version": "3.2.6", + "resolved": "https://registry.npmmirror.com/@vue/language-core/-/language-core-3.2.6.tgz", + "integrity": "sha512-xYYYX3/aVup576tP/23sEUpgiEnujrENaoNRbaozC1/MA9I6EGFQRJb4xrt/MmUCAGlxTKL2RmT8JLTPqagCkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/language-core": "2.4.28", + "@vue/compiler-dom": "^3.5.0", + "@vue/shared": "^3.5.0", + "alien-signals": "^3.0.0", + "muggle-string": "^0.4.1", + "path-browserify": "^1.0.1", + "picomatch": "^4.0.2" + } + }, + "node_modules/@vue/reactivity": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.30.tgz", + "integrity": "sha512-179YNgKATuwj9gB+66snskRDOitDiuOZqkYia7mHKJaidOMo/WJxHKF8DuGc4V4XbYTJANlfEKb0yxTQotnx4Q==", + "license": "MIT", + "dependencies": { + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-core": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.30.tgz", + "integrity": "sha512-e0Z+8PQsUTdwV8TtEsLzUM7SzC7lQwYKePydb7K2ZnmS6jjND+WJXkmmfh/swYzRyfP1EY3fpdesyYoymCzYfg==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/shared": "3.5.30" + } + }, + "node_modules/@vue/runtime-dom": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.30.tgz", + "integrity": "sha512-2UIGakjU4WSQ0T4iwDEW0W7vQj6n7AFn7taqZ9Cvm0Q/RA2FFOziLESrDL4GmtI1wV3jXg5nMoJSYO66egDUBw==", + "license": "MIT", + "dependencies": { + "@vue/reactivity": "3.5.30", + "@vue/runtime-core": "3.5.30", + "@vue/shared": "3.5.30", + "csstype": "^3.2.3" + } + }, + "node_modules/@vue/server-renderer": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.30.tgz", + "integrity": "sha512-v+R34icapydRwbZRD0sXwtHqrQJv38JuMB4JxbOxd8NEpGLny7cncMp53W9UH/zo4j8eDHjQ1dEJXwzFQknjtQ==", + "license": "MIT", + "dependencies": { + "@vue/compiler-ssr": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "vue": "3.5.30" + } + }, + "node_modules/@vue/shared": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.30.tgz", + "integrity": "sha512-YXgQ7JjaO18NeK2K9VTbDHaFy62WrObMa6XERNfNOkAhD1F1oDSf3ZJ7K6GqabZ0BvSDHajp8qfS5Sa2I9n8uQ==", + "license": "MIT" + }, + "node_modules/@vueuse/core": { + "version": "12.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/core/-/core-12.0.0.tgz", + "integrity": "sha512-C12RukhXiJCbx4MGhjmd/gH52TjJsc3G0E0kQj/kb19H3Nt6n1CA4DRWuTdWWcaFRdlTe0npWDS942mvacvNBw==", + "license": "MIT", + "dependencies": { + "@types/web-bluetooth": "^0.0.20", + "@vueuse/metadata": "12.0.0", + "@vueuse/shared": "12.0.0", + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/metadata": { + "version": "12.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/metadata/-/metadata-12.0.0.tgz", + "integrity": "sha512-Yzimd1D3sjxTDOlF05HekU5aSGdKjxhuhRFHA7gDWLn57PRbBIh+SF5NmjhJ0WRgF3my7T8LBucyxdFJjIfRJQ==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/@vueuse/shared": { + "version": "12.0.0", + "resolved": "https://registry.npmmirror.com/@vueuse/shared/-/shared-12.0.0.tgz", + "integrity": "sha512-3i6qtcq2PIio5i/vVYidkkcgvmTjCqrf26u+Fd4LhnbBmIT6FN8y6q/GJERp8lfcB9zVEfjdV0Br0443qZuJpw==", + "license": "MIT", + "dependencies": { + "vue": "^3.5.13" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/acorn": { + "version": "8.16.0", + "resolved": "https://registry.npmmirror.com/acorn/-/acorn-8.16.0.tgz", + "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/alien-signals": { + "version": "3.1.2", + "resolved": "https://registry.npmmirror.com/alien-signals/-/alien-signals-3.1.2.tgz", + "integrity": "sha512-d9dYqZTS90WLiU0I5c6DHj/HcKkF8ZyGN3G5x8wSbslulz70KOxaqCT0hQCo9KOyhVqzqGojvNdJXoTumZOtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmmirror.com/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/async-validator": { + "version": "4.2.5", + "resolved": "https://registry.npmmirror.com/async-validator/-/async-validator-4.2.5.tgz", + "integrity": "sha512-7HhHjtERjqlNbZtqNqy2rckN/SpOOlmDliet+lP7k+eKZEjPk3DgyeU9lIXLdeLz0uBbbVp+9Qdow9wJWgwwfg==", + "license": "MIT" + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, + "node_modules/axios": { + "version": "1.13.6", + "resolved": "https://registry.npmmirror.com/axios/-/axios-1.13.6.tgz", + "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "license": "MIT", + "dependencies": { + "follow-redirects": "^1.15.11", + "form-data": "^4.0.5", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/binary-extensions": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/dayjs": { + "version": "1.11.20", + "resolved": "https://registry.npmmirror.com/dayjs/-/dayjs-1.11.20.tgz", + "integrity": "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==", + "license": "MIT" + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/element-plus": { + "version": "2.13.5", + "resolved": "https://registry.npmmirror.com/element-plus/-/element-plus-2.13.5.tgz", + "integrity": "sha512-dmY24fhSREfZN/PuUt0YZigMso7wWzl+B5o+YKNN15kQIn/0hzamsPU+ebj9SES0IbUqsLX1wkrzYmzU8VrVOQ==", + "license": "MIT", + "dependencies": { + "@ctrl/tinycolor": "^4.2.0", + "@element-plus/icons-vue": "^2.3.2", + "@floating-ui/dom": "^1.0.1", + "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7", + "@types/lodash": "^4.17.20", + "@types/lodash-es": "^4.17.12", + "@vueuse/core": "12.0.0", + "async-validator": "^4.2.5", + "dayjs": "^1.11.19", + "lodash": "^4.17.23", + "lodash-es": "^4.17.23", + "lodash-unified": "^1.0.3", + "memoize-one": "^6.0.0", + "normalize-wheel-es": "^1.2.0" + }, + "peerDependencies": { + "vue": "^3.3.0" + } + }, + "node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-object-atoms": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/esbuild": { + "version": "0.27.4", + "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.27.4.tgz", + "integrity": "sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.27.4", + "@esbuild/android-arm": "0.27.4", + "@esbuild/android-arm64": "0.27.4", + "@esbuild/android-x64": "0.27.4", + "@esbuild/darwin-arm64": "0.27.4", + "@esbuild/darwin-x64": "0.27.4", + "@esbuild/freebsd-arm64": "0.27.4", + "@esbuild/freebsd-x64": "0.27.4", + "@esbuild/linux-arm": "0.27.4", + "@esbuild/linux-arm64": "0.27.4", + "@esbuild/linux-ia32": "0.27.4", + "@esbuild/linux-loong64": "0.27.4", + "@esbuild/linux-mips64el": "0.27.4", + "@esbuild/linux-ppc64": "0.27.4", + "@esbuild/linux-riscv64": "0.27.4", + "@esbuild/linux-s390x": "0.27.4", + "@esbuild/linux-x64": "0.27.4", + "@esbuild/netbsd-arm64": "0.27.4", + "@esbuild/netbsd-x64": "0.27.4", + "@esbuild/openbsd-arm64": "0.27.4", + "@esbuild/openbsd-x64": "0.27.4", + "@esbuild/openharmony-arm64": "0.27.4", + "@esbuild/sunos-x64": "0.27.4", + "@esbuild/win32-arm64": "0.27.4", + "@esbuild/win32-ia32": "0.27.4", + "@esbuild/win32-x64": "0.27.4" + } + }, + "node_modules/escape-string-regexp": { + "version": "5.0.0", + "resolved": "https://registry.npmmirror.com/escape-string-regexp/-/escape-string-regexp-5.0.0.tgz", + "integrity": "sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/exsolve": { + "version": "1.0.8", + "resolved": "https://registry.npmmirror.com/exsolve/-/exsolve-1.0.8.tgz", + "integrity": "sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==", + "dev": true, + "license": "MIT" + }, + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmmirror.com/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmmirror.com/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/follow-redirects": { + "version": "1.15.11", + "resolved": "https://registry.npmmirror.com/follow-redirects/-/follow-redirects-1.15.11.tgz", + "integrity": "sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "license": "MIT", + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.5", + "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.5.tgz", + "integrity": "sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "hasown": "^2.0.2", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmmirror.com/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmmirror.com/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmmirror.com/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/js-tokens": { + "version": "9.0.1", + "resolved": "https://registry.npmmirror.com/js-tokens/-/js-tokens-9.0.1.tgz", + "integrity": "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/local-pkg": { + "version": "1.1.2", + "resolved": "https://registry.npmmirror.com/local-pkg/-/local-pkg-1.1.2.tgz", + "integrity": "sha512-arhlxbFRmoQHl33a0Zkle/YWlmNwoyt6QNZEIJcqNbdrsix5Lvc4HyyI3EnwxTYlZYc32EbYrQ8SzEZ7dqgg9A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mlly": "^1.7.4", + "pkg-types": "^2.3.0", + "quansync": "^0.2.11" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/lodash": { + "version": "4.17.23", + "resolved": "https://registry.npmmirror.com/lodash/-/lodash-4.17.23.tgz", + "integrity": "sha512-LgVTMpQtIopCi79SJeDiP0TfWi5CNEc/L/aRdTh3yIvmZXTnheWpKjSZhnvMl8iXbC1tFg9gdHHDMLoV7CnG+w==", + "license": "MIT" + }, + "node_modules/lodash-es": { + "version": "4.17.23", + "resolved": "https://registry.npmmirror.com/lodash-es/-/lodash-es-4.17.23.tgz", + "integrity": "sha512-kVI48u3PZr38HdYz98UmfPnXl2DXrpdctLrFLCd3kOx1xUkOmpFPx7gCWWM5MPkL/fD8zb+Ph0QzjGFs4+hHWg==", + "license": "MIT" + }, + "node_modules/lodash-unified": { + "version": "1.0.3", + "resolved": "https://registry.npmmirror.com/lodash-unified/-/lodash-unified-1.0.3.tgz", + "integrity": "sha512-WK9qSozxXOD7ZJQlpSqOT+om2ZfcT4yO+03FuzAHD0wF6S0l0090LRPDx3vhTTLZ8cFKpBn+IOcVXK6qOcIlfQ==", + "license": "MIT", + "peerDependencies": { + "@types/lodash-es": "*", + "lodash": "*", + "lodash-es": "*" + } + }, + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/memoize-one": { + "version": "6.0.0", + "resolved": "https://registry.npmmirror.com/memoize-one/-/memoize-one-6.0.0.tgz", + "integrity": "sha512-rkpe71W0N0c0Xz6QD0eJETuWAJGnJ9afsl1srmwPrI+yBCkge5EycXXbYRyvL29zZVUWQCY7InPRCv3GDXuZNw==", + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mlly": { + "version": "1.8.1", + "resolved": "https://registry.npmmirror.com/mlly/-/mlly-1.8.1.tgz", + "integrity": "sha512-SnL6sNutTwRWWR/vcmCYHSADjiEesp5TGQQ0pXyLhW5IoeibRlF/CbSLailbB3CNqJUk9cVJ9dUDnbD7GrcHBQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "pathe": "^2.0.3", + "pkg-types": "^1.3.1", + "ufo": "^1.6.3" + } + }, + "node_modules/mlly/node_modules/confbox": { + "version": "0.1.8", + "resolved": "https://registry.npmmirror.com/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/mlly/node_modules/pkg-types": { + "version": "1.3.1", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/muggle-string": { + "version": "0.4.1", + "resolved": "https://registry.npmmirror.com/muggle-string/-/muggle-string-0.4.1.tgz", + "integrity": "sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmmirror.com/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-wheel-es": { + "version": "1.2.0", + "resolved": "https://registry.npmmirror.com/normalize-wheel-es/-/normalize-wheel-es-1.2.0.tgz", + "integrity": "sha512-Wj7+EJQ8mSuXr2iWfnujrimU35R2W4FAErEyTmJoJ7ucwTn2hOUSsRehMb5RSYkxXGTM7Y9QpvPmp++w5ftoJw==", + "license": "BSD-3-Clause" + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmmirror.com/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmmirror.com/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.3", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.3.tgz", + "integrity": "sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-types": { + "version": "2.3.0", + "resolved": "https://registry.npmmirror.com/pkg-types/-/pkg-types-2.3.0.tgz", + "integrity": "sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==", + "dev": true, + "license": "MIT", + "dependencies": { + "confbox": "^0.2.2", + "exsolve": "^1.0.7", + "pathe": "^2.0.3" + } + }, + "node_modules/postcss": { + "version": "8.5.8", + "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.8.tgz", + "integrity": "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.11", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmmirror.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "license": "MIT" + }, + "node_modules/quansync": { + "version": "0.2.11", + "resolved": "https://registry.npmmirror.com/quansync/-/quansync-0.2.11.tgz", + "integrity": "sha512-AifT7QEbW9Nri4tAwR5M/uzpBuqfZf+zwaEM/QkzEjj7NBuFD2rBuy0K3dE+8wltbezDV7JMA0WfnCPYRSYbXA==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/antfu" + }, + { + "type": "individual", + "url": "https://github.com/sponsors/sxzz" + } + ], + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/rollup": { + "version": "4.59.0", + "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.59.0.tgz", + "integrity": "sha512-2oMpl67a3zCH9H79LeMcbDhXW/UmWG/y2zuqnF2jQq5uq9TbM9TVyXvA4+t+ne2IIkBdrLpAaRQAvo7YI/Yyeg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.59.0", + "@rollup/rollup-android-arm64": "4.59.0", + "@rollup/rollup-darwin-arm64": "4.59.0", + "@rollup/rollup-darwin-x64": "4.59.0", + "@rollup/rollup-freebsd-arm64": "4.59.0", + "@rollup/rollup-freebsd-x64": "4.59.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.59.0", + "@rollup/rollup-linux-arm-musleabihf": "4.59.0", + "@rollup/rollup-linux-arm64-gnu": "4.59.0", + "@rollup/rollup-linux-arm64-musl": "4.59.0", + "@rollup/rollup-linux-loong64-gnu": "4.59.0", + "@rollup/rollup-linux-loong64-musl": "4.59.0", + "@rollup/rollup-linux-ppc64-gnu": "4.59.0", + "@rollup/rollup-linux-ppc64-musl": "4.59.0", + "@rollup/rollup-linux-riscv64-gnu": "4.59.0", + "@rollup/rollup-linux-riscv64-musl": "4.59.0", + "@rollup/rollup-linux-s390x-gnu": "4.59.0", + "@rollup/rollup-linux-x64-gnu": "4.59.0", + "@rollup/rollup-linux-x64-musl": "4.59.0", + "@rollup/rollup-openbsd-x64": "4.59.0", + "@rollup/rollup-openharmony-arm64": "4.59.0", + "@rollup/rollup-win32-arm64-msvc": "4.59.0", + "@rollup/rollup-win32-ia32-msvc": "4.59.0", + "@rollup/rollup-win32-x64-gnu": "4.59.0", + "@rollup/rollup-win32-x64-msvc": "4.59.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/scule": { + "version": "1.3.0", + "resolved": "https://registry.npmmirror.com/scule/-/scule-1.3.0.tgz", + "integrity": "sha512-6FtHJEvt+pVMIB9IBY+IcCJ6Z5f1iQnytgyfKMhDKgmzYG+TeH/wx1y3l27rshSbLiSanrR9ffZDrEsmjlQF2g==", + "dev": true, + "license": "MIT" + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-literal": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/strip-literal/-/strip-literal-3.1.0.tgz", + "integrity": "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==", + "dev": true, + "license": "MIT", + "dependencies": { + "js-tokens": "^9.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + } + }, + "node_modules/tinyglobby": { + "version": "0.2.15", + "resolved": "https://registry.npmmirror.com/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmmirror.com/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmmirror.com/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ufo": { + "version": "1.6.3", + "resolved": "https://registry.npmmirror.com/ufo/-/ufo-1.6.3.tgz", + "integrity": "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/undici-types": { + "version": "7.16.0", + "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-7.16.0.tgz", + "integrity": "sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==", + "dev": true, + "license": "MIT" + }, + "node_modules/unimport": { + "version": "5.7.0", + "resolved": "https://registry.npmmirror.com/unimport/-/unimport-5.7.0.tgz", + "integrity": "sha512-njnL6sp8lEA8QQbZrt+52p/g4X0rw3bnGGmUcJnt1jeG8+iiqO779aGz0PirCtydAIVcuTBRlJ52F0u46z309Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.16.0", + "escape-string-regexp": "^5.0.0", + "estree-walker": "^3.0.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "mlly": "^1.8.0", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "pkg-types": "^2.3.0", + "scule": "^1.3.0", + "strip-literal": "^3.1.0", + "tinyglobby": "^0.2.15", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin": { + "version": "2.3.11", + "resolved": "https://registry.npmmirror.com/unplugin/-/unplugin-2.3.11.tgz", + "integrity": "sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "acorn": "^8.15.0", + "picomatch": "^4.0.3", + "webpack-virtual-modules": "^0.6.2" + }, + "engines": { + "node": ">=18.12.0" + } + }, + "node_modules/unplugin-auto-import": { + "version": "20.3.0", + "resolved": "https://registry.npmmirror.com/unplugin-auto-import/-/unplugin-auto-import-20.3.0.tgz", + "integrity": "sha512-RcSEQiVv7g0mLMMXibYVKk8mpteKxvyffGuDKqZZiFr7Oq3PB1HwgHdK5O7H4AzbhzHoVKG0NnMnsk/1HIVYzQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "local-pkg": "^1.1.2", + "magic-string": "^0.30.21", + "picomatch": "^4.0.3", + "unimport": "^5.5.0", + "unplugin": "^2.3.11", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@nuxt/kit": "^4.0.0", + "@vueuse/core": "*" + }, + "peerDependenciesMeta": { + "@nuxt/kit": { + "optional": true + }, + "@vueuse/core": { + "optional": true + } + } + }, + "node_modules/unplugin-utils": { + "version": "0.3.1", + "resolved": "https://registry.npmmirror.com/unplugin-utils/-/unplugin-utils-0.3.1.tgz", + "integrity": "sha512-5lWVjgi6vuHhJ526bI4nlCOmkCIF3nnfXkCMDeMJrtdvxTs6ZFCM8oNufGTsDbKv/tJ/xj8RpvXjRuPBZJuJog==", + "dev": true, + "license": "MIT", + "dependencies": { + "pathe": "^2.0.3", + "picomatch": "^4.0.3" + }, + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/sponsors/sxzz" + } + }, + "node_modules/unplugin-vue-components": { + "version": "29.2.0", + "resolved": "https://registry.npmmirror.com/unplugin-vue-components/-/unplugin-vue-components-29.2.0.tgz", + "integrity": "sha512-QxBeBdmEflgtJRgMQMc/z/JVV5lcwXN5nOy5ehX6CKDGylIu6Qn4Goy8X95S0qOxF7EdI+uNhdBd4v5i0bvzCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "chokidar": "^3.6.0", + "debug": "^4.4.3", + "local-pkg": "^1.1.2", + "magic-string": "^0.30.19", + "mlly": "^1.8.0", + "tinyglobby": "^0.2.15", + "unplugin": "^2.3.10", + "unplugin-utils": "^0.3.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/antfu" + }, + "peerDependencies": { + "@babel/parser": "^7.15.8", + "@nuxt/kit": "^3.2.2 || ^4.0.0", + "vue": "2 || 3" + }, + "peerDependenciesMeta": { + "@babel/parser": { + "optional": true + }, + "@nuxt/kit": { + "optional": true + } + } + }, + "node_modules/vite": { + "version": "7.3.1", + "resolved": "https://registry.npmmirror.com/vite/-/vite-7.3.1.tgz", + "integrity": "sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.27.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", + "postcss": "^8.5.6", + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "lightningcss": "^1.21.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vscode-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmmirror.com/vscode-uri/-/vscode-uri-3.1.0.tgz", + "integrity": "sha512-/BpdSx+yCQGnCvecbyXdxHDkuk55/G3xwnC0GqY4gmQ3j+A+g8kzzgB4Nk/SINjqn6+waqw3EgbVF2QKExkRxQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/vue": { + "version": "3.5.30", + "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.30.tgz", + "integrity": "sha512-hTHLc6VNZyzzEH/l7PFGjpcTvUgiaPK5mdLkbjrTeWSRcEfxFrv56g/XckIYlE9ckuobsdwqd5mk2g1sBkMewg==", + "license": "MIT", + "dependencies": { + "@vue/compiler-dom": "3.5.30", + "@vue/compiler-sfc": "3.5.30", + "@vue/runtime-dom": "3.5.30", + "@vue/server-renderer": "3.5.30", + "@vue/shared": "3.5.30" + }, + "peerDependencies": { + "typescript": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/vue-router": { + "version": "4.6.4", + "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz", + "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==", + "license": "MIT", + "dependencies": { + "@vue/devtools-api": "^6.6.4" + }, + "funding": { + "url": "https://github.com/sponsors/posva" + }, + "peerDependencies": { + "vue": "^3.5.0" + } + }, + "node_modules/vue-tsc": { + "version": "3.2.6", + "resolved": "https://registry.npmmirror.com/vue-tsc/-/vue-tsc-3.2.6.tgz", + "integrity": "sha512-gYW/kWI0XrwGzd0PKc7tVB/qpdeAkIZLNZb10/InizkQjHjnT8weZ/vBarZoj4kHKbUTZT/bAVgoOr8x4NsQ/Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@volar/typescript": "2.4.28", + "@vue/language-core": "3.2.6" + }, + "bin": { + "vue-tsc": "bin/vue-tsc.js" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + } + }, + "node_modules/webpack-virtual-modules": { + "version": "0.6.2", + "resolved": "https://registry.npmmirror.com/webpack-virtual-modules/-/webpack-virtual-modules-0.6.2.tgz", + "integrity": "sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/frontend-vue/package.json b/frontend-vue/package.json new file mode 100644 index 0000000..1e85cce --- /dev/null +++ b/frontend-vue/package.json @@ -0,0 +1,26 @@ +{ + "name": "crawler-plugin-frontend-vue", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite --host --port 5173", + "build": "vue-tsc --noEmit && vite build", + "preview": "vite preview" + }, + "dependencies": { + "axios": "^1.13.6", + "element-plus": "^2.11.4", + "vue": "^3.5.18", + "vue-router": "^4.5.1" + }, + "devDependencies": { + "@types/node": "^24.3.0", + "@vitejs/plugin-vue": "^6.0.1", + "typescript": "^5.9.2", + "unplugin-auto-import": "^20.1.0", + "unplugin-vue-components": "^29.0.0", + "vite": "^7.1.3", + "vue-tsc": "^3.0.6" + } +} \ No newline at end of file diff --git a/frontend-vue/src/App.vue b/frontend-vue/src/App.vue new file mode 100644 index 0000000..98240ae --- /dev/null +++ b/frontend-vue/src/App.vue @@ -0,0 +1,3 @@ + diff --git a/frontend-vue/src/components/layout/PageShell.vue b/frontend-vue/src/components/layout/PageShell.vue new file mode 100644 index 0000000..3f211f6 --- /dev/null +++ b/frontend-vue/src/components/layout/PageShell.vue @@ -0,0 +1,20 @@ + + + diff --git a/frontend-vue/src/main.ts b/frontend-vue/src/main.ts new file mode 100644 index 0000000..34be832 --- /dev/null +++ b/frontend-vue/src/main.ts @@ -0,0 +1,8 @@ +import { createApp } from 'vue' +import ElementPlus from 'element-plus' +import 'element-plus/dist/index.css' +import '@/styles/main.css' +import App from '@/App.vue' +import router from '@/router' + +createApp(App).use(ElementPlus).use(router).mount('#app') diff --git a/frontend-vue/src/pages/admin/index.vue b/frontend-vue/src/pages/admin/index.vue new file mode 100644 index 0000000..ba566d8 --- /dev/null +++ b/frontend-vue/src/pages/admin/index.vue @@ -0,0 +1,584 @@ + + + + + diff --git a/frontend-vue/src/pages/brand/index.vue b/frontend-vue/src/pages/brand/index.vue new file mode 100644 index 0000000..ef72801 --- /dev/null +++ b/frontend-vue/src/pages/brand/index.vue @@ -0,0 +1,1096 @@ + + + + + diff --git a/frontend-vue/src/pages/home/index.vue b/frontend-vue/src/pages/home/index.vue new file mode 100644 index 0000000..edba641 --- /dev/null +++ b/frontend-vue/src/pages/home/index.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/frontend-vue/src/pages/image/index.vue b/frontend-vue/src/pages/image/index.vue new file mode 100644 index 0000000..acf5087 --- /dev/null +++ b/frontend-vue/src/pages/image/index.vue @@ -0,0 +1,94 @@ + + + + + diff --git a/frontend-vue/src/pages/login/index.vue b/frontend-vue/src/pages/login/index.vue new file mode 100644 index 0000000..f9ee27c --- /dev/null +++ b/frontend-vue/src/pages/login/index.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/frontend-vue/src/router.ts b/frontend-vue/src/router.ts new file mode 100644 index 0000000..fee1061 --- /dev/null +++ b/frontend-vue/src/router.ts @@ -0,0 +1,46 @@ +import { createRouter, createWebHistory } from 'vue-router' + +const routes = [ + { + path: '/', + redirect: '/home', + }, + { + path: '/login', + component: () => import('@/pages/login/index.vue'), + meta: { title: '登录 - 南日AI' }, + }, + { + path: '/home', + component: () => import('@/pages/home/index.vue'), + meta: { title: '首页 - 南日AI' }, + }, + { + path: '/brand', + component: () => import('@/pages/brand/index.vue'), + meta: { title: '亚马逊 - 南日AI' }, + }, + { + path: '/admin', + component: () => import('@/pages/admin/index.vue'), + meta: { title: '管理后台 - 南日AI' }, + }, + { + path: '/image', + component: () => import('@/pages/image/index.vue'), + meta: { title: '图片 - 南日AI' }, + }, +] + +const router = createRouter({ + history: createWebHistory(), + routes, +}) + +router.afterEach((to) => { + if (to.meta.title) { + document.title = String(to.meta.title) + } +}) + +export default router diff --git a/frontend-vue/src/shared/api/admin.ts b/frontend-vue/src/shared/api/admin.ts new file mode 100644 index 0000000..c5c65e6 --- /dev/null +++ b/frontend-vue/src/shared/api/admin.ts @@ -0,0 +1,96 @@ +import { requestDeleteJson, requestGetJson, requestPostJson, requestPutJson } from '@/shared/api/http' + +export interface AdminUserItem { + id: number + username?: string + role?: 'super_admin' | 'admin' | 'normal' | string + creator_username?: string + created_at?: string +} + +export interface AdminSimpleUser { + id: number + username: string +} + +export interface AdminUsersResponse { + success: boolean + current_user_role?: 'super_admin' | 'admin' | 'normal' | string + admins?: AdminSimpleUser[] + items?: AdminUserItem[] + total?: number + page?: number + page_size?: number + error?: string +} + +export interface AdminMutationResponse { + success: boolean + msg?: string + error?: string +} + +export interface AdminHistoryItem { + id: number + username?: string + panel_type?: string + created_at?: string + long_image_url?: string | null + result_urls?: string[] +} + +export interface AdminHistoryResponse { + success: boolean + items?: AdminHistoryItem[] + total?: number + page?: number + page_size?: number + error?: string +} + +export interface AdminColumnPermissionItem { + column_key?: string +} + +export interface AdminColumnPermissionResponse { + success: boolean + items?: AdminColumnPermissionItem[] + error?: string +} + +export function getAdminUsers(query = '') { + const suffix = query ? `?${query}` : '' + return requestGetJson(`/api/admin/users${suffix}`) +} + +export function createAdminUser(payload: { + username: string + password: string + role: string + created_by_id?: number +}) { + return requestPostJson('/api/admin/user', payload) +} + +export function updateAdminUser( + userId: number | string, + payload: { + password?: string + role?: string + }, +) { + return requestPutJson(`/api/admin/user/${userId}`, payload) +} + +export function deleteAdminUser(userId: number | string) { + return requestDeleteJson(`/api/admin/user/${userId}`) +} + +export function getAdminHistory(query = '') { + const suffix = query ? `?${query}` : '' + return requestGetJson(`/api/admin/history${suffix}`) +} + +export function getUserColumnPermissions(userId: string | number) { + return requestGetJson(`/api/admin/user/${userId}/column-permissions`) +} diff --git a/frontend-vue/src/shared/api/auth.ts b/frontend-vue/src/shared/api/auth.ts new file mode 100644 index 0000000..da7da51 --- /dev/null +++ b/frontend-vue/src/shared/api/auth.ts @@ -0,0 +1,38 @@ +import { requestGetJson, requestPostJson } from '@/shared/api/http' + +export interface LoginResponse { + success: boolean + redirect?: string + error?: string +} + +export interface AuthCheckResponse { + logged_in: boolean + redirect?: string +} + +export async function checkAuth() { + return requestGetJson('/api/auth/check') +} + +export async function login(username: string, password: string) { + const formData = new FormData() + formData.set('username', username) + formData.set('password', password) + + return requestPostJson('/login', formData, { + headers: { + 'Content-Type': 'multipart/form-data', + }, + }) +} + +export async function logout() { + try { + await requestGetJson('/logout', { + validateStatus: () => true, + }) + } catch { + // logout should still continue on the client even if backend responds abnormally + } +} diff --git a/frontend-vue/src/shared/api/brand.ts b/frontend-vue/src/shared/api/brand.ts new file mode 100644 index 0000000..e7be016 --- /dev/null +++ b/frontend-vue/src/shared/api/brand.ts @@ -0,0 +1,88 @@ +import { requestDeleteJson, requestGetJson, requestPostJson } from '@/shared/api/http' + +export interface BrandExpandFolderResponse { + success: boolean + paths?: string[] + error?: string +} + +export interface BrandTaskResultPaths { + zip_url?: string +} + +export interface BrandTaskItem { + id: number | string + status?: 'pending' | 'running' | 'success' | 'failed' | 'cancelled' | string + desc?: string + file_paths?: string[] + created_at?: string + progress_total?: number + progress_current?: number + result_paths?: BrandTaskResultPaths +} + +export interface BrandTaskListResponse { + success: boolean + items?: BrandTaskItem[] + error?: string +} + +export interface BrandTaskDetailResponse { + success: boolean + task?: BrandTaskItem + error?: string +} + +export interface BrandTaskMutationResponse { + success: boolean + task_id?: string + error?: string +} + +export function getBrandTaskEventsUrl(taskId: string | number) { + return `/api/brand/tasks/${taskId}/events` +} + +export function getBrandTaskDownloadUrl(taskId: string | number) { + return `/api/brand/download/${taskId}` +} + +export function getBrandTemplateXlsxUrl() { + return '/static/品牌文档格式_模板.xlsx' +} + +export function getBrandTemplateZipUrl() { + return '/static/模板2-以文件夹方式上传.zip' +} + +export function expandBrandFolder(folder: string) { + return requestPostJson('/api/brand/expand-folder', { folder }) +} + +export function runBrandNow(paths: string[], strategy: string) { + return requestPostJson('/api/brand/run', { paths, strategy }) +} + +export function createBrandTask(paths: string[], strategy: string) { + return requestPostJson('/api/brand/tasks', { paths, strategy }) +} + +export function getBrandTasks() { + return requestGetJson('/api/brand/tasks') +} + +export function getBrandTask(taskId: string | number) { + return requestGetJson(`/api/brand/tasks/${taskId}`) +} + +export function cancelBrandTask(taskId: string | number) { + return requestPostJson(`/api/brand/tasks/${taskId}/cancel`) +} + +export function deleteBrandTask(taskId: string | number) { + return requestDeleteJson(`/api/brand/tasks/${taskId}`) +} + +export function createBrandTaskEvents(taskId: string | number) { + return new EventSource(getBrandTaskEventsUrl(taskId)) +} diff --git a/frontend-vue/src/shared/api/http.ts b/frontend-vue/src/shared/api/http.ts new file mode 100644 index 0000000..e89e22f --- /dev/null +++ b/frontend-vue/src/shared/api/http.ts @@ -0,0 +1,107 @@ +import axios, { + AxiosError, + type AxiosInstance, + type AxiosRequestConfig, + type AxiosResponse, + type InternalAxiosRequestConfig, +} from 'axios' + +export interface ApiSuccess { + success: true + msg?: string + data?: T +} + +export interface ApiFailure { + success: false + error?: string +} + +export type ApiResponse = ApiSuccess | ApiFailure +export type RequestOptions = AxiosRequestConfig + +function extractErrorMessage(error: unknown) { + if (error instanceof AxiosError) { + const data = error.response?.data + + if (data && typeof data === 'object' && 'error' in data) { + return String(data.error) + } + + if (typeof data === 'string' && data.trim()) { + return data + } + + return error.message || '请求失败' + } + + return error instanceof Error ? error.message : '请求失败' +} + +function createHttpClient(): AxiosInstance { + const instance = axios.create({ + withCredentials: true, + timeout: 30000, + headers: { + 'X-Requested-With': 'XMLHttpRequest', + }, + }) + + instance.interceptors.request.use((config: InternalAxiosRequestConfig) => { + return config + }) + + instance.interceptors.response.use( + (response: AxiosResponse) => response, + (error: unknown) => Promise.reject(new Error(extractErrorMessage(error))), + ) + + return instance +} + +export const http = createHttpClient() + +export async function request(config: RequestOptions): Promise { + const response = await http.request, D>(config) + return response.data +} + +export function get(url: string, config?: RequestOptions) { + return request({ + url, + method: 'GET', + ...config, + }) +} + +export function post(url: string, data?: D, config?: RequestOptions) { + return request({ + url, + method: 'POST', + data, + ...config, + }) +} + +export function put(url: string, data?: D, config?: RequestOptions) { + return request({ + url, + method: 'PUT', + data, + ...config, + }) +} + +export function del(url: string, config?: RequestOptions) { + return request({ + url, + method: 'DELETE', + ...config, + }) +} + +export const requestJson = request +export const requestGetJson = get +export const requestPostJson = post +export const requestPutJson = put +export const requestDeleteJson = del diff --git a/frontend-vue/src/shared/api/update.ts b/frontend-vue/src/shared/api/update.ts new file mode 100644 index 0000000..099ed55 --- /dev/null +++ b/frontend-vue/src/shared/api/update.ts @@ -0,0 +1,22 @@ +import { requestGetJson, requestPostJson } from '@/shared/api/http' + +export interface VersionResponse { + version?: string + has_update?: boolean + latest_version?: string + desc?: string + file_url?: string +} + +export interface UpdateStartResponse { + success: boolean + error?: string +} + +export function fetchVersion() { + return requestGetJson('/api/version') +} + +export function startUpdate(fileUrl: string) { + return requestPostJson('/api/update/do', { file_url: fileUrl }) +} diff --git a/frontend-vue/src/shared/bridges/pywebview.ts b/frontend-vue/src/shared/bridges/pywebview.ts new file mode 100644 index 0000000..52f2628 --- /dev/null +++ b/frontend-vue/src/shared/bridges/pywebview.ts @@ -0,0 +1,24 @@ +export interface PywebviewApi { + select_brand_xlsx_files?: () => Promise + select_brand_folder?: () => Promise + select_folder?: () => Promise + save_template_xlsx?: () => Promise<{ success: boolean; path?: string; error?: string }> + save_template_zip?: () => Promise<{ success: boolean; path?: string; error?: string }> + save_file_from_url?: (url: string, filename: string) => Promise<{ success: boolean; path?: string; error?: string }> +} + +declare global { + interface Window { + pywebview?: { + api?: PywebviewApi + } + } +} + +export function getPywebviewApi() { + return window.pywebview?.api +} + +export function hasPywebview() { + return Boolean(getPywebviewApi()) +} diff --git a/frontend-vue/src/shared/composables/useUpdateCheck.ts b/frontend-vue/src/shared/composables/useUpdateCheck.ts new file mode 100644 index 0000000..ca03bf4 --- /dev/null +++ b/frontend-vue/src/shared/composables/useUpdateCheck.ts @@ -0,0 +1,71 @@ +import { ref } from 'vue' +import { fetchVersion, startUpdate } from '@/shared/api/update' + +export function useUpdateCheck() { + const loading = ref(false) + const version = ref('1.0.0') + const hint = ref('') + const downloadVisible = ref(false) + const downloadLoading = ref(false) + const fileUrl = ref('') + + const check = async () => { + loading.value = true + hint.value = '正在检测更新...' + downloadVisible.value = false + + try { + const result = await fetchVersion() + version.value = (result.version || version.value).replace(/^v/i, '') + + if (result.has_update && result.latest_version) { + hint.value = `发现新版本 v${result.latest_version}${result.desc ? `:${result.desc}` : ''}` + fileUrl.value = result.file_url || '' + downloadVisible.value = true + return + } + + hint.value = '已是最新版本' + } catch (error) { + hint.value = error instanceof Error ? error.message : '检测更新失败' + } finally { + loading.value = false + } + } + + const runUpdate = async () => { + if (!fileUrl.value) { + hint.value = '暂无下载地址,请关注官方渠道。' + return false + } + + downloadLoading.value = true + hint.value = '正在下载并准备更新,程序将自动退出...' + + try { + const result = await startUpdate(fileUrl.value) + if (result.success) { + hint.value = '更新已启动,程序即将退出...' + return true + } + + hint.value = result.error || '更新启动失败' + return false + } catch (error) { + hint.value = error instanceof Error ? error.message : '请求更新失败,请重试' + return false + } finally { + downloadLoading.value = false + } + } + + return { + loading, + version, + hint, + downloadVisible, + downloadLoading, + check, + runUpdate, + } +} diff --git a/frontend-vue/src/shared/utils/bootstrap.ts b/frontend-vue/src/shared/utils/bootstrap.ts new file mode 100644 index 0000000..239c751 --- /dev/null +++ b/frontend-vue/src/shared/utils/bootstrap.ts @@ -0,0 +1,16 @@ +export interface BootstrapState { + username?: string + userId?: string + isAdmin?: boolean + error?: string +} + +declare global { + interface Window { + __BOOTSTRAP__?: BootstrapState + } +} + +export function getBootstrapState(): BootstrapState { + return window.__BOOTSTRAP__ ?? {} +} diff --git a/frontend-vue/src/styles/main.css b/frontend-vue/src/styles/main.css new file mode 100644 index 0000000..169cc44 --- /dev/null +++ b/frontend-vue/src/styles/main.css @@ -0,0 +1,51 @@ +@import './tokens.css'; +@import './reset.css'; + +body { + background: var(--color-bg-light); +} + +html { + scrollbar-color: rgba(123, 135, 148, 0.7) rgba(255, 255, 255, 0.04); + scrollbar-width: thin; +} + +*::-webkit-scrollbar { + width: 10px; + height: 10px; +} + +*::-webkit-scrollbar-track { + background: rgba(255, 255, 255, 0.04); +} + +*::-webkit-scrollbar-thumb { + background: rgba(123, 135, 148, 0.7); + border: 2px solid transparent; + border-radius: 999px; + background-clip: padding-box; +} + +*::-webkit-scrollbar-thumb:hover { + background: rgba(148, 163, 184, 0.9); + border: 2px solid transparent; + background-clip: padding-box; +} + +*::-webkit-scrollbar-corner { + background: transparent; +} + +.page-shell { + min-height: 100vh; +} + +.theme-light { + background: var(--color-bg-light); + color: var(--color-text-primary); +} + +.theme-dark { + background: var(--color-bg-dark); + color: var(--color-text-dark); +} diff --git a/frontend-vue/src/styles/reset.css b/frontend-vue/src/styles/reset.css new file mode 100644 index 0000000..898e95a --- /dev/null +++ b/frontend-vue/src/styles/reset.css @@ -0,0 +1,27 @@ +* { + box-sizing: border-box; +} + +html, +body, +#app { + margin: 0; + min-height: 100%; +} + +body { + font-family: var(--font-family-base); + color: var(--color-text-primary); +} + +a { + color: inherit; + text-decoration: none; +} + +button, +input, +select, +textarea { + font: inherit; +} diff --git a/frontend-vue/src/styles/tokens.css b/frontend-vue/src/styles/tokens.css new file mode 100644 index 0000000..3195ddd --- /dev/null +++ b/frontend-vue/src/styles/tokens.css @@ -0,0 +1,17 @@ +:root { + --font-family-base: "Microsoft YaHei", "PingFang SC", "Hiragino Sans GB", sans-serif; + --color-primary: #409eff; + --color-bg-light: #eef3f8; + --color-bg-dark: #0d0d0d; + --color-surface-light: rgba(255, 255, 255, 0.92); + --color-surface-dark: #1a1a1a; + --color-border-light: #d6e4ef; + --color-border-dark: #2a2a2a; + --color-text-primary: #303133; + --color-text-secondary: #606266; + --color-text-dark: #e5eaf3; + --shadow-card: 0 10px 30px rgba(0, 0, 0, 0.08); + --radius-lg: 16px; + --radius-md: 12px; + --radius-sm: 8px; +} diff --git a/frontend-vue/src/vite-env.d.ts b/frontend-vue/src/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/frontend-vue/src/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/frontend-vue/tsconfig.json b/frontend-vue/tsconfig.json new file mode 100644 index 0000000..98e4ec6 --- /dev/null +++ b/frontend-vue/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "strict": true, + "jsx": "preserve", + "resolveJsonModule": true, + "isolatedModules": true, + "esModuleInterop": true, + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + "baseUrl": ".", + "paths": { + "@/*": ["src/*"] + }, + "types": ["vite/client"] + }, + "include": [ + "src/**/*.ts", + "src/**/*.d.ts", + "src/**/*.tsx", + "src/**/*.vue", + "auto-imports.d.ts", + "components.d.ts" + ], + "references": [{ "path": "./tsconfig.node.json" }] +} \ No newline at end of file diff --git a/frontend-vue/tsconfig.node.json b/frontend-vue/tsconfig.node.json new file mode 100644 index 0000000..787f927 --- /dev/null +++ b/frontend-vue/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "composite": true, + "module": "ESNext", + "moduleResolution": "Bundler", + "allowSyntheticDefaultImports": true, + "types": ["node"] + }, + "include": ["vite.config.ts"] +} \ No newline at end of file diff --git a/frontend-vue/vite.config.ts b/frontend-vue/vite.config.ts new file mode 100644 index 0000000..cd05be6 --- /dev/null +++ b/frontend-vue/vite.config.ts @@ -0,0 +1,51 @@ +import { fileURLToPath, URL } from 'node:url' +import { defineConfig } from 'vite' +import vue from '@vitejs/plugin-vue' +import AutoImport from 'unplugin-auto-import/vite' +import Components from 'unplugin-vue-components/vite' +import { ElementPlusResolver } from 'unplugin-vue-components/resolvers' + +export default defineConfig({ + plugins: [ + vue(), + AutoImport({ + imports: ['vue', 'vue-router'], + resolvers: [ElementPlusResolver()], + dts: 'auto-imports.d.ts', + vueTemplate: true, + }), + Components({ + resolvers: [ElementPlusResolver()], + dts: 'components.d.ts', + }), + ], + resolve: { + alias: { + '@': fileURLToPath(new URL('./src', import.meta.url)), + }, + }, + server: { + port: 5173, + proxy: { + '/api': { + target: 'http://127.0.0.1:8000', + changeOrigin: true, + }, + '/login': { + target: 'http://127.0.0.1:8000', + changeOrigin: true, + }, + '/logout': { + target: 'http://127.0.0.1:8000', + changeOrigin: true, + }, + '/static': { + target: 'http://127.0.0.1:8000', + changeOrigin: true, + }, + }, + }, + build: { + outDir: 'dist', + }, +})