Browse Source

Merge branch 'feature/luojunhui/set-jenkins' of Server/LongArticleTaskServer into master

luojunhui 1 tháng trước cách đây
mục cha
commit
34b7e20ad6

+ 1 - 11
Dockerfile

@@ -1,22 +1,12 @@
-FROM python:3.11-slim
+FROM registry.cn-hangzhou.aliyuncs.com/stuuudy/python:3.11-slim
 
 WORKDIR /app
 
 ENV PYTHONDONTWRITEBYTECODE=1
 ENV PYTHONUNBUFFERED=1
 ENV PIP_DISABLE_PIP_VERSION_CHECK=on
-ENV NVM_DIR=/root/.nvm
 ENV TZ=Asia/Shanghai
 
-# 安装 Node.js(推荐安装官方 LTS 版本)并安装 jsdom
-RUN apt-get update && apt-get install -y curl gnupg ca-certificates \
-    && ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone \
-    && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \
-    && apt-get install -y nodejs \
-    && npm install jsdom \
-    && apt-get clean \
-    && rm -rf /var/lib/apt/lists/*
-
 COPY requirements.txt .
 RUN pip install --no-cache-dir -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
 

+ 1 - 22
docker-compose.yaml

@@ -12,25 +12,4 @@ services:
       - .:/app
     environment:
       - PYTHONUNBUFFERED=1
-    restart: always
-    # 如果应用依赖其他服务(如MySQL)
-    # depends_on:
-    #   - db
-
-  # 如果需要数据库服务,取消注释以下配置
-  # db:
-  #   image: mysql:8.0
-  #   container_name: mysql-db
-  #   environment:
-  #     MYSQL_ROOT_PASSWORD: rootpassword
-  #     MYSQL_DATABASE: mydb
-  #     MYSQL_USER: user
-  #     MYSQL_PASSWORD: password
-  #   volumes:
-  #     - mysql-data:/var/lib/mysql
-  #   ports:
-  #     - "3306:3306"
-
-# 如果需要持久化数据库,取消注释
-# volumes:
-#   mysql-data:
+    restart: always

+ 44 - 0
jenkins_bash.sh

@@ -0,0 +1,44 @@
+REMOTE_HOST="192.168.205.169"
+REMOTE_USER="root"#!/bin/bash
+set -e
+
+echo "===== 1. 准备构建目录 ====="
+BUILD_DIR="/home/docker/LongArticleTaskServer/prod"
+
+rm -rf ${BUILD_DIR:?}/*
+cp -r "$WORKSPACE"/. "$BUILD_DIR"/
+
+cd "$BUILD_DIR"
+
+echo "===== 2. 镜像信息(必须全小写) ====="
+REGISTRY="registry-vpc.cn-hangzhou.aliyuncs.com"
+NAMESPACE="stuuudy"
+IMAGE_NAME="longarticle-taskserver-prod"
+TAG="${BUILD_TIMESTAMP}"
+
+FULL_IMAGE="${REGISTRY}/${NAMESPACE}/${IMAGE_NAME}:${TAG}"
+
+echo "IMAGE => ${FULL_IMAGE}"
+
+echo "===== 3. 登录阿里云镜像仓库 ====="
+echo "Qingqu@2019" | docker login registry.cn-hangzhou.aliyuncs.com -u stuuudys --password-stdin
+
+echo "===== 4. 构建 Docker 镜像 ====="
+docker build \
+  --progress=plain \
+  -t ${FULL_IMAGE} \
+  .
+
+echo "===== 5. 推送 Docker 镜像 ====="
+docker push ${FULL_IMAGE}
+
+echo "===== 6. 远程服务器部署 ====="
+REMOTE_HOST="192.168.205.169"
+REMOTE_USER="root"
+REMOTE_PASS="Qingqu@2024"
+
+sshpass -p "${REMOTE_PASS}" ssh -o StrictHostKeyChecking=no \
+  ${REMOTE_USER}@${REMOTE_HOST} \
+  "sh /home/server/sh/update_docker.sh ${TAG}"
+
+echo "===== ✅ 部署完成 ====="

+ 0 - 14
run_dev_server.sh

@@ -1,14 +0,0 @@
-#!/usr/bin/env bash
-set -e
-
-# 切到脚本所在目录(确保相对路径正确)
-cd "$(dirname "$0")"
-
-# 启动 Hypercorn 服务
-hypercorn task_app:app \
-  --reload \
-  --bind 0.0.0.0:6062 \
-  --workers 1 \
-  --keep-alive 120 \
-  --graceful-timeout 30 \
-  --log-level info

+ 0 - 2
ui/.env.development

@@ -1,2 +0,0 @@
-VITE_API_BASE=http://192.168.142.66:6060
-

+ 0 - 24
ui/.gitignore

@@ -1,24 +0,0 @@
-# Logs
-logs
-*.log
-npm-debug.log*
-yarn-debug.log*
-yarn-error.log*
-pnpm-debug.log*
-lerna-debug.log*
-
-node_modules
-dist
-dist-ssr
-*.local
-
-# Editor directories and files
-.vscode/*
-!.vscode/extensions.json
-.idea
-.DS_Store
-*.suo
-*.ntvs*
-*.njsproj
-*.sln
-*.sw?

+ 0 - 3
ui/.vscode/extensions.json

@@ -1,3 +0,0 @@
-{
-  "recommendations": ["Vue.volar"]
-}

+ 0 - 5
ui/README.md

@@ -1,5 +0,0 @@
-# Vue 3 + TypeScript + Vite
-
-This template should help get you started developing with Vue 3 and TypeScript in Vite. The template uses Vue 3 `<script setup>` SFCs, check out the [script setup docs](https://v3.vuejs.org/api/sfc-script-setup.html#sfc-script-setup) to learn more.
-
-Learn more about the recommended Project Setup and IDE Support in the [Vue Docs TypeScript Guide](https://vuejs.org/guide/typescript/overview.html#project-setup).

+ 0 - 13
ui/index.html

@@ -1,13 +0,0 @@
-<!doctype html>
-<html lang="en">
-  <head>
-    <meta charset="UTF-8" />
-    <link rel="icon" type="image/svg+xml" href="/vite.svg" />
-    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
-    <title>小辉的长文任务管理系统</title>
-  </head>
-  <body>
-    <div id="app"></div>
-    <script type="module" src="/src/main.ts"></script>
-  </body>
-</html>

+ 0 - 1942
ui/package-lock.json

@@ -1,1942 +0,0 @@
-{
-  "name": "ui",
-  "version": "0.0.0",
-  "lockfileVersion": 3,
-  "requires": true,
-  "packages": {
-    "": {
-      "name": "ui",
-      "version": "0.0.0",
-      "dependencies": {
-        "axios": "^1.11.0",
-        "element-plus": "^2.10.6",
-        "vue": "^3.5.18"
-      },
-      "devDependencies": {
-        "@vitejs/plugin-vue": "^6.0.1",
-        "@vue/tsconfig": "^0.7.0",
-        "typescript": "~5.8.3",
-        "vite": "^7.1.0",
-        "vue-tsc": "^3.0.5"
-      }
-    },
-    "node_modules/@babel/helper-string-parser": {
-      "version": "7.27.1",
-      "resolved": "https://registry.npmjs.org/@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.27.1",
-      "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.27.1.tgz",
-      "integrity": "sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@babel/parser": {
-      "version": "7.28.0",
-      "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.28.0.tgz",
-      "integrity": "sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/types": "^7.28.0"
-      },
-      "bin": {
-        "parser": "bin/babel-parser.js"
-      },
-      "engines": {
-        "node": ">=6.0.0"
-      }
-    },
-    "node_modules/@babel/types": {
-      "version": "7.28.2",
-      "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.28.2.tgz",
-      "integrity": "sha512-ruv7Ae4J5dUYULmeXw1gmb7rYRz57OWCPM57pHojnLq/3Z1CK2lNSLTCVjxVk1F/TZHwOZZrOWi0ur95BbLxNQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/helper-string-parser": "^7.27.1",
-        "@babel/helper-validator-identifier": "^7.27.1"
-      },
-      "engines": {
-        "node": ">=6.9.0"
-      }
-    },
-    "node_modules/@ctrl/tinycolor": {
-      "version": "3.6.1",
-      "resolved": "https://registry.npmjs.org/@ctrl/tinycolor/-/tinycolor-3.6.1.tgz",
-      "integrity": "sha512-SITSV6aIXsuVNV3f3O0f2n/cgyEDWoSqtZMYiAmcsYHydcKrOz3gUxB/iXd/Qf08+IZX4KpgNbvUdMBmWz+kcA==",
-      "license": "MIT",
-      "engines": {
-        "node": ">=10"
-      }
-    },
-    "node_modules/@element-plus/icons-vue": {
-      "version": "2.3.2",
-      "resolved": "https://registry.npmjs.org/@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.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.8.tgz",
-      "integrity": "sha512-urAvrUedIqEiFR3FYSLTWQgLu5tb+m0qZw0NBEasUeo6wuqatkMDaRT+1uABiGXEu5vqgPd7FGE1BhsAIy9QVA==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "aix"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.8.tgz",
-      "integrity": "sha512-RONsAvGCz5oWyePVnLdZY/HHwA++nxYWIX1atInlaW6SEkwq6XkP3+cb825EUcRs5Vss/lGh/2YxAb5xqc07Uw==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.8.tgz",
-      "integrity": "sha512-OD3p7LYzWpLhZEyATcTSJ67qB5D+20vbtr6vHlHWSQYhKtzUYrETuWThmzFpZtFsBIxRvhO07+UgVA9m0i/O1w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/android-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.8.tgz",
-      "integrity": "sha512-yJAVPklM5+4+9dTeKwHOaA+LQkmrKFX96BM0A/2zQrbS6ENCmxc4OVoBs5dPkCCak2roAD+jKCdnmOqKszPkjA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.8.tgz",
-      "integrity": "sha512-Jw0mxgIaYX6R8ODrdkLLPwBqHTtYHJSmzzd+QeytSugzQ0Vg4c5rDky5VgkoowbZQahCbsv1rT1KW72MPIkevw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/darwin-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.8.tgz",
-      "integrity": "sha512-Vh2gLxxHnuoQ+GjPNvDSDRpoBCUzY4Pu0kBqMBDlK4fuWbKgGtmDIeEC081xi26PPjn+1tct+Bh8FjyLlw1Zlg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.8.tgz",
-      "integrity": "sha512-YPJ7hDQ9DnNe5vxOm6jaie9QsTwcKedPvizTVlqWG9GBSq+BuyWEDazlGaDTC5NGU4QJd666V0yqCBL2oWKPfA==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/freebsd-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.8.tgz",
-      "integrity": "sha512-MmaEXxQRdXNFsRN/KcIimLnSJrk2r5H8v+WVafRWz5xdSVmWLoITZQXcgehI2ZE6gioE6HirAEToM/RvFBeuhw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.8.tgz",
-      "integrity": "sha512-FuzEP9BixzZohl1kLf76KEVOsxtIBFwCaLupVuk4eFVnOZfU+Wsn+x5Ryam7nILV2pkq2TqQM9EZPsOBuMC+kg==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.8.tgz",
-      "integrity": "sha512-WIgg00ARWv/uYLU7lsuDK00d/hHSfES5BzdWAdAig1ioV5kaFNrtK8EqGcUBJhYqotlUByUKz5Qo6u8tt7iD/w==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ia32": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.8.tgz",
-      "integrity": "sha512-A1D9YzRX1i+1AJZuFFUMP1E9fMaYY+GnSQil9Tlw05utlE86EKTUA7RjwHDkEitmLYiFsRd9HwKBPEftNdBfjg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-loong64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.8.tgz",
-      "integrity": "sha512-O7k1J/dwHkY1RMVvglFHl1HzutGEFFZ3kNiDMSOyUrB7WcoHGf96Sh+64nTRT26l3GMbCW01Ekh/ThKM5iI7hQ==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-mips64el": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.8.tgz",
-      "integrity": "sha512-uv+dqfRazte3BzfMp8PAQXmdGHQt2oC/y2ovwpTteqrMx2lwaksiFZ/bdkXJC19ttTvNXBuWH53zy/aTj1FgGw==",
-      "cpu": [
-        "mips64el"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-ppc64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.8.tgz",
-      "integrity": "sha512-GyG0KcMi1GBavP5JgAkkstMGyMholMDybAf8wF5A70CALlDM2p/f7YFE7H92eDeH/VBtFJA5MT4nRPDGg4JuzQ==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-riscv64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.8.tgz",
-      "integrity": "sha512-rAqDYFv3yzMrq7GIcen3XP7TUEG/4LK86LUPMIz6RT8A6pRIDn0sDcvjudVZBiiTcZCY9y2SgYX2lgK3AF+1eg==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-s390x": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.8.tgz",
-      "integrity": "sha512-Xutvh6VjlbcHpsIIbwY8GVRbwoviWT19tFhgdA7DlenLGC/mbc3lBoVb7jxj9Z+eyGqvcnSyIltYUrkKzWqSvg==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/linux-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.8.tgz",
-      "integrity": "sha512-ASFQhgY4ElXh3nDcOMTkQero4b1lgubskNlhIfJrsH5OKZXDpUAKBlNS0Kx81jwOBp+HCeZqmoJuihTv57/jvQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.8.tgz",
-      "integrity": "sha512-d1KfruIeohqAi6SA+gENMuObDbEjn22olAR7egqnkCD9DGBG0wsEARotkLgXDu6c4ncgWTZJtN5vcgxzWRMzcw==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/netbsd-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.8.tgz",
-      "integrity": "sha512-nVDCkrvx2ua+XQNyfrujIG38+YGyuy2Ru9kKVNyh5jAys6n+l44tTtToqHjino2My8VAY6Lw9H7RI73XFi66Cg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "netbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.8.tgz",
-      "integrity": "sha512-j8HgrDuSJFAujkivSMSfPQSAa5Fxbvk4rgNAS5i3K+r8s1X0p1uOO2Hl2xNsGFppOeHOLAVgYwDVlmxhq5h+SQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openbsd-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.8.tgz",
-      "integrity": "sha512-1h8MUAwa0VhNCDp6Af0HToI2TJFAn1uqT9Al6DJVzdIBAd21m/G0Yfc77KDM3uF3T/YaOgQq3qTJHPbTOInaIQ==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openbsd"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/openharmony-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.25.8.tgz",
-      "integrity": "sha512-r2nVa5SIK9tSWd0kJd9HCffnDHKchTGikb//9c7HX+r+wHYCpQrSgxhlY6KWV1nFo1l4KFbsMlHk+L6fekLsUg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "openharmony"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/sunos-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.8.tgz",
-      "integrity": "sha512-zUlaP2S12YhQ2UzUfcCuMDHQFJyKABkAjvO5YSndMiIkMimPmxA+BYSBikWgsRpvyxuRnow4nS5NPnf9fpv41w==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "sunos"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-arm64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.8.tgz",
-      "integrity": "sha512-YEGFFWESlPva8hGL+zvj2z/SaK+pH0SwOM0Nc/d+rVnW7GSTFlLBGzZkuSU9kFIGIo8q9X3ucpZhu8PDN5A2sQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-ia32": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.8.tgz",
-      "integrity": "sha512-hiGgGC6KZ5LZz58OL/+qVVoZiuZlUYlYHNAmczOm7bs2oE1XriPFi5ZHHrS8ACpV5EjySrnoCKmcbQMN+ojnHg==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@esbuild/win32-x64": {
-      "version": "0.25.8",
-      "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.8.tgz",
-      "integrity": "sha512-cn3Yr7+OaaZq1c+2pe+8yxC8E144SReCQjN6/2ynubzYjvyqZjTXfQJpAcQpsdJq3My7XADANiYGHoFC69pLQw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ],
-      "engines": {
-        "node": ">=18"
-      }
-    },
-    "node_modules/@floating-ui/core": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.3.tgz",
-      "integrity": "sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==",
-      "license": "MIT",
-      "dependencies": {
-        "@floating-ui/utils": "^0.2.10"
-      }
-    },
-    "node_modules/@floating-ui/dom": {
-      "version": "1.7.3",
-      "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.3.tgz",
-      "integrity": "sha512-uZA413QEpNuhtb3/iIKoYMSK07keHPYeXF02Zhd6e213j+d1NamLix/mCLxBUDW/Gx52sPH2m+chlUsyaBs/Ag==",
-      "license": "MIT",
-      "dependencies": {
-        "@floating-ui/core": "^1.7.3",
-        "@floating-ui/utils": "^0.2.10"
-      }
-    },
-    "node_modules/@floating-ui/utils": {
-      "version": "0.2.10",
-      "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.10.tgz",
-      "integrity": "sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==",
-      "license": "MIT"
-    },
-    "node_modules/@jridgewell/sourcemap-codec": {
-      "version": "1.5.4",
-      "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.4.tgz",
-      "integrity": "sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==",
-      "license": "MIT"
-    },
-    "node_modules/@popperjs/core": {
-      "name": "@sxzz/popperjs-es",
-      "version": "2.11.7",
-      "resolved": "https://registry.npmjs.org/@sxzz/popperjs-es/-/popperjs-es-2.11.7.tgz",
-      "integrity": "sha512-Ccy0NlLkzr0Ex2FKvh2X+OyERHXJ88XJ1MXtsI9y9fGexlaXaVTPzBCRBwIxFkORuOb+uBqeu+RqnpgYTEZRUQ==",
-      "license": "MIT",
-      "funding": {
-        "type": "opencollective",
-        "url": "https://opencollective.com/popperjs"
-      }
-    },
-    "node_modules/@rolldown/pluginutils": {
-      "version": "1.0.0-beta.29",
-      "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-beta.29.tgz",
-      "integrity": "sha512-NIJgOsMjbxAXvoGq/X0gD7VPMQ8j9g0BiDaNjVNVjvl+iKXxL3Jre0v31RmBYeLEmkbj2s02v8vFTbUXi5XS2Q==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@rollup/rollup-android-arm-eabi": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.46.2.tgz",
-      "integrity": "sha512-Zj3Hl6sN34xJtMv7Anwb5Gu01yujyE/cLBDB2gnHTAHaWS1Z38L7kuSG+oAh0giZMqG060f/YBStXtMH6FvPMA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@rollup/rollup-android-arm64": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.46.2.tgz",
-      "integrity": "sha512-nTeCWY83kN64oQ5MGz3CgtPx8NSOhC5lWtsjTs+8JAJNLcP3QbLCtDDgUKQc/Ro/frpMq4SHUaHN6AMltcEoLQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "android"
-      ]
-    },
-    "node_modules/@rollup/rollup-darwin-arm64": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.46.2.tgz",
-      "integrity": "sha512-HV7bW2Fb/F5KPdM/9bApunQh68YVDU8sO8BvcW9OngQVN3HHHkw99wFupuUJfGR9pYLLAjcAOA6iO+evsbBaPQ==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@rollup/rollup-darwin-x64": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.46.2.tgz",
-      "integrity": "sha512-SSj8TlYV5nJixSsm/y3QXfhspSiLYP11zpfwp6G/YDXctf3Xkdnk4woJIF5VQe0of2OjzTt8EsxnJDCdHd2xMA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "darwin"
-      ]
-    },
-    "node_modules/@rollup/rollup-freebsd-arm64": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.46.2.tgz",
-      "integrity": "sha512-ZyrsG4TIT9xnOlLsSSi9w/X29tCbK1yegE49RYm3tu3wF1L/B6LVMqnEWyDB26d9Ecx9zrmXCiPmIabVuLmNSg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ]
-    },
-    "node_modules/@rollup/rollup-freebsd-x64": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.46.2.tgz",
-      "integrity": "sha512-pCgHFoOECwVCJ5GFq8+gR8SBKnMO+xe5UEqbemxBpCKYQddRQMgomv1104RnLSg7nNvgKy05sLsY51+OVRyiVw==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "freebsd"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.46.2.tgz",
-      "integrity": "sha512-EtP8aquZ0xQg0ETFcxUbU71MZlHaw9MChwrQzatiE8U/bvi5uv/oChExXC4mWhjiqK7azGJBqU0tt5H123SzVA==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.46.2.tgz",
-      "integrity": "sha512-qO7F7U3u1nfxYRPM8HqFtLd+raev2K137dsV08q/LRKRLEc7RsiDWihUnrINdsWQxPR9jqZ8DIIZ1zJJAm5PjQ==",
-      "cpu": [
-        "arm"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm64-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.46.2.tgz",
-      "integrity": "sha512-3dRaqLfcOXYsfvw5xMrxAk9Lb1f395gkoBYzSFcc/scgRFptRXL9DOaDpMiehf9CO8ZDRJW2z45b6fpU5nwjng==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-arm64-musl": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.46.2.tgz",
-      "integrity": "sha512-fhHFTutA7SM+IrR6lIfiHskxmpmPTJUXpWIsBXpeEwNgZzZZSg/q4i6FU4J8qOGyJ0TR+wXBwx/L7Ho9z0+uDg==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-loongarch64-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.46.2.tgz",
-      "integrity": "sha512-i7wfGFXu8x4+FRqPymzjD+Hyav8l95UIZ773j7J7zRYc3Xsxy2wIn4x+llpunexXe6laaO72iEjeeGyUFmjKeA==",
-      "cpu": [
-        "loong64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.46.2.tgz",
-      "integrity": "sha512-B/l0dFcHVUnqcGZWKcWBSV2PF01YUt0Rvlurci5P+neqY/yMKchGU8ullZvIv5e8Y1C6wOn+U03mrDylP5q9Yw==",
-      "cpu": [
-        "ppc64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.46.2.tgz",
-      "integrity": "sha512-32k4ENb5ygtkMwPMucAb8MtV8olkPT03oiTxJbgkJa7lJ7dZMr0GCFJlyvy+K8iq7F/iuOr41ZdUHaOiqyR3iQ==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-riscv64-musl": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.46.2.tgz",
-      "integrity": "sha512-t5B2loThlFEauloaQkZg9gxV05BYeITLvLkWOkRXogP4qHXLkWSbSHKM9S6H1schf/0YGP/qNKtiISlxvfmmZw==",
-      "cpu": [
-        "riscv64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-s390x-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.46.2.tgz",
-      "integrity": "sha512-YKjekwTEKgbB7n17gmODSmJVUIvj8CX7q5442/CK80L8nqOUbMtf8b01QkG3jOqyr1rotrAnW6B/qiHwfcuWQA==",
-      "cpu": [
-        "s390x"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-x64-gnu": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.46.2.tgz",
-      "integrity": "sha512-Jj5a9RUoe5ra+MEyERkDKLwTXVu6s3aACP51nkfnK9wJTraCC8IMe3snOfALkrjTYd2G1ViE1hICj0fZ7ALBPA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-linux-x64-musl": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.46.2.tgz",
-      "integrity": "sha512-7kX69DIrBeD7yNp4A5b81izs8BqoZkCIaxQaOpumcJ1S/kmqNFjPhDu1LHeVXv0SexfHQv5cqHsxLOjETuqDuA==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "linux"
-      ]
-    },
-    "node_modules/@rollup/rollup-win32-arm64-msvc": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.46.2.tgz",
-      "integrity": "sha512-wiJWMIpeaak/jsbaq2HMh/rzZxHVW1rU6coyeNNpMwk5isiPjSTx0a4YLSlYDwBH/WBvLz+EtsNqQScZTLJy3g==",
-      "cpu": [
-        "arm64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@rollup/rollup-win32-ia32-msvc": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.46.2.tgz",
-      "integrity": "sha512-gBgaUDESVzMgWZhcyjfs9QFK16D8K6QZpwAaVNJxYDLHWayOta4ZMjGm/vsAEy3hvlS2GosVFlBlP9/Wb85DqQ==",
-      "cpu": [
-        "ia32"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@rollup/rollup-win32-x64-msvc": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.46.2.tgz",
-      "integrity": "sha512-CvUo2ixeIQGtF6WvuB87XWqPQkoFAFqW+HUo/WzHwuHDvIwZCtjdWXoYCcr06iKGydiqTclC4jU/TNObC/xKZg==",
-      "cpu": [
-        "x64"
-      ],
-      "dev": true,
-      "license": "MIT",
-      "optional": true,
-      "os": [
-        "win32"
-      ]
-    },
-    "node_modules/@types/estree": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz",
-      "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@types/lodash": {
-      "version": "4.17.20",
-      "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.20.tgz",
-      "integrity": "sha512-H3MHACvFUEiujabxhaI/ImO6gUrd8oOurg7LQtS7mbwIXA/cUqWrvBsaeJ23aZEPk1TAYkurjfMbSELfoCXlGA==",
-      "license": "MIT"
-    },
-    "node_modules/@types/lodash-es": {
-      "version": "4.17.12",
-      "resolved": "https://registry.npmjs.org/@types/lodash-es/-/lodash-es-4.17.12.tgz",
-      "integrity": "sha512-0NgftHUcV4v34VhXm8QBSftKVXtbkBG3ViCjs6+eJ5a6y6Mi/jiFGPc1sC7QK+9BFhWrURE3EOggmWaSxL9OzQ==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/lodash": "*"
-      }
-    },
-    "node_modules/@types/web-bluetooth": {
-      "version": "0.0.16",
-      "resolved": "https://registry.npmjs.org/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
-      "integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
-      "license": "MIT"
-    },
-    "node_modules/@vitejs/plugin-vue": {
-      "version": "6.0.1",
-      "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.1.tgz",
-      "integrity": "sha512-+MaE752hU0wfPFJEUAIxqw18+20euHHdxVtMvbFcOEpjEyfqXH/5DCoTHiVJ0J29EhTJdoTkjEv5YBKU9dnoTw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@rolldown/pluginutils": "1.0.0-beta.29"
-      },
-      "engines": {
-        "node": "^20.19.0 || >=22.12.0"
-      },
-      "peerDependencies": {
-        "vite": "^5.0.0 || ^6.0.0 || ^7.0.0",
-        "vue": "^3.2.25"
-      }
-    },
-    "node_modules/@volar/language-core": {
-      "version": "2.4.22",
-      "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.22.tgz",
-      "integrity": "sha512-gp4M7Di5KgNyIyO903wTClYBavRt6UyFNpc5LWfyZr1lBsTUY+QrVZfmbNF2aCyfklBOVk9YC4p+zkwoyT7ECg==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@volar/source-map": "2.4.22"
-      }
-    },
-    "node_modules/@volar/source-map": {
-      "version": "2.4.22",
-      "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.22.tgz",
-      "integrity": "sha512-L2nVr/1vei0xKRgO2tYVXtJYd09HTRjaZi418e85Q+QdbbqA8h7bBjfNyPPSsjnrOO4l4kaAo78c8SQUAdHvgA==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/@volar/typescript": {
-      "version": "2.4.22",
-      "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.22.tgz",
-      "integrity": "sha512-6ZczlJW1/GWTrNnkmZxJp4qyBt/SGVlcTuCWpI5zLrdPdCZsj66Aff9ZsfFaT3TyjG8zVYgBMYPuCm/eRkpcpQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@volar/language-core": "2.4.22",
-        "path-browserify": "^1.0.1",
-        "vscode-uri": "^3.0.8"
-      }
-    },
-    "node_modules/@vue/compiler-core": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-core/-/compiler-core-3.5.18.tgz",
-      "integrity": "sha512-3slwjQrrV1TO8MoXgy3aynDQ7lslj5UqDxuHnrzHtpON5CBinhWjJETciPngpin/T3OuW3tXUf86tEurusnztw==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/parser": "^7.28.0",
-        "@vue/shared": "3.5.18",
-        "entities": "^4.5.0",
-        "estree-walker": "^2.0.2",
-        "source-map-js": "^1.2.1"
-      }
-    },
-    "node_modules/@vue/compiler-dom": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-dom/-/compiler-dom-3.5.18.tgz",
-      "integrity": "sha512-RMbU6NTU70++B1JyVJbNbeFkK+A+Q7y9XKE2EM4NLGm2WFR8x9MbAtWxPPLdm0wUkuZv9trpwfSlL6tjdIa1+A==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/compiler-core": "3.5.18",
-        "@vue/shared": "3.5.18"
-      }
-    },
-    "node_modules/@vue/compiler-sfc": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-sfc/-/compiler-sfc-3.5.18.tgz",
-      "integrity": "sha512-5aBjvGqsWs+MoxswZPoTB9nSDb3dhd1x30xrrltKujlCxo48j8HGDNj3QPhF4VIS0VQDUrA1xUfp2hEa+FNyXA==",
-      "license": "MIT",
-      "dependencies": {
-        "@babel/parser": "^7.28.0",
-        "@vue/compiler-core": "3.5.18",
-        "@vue/compiler-dom": "3.5.18",
-        "@vue/compiler-ssr": "3.5.18",
-        "@vue/shared": "3.5.18",
-        "estree-walker": "^2.0.2",
-        "magic-string": "^0.30.17",
-        "postcss": "^8.5.6",
-        "source-map-js": "^1.2.1"
-      }
-    },
-    "node_modules/@vue/compiler-ssr": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-ssr/-/compiler-ssr-3.5.18.tgz",
-      "integrity": "sha512-xM16Ak7rSWHkM3m22NlmcdIM+K4BMyFARAfV9hYFl+SFuRzrZ3uGMNW05kA5pmeMa0X9X963Kgou7ufdbpOP9g==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/compiler-dom": "3.5.18",
-        "@vue/shared": "3.5.18"
-      }
-    },
-    "node_modules/@vue/compiler-vue2": {
-      "version": "2.7.16",
-      "resolved": "https://registry.npmjs.org/@vue/compiler-vue2/-/compiler-vue2-2.7.16.tgz",
-      "integrity": "sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "de-indent": "^1.0.2",
-        "he": "^1.2.0"
-      }
-    },
-    "node_modules/@vue/language-core": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/@vue/language-core/-/language-core-3.0.5.tgz",
-      "integrity": "sha512-gCEjn9Ik7I/seHVNIEipOm8W+f3/kg60e8s1IgIkMYma2wu9ZGUTMv3mSL2bX+Md2L8fslceJ4SU8j1fgSRoiw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@volar/language-core": "2.4.22",
-        "@vue/compiler-dom": "^3.5.0",
-        "@vue/compiler-vue2": "^2.7.16",
-        "@vue/shared": "^3.5.0",
-        "alien-signals": "^2.0.5",
-        "muggle-string": "^0.4.1",
-        "path-browserify": "^1.0.1",
-        "picomatch": "^4.0.2"
-      },
-      "peerDependencies": {
-        "typescript": "*"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@vue/reactivity": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/reactivity/-/reactivity-3.5.18.tgz",
-      "integrity": "sha512-x0vPO5Imw+3sChLM5Y+B6G1zPjwdOri9e8V21NnTnlEvkxatHEH5B5KEAJcjuzQ7BsjGrKtfzuQ5eQwXh8HXBg==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/shared": "3.5.18"
-      }
-    },
-    "node_modules/@vue/runtime-core": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-core/-/runtime-core-3.5.18.tgz",
-      "integrity": "sha512-DUpHa1HpeOQEt6+3nheUfqVXRog2kivkXHUhoqJiKR33SO4x+a5uNOMkV487WPerQkL0vUuRvq/7JhRgLW3S+w==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/reactivity": "3.5.18",
-        "@vue/shared": "3.5.18"
-      }
-    },
-    "node_modules/@vue/runtime-dom": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/runtime-dom/-/runtime-dom-3.5.18.tgz",
-      "integrity": "sha512-YwDj71iV05j4RnzZnZtGaXwPoUWeRsqinblgVJwR8XTXYZ9D5PbahHQgsbmzUvCWNF6x7siQ89HgnX5eWkr3mw==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/reactivity": "3.5.18",
-        "@vue/runtime-core": "3.5.18",
-        "@vue/shared": "3.5.18",
-        "csstype": "^3.1.3"
-      }
-    },
-    "node_modules/@vue/server-renderer": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/server-renderer/-/server-renderer-3.5.18.tgz",
-      "integrity": "sha512-PvIHLUoWgSbDG7zLHqSqaCoZvHi6NNmfVFOqO+OnwvqMz/tqQr3FuGWS8ufluNddk7ZLBJYMrjcw1c6XzR12mA==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/compiler-ssr": "3.5.18",
-        "@vue/shared": "3.5.18"
-      },
-      "peerDependencies": {
-        "vue": "3.5.18"
-      }
-    },
-    "node_modules/@vue/shared": {
-      "version": "3.5.18",
-      "resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.18.tgz",
-      "integrity": "sha512-cZy8Dq+uuIXbxCZpuLd2GJdeSO/lIzIspC2WtkqIpje5QyFbvLaI5wZtdUjLHjGZrlVX6GilejatWwVYYRc8tA==",
-      "license": "MIT"
-    },
-    "node_modules/@vue/tsconfig": {
-      "version": "0.7.0",
-      "resolved": "https://registry.npmjs.org/@vue/tsconfig/-/tsconfig-0.7.0.tgz",
-      "integrity": "sha512-ku2uNz5MaZ9IerPPUyOHzyjhXoX2kVJaVf7hL315DC17vS6IiZRmmCPfggNbU16QTvM80+uYYy3eYJB59WCtvg==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "typescript": "5.x",
-        "vue": "^3.4.0"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        },
-        "vue": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@vueuse/core": {
-      "version": "9.13.0",
-      "resolved": "https://registry.npmjs.org/@vueuse/core/-/core-9.13.0.tgz",
-      "integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
-      "license": "MIT",
-      "dependencies": {
-        "@types/web-bluetooth": "^0.0.16",
-        "@vueuse/metadata": "9.13.0",
-        "@vueuse/shared": "9.13.0",
-        "vue-demi": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      }
-    },
-    "node_modules/@vueuse/core/node_modules/vue-demi": {
-      "version": "0.14.10",
-      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
-      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "vue-demi-fix": "bin/vue-demi-fix.js",
-        "vue-demi-switch": "bin/vue-demi-switch.js"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      },
-      "peerDependencies": {
-        "@vue/composition-api": "^1.0.0-rc.1",
-        "vue": "^3.0.0-0 || ^2.6.0"
-      },
-      "peerDependenciesMeta": {
-        "@vue/composition-api": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/@vueuse/metadata": {
-      "version": "9.13.0",
-      "resolved": "https://registry.npmjs.org/@vueuse/metadata/-/metadata-9.13.0.tgz",
-      "integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
-      "license": "MIT",
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      }
-    },
-    "node_modules/@vueuse/shared": {
-      "version": "9.13.0",
-      "resolved": "https://registry.npmjs.org/@vueuse/shared/-/shared-9.13.0.tgz",
-      "integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
-      "license": "MIT",
-      "dependencies": {
-        "vue-demi": "*"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      }
-    },
-    "node_modules/@vueuse/shared/node_modules/vue-demi": {
-      "version": "0.14.10",
-      "resolved": "https://registry.npmjs.org/vue-demi/-/vue-demi-0.14.10.tgz",
-      "integrity": "sha512-nMZBOwuzabUO0nLgIcc6rycZEebF6eeUfaiQx9+WSk8e29IbLvPU9feI6tqW4kTo3hvoYAJkMh8n8D0fuISphg==",
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "vue-demi-fix": "bin/vue-demi-fix.js",
-        "vue-demi-switch": "bin/vue-demi-switch.js"
-      },
-      "engines": {
-        "node": ">=12"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/antfu"
-      },
-      "peerDependencies": {
-        "@vue/composition-api": "^1.0.0-rc.1",
-        "vue": "^3.0.0-0 || ^2.6.0"
-      },
-      "peerDependenciesMeta": {
-        "@vue/composition-api": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/alien-signals": {
-      "version": "2.0.6",
-      "resolved": "https://registry.npmjs.org/alien-signals/-/alien-signals-2.0.6.tgz",
-      "integrity": "sha512-P3TxJSe31bUHBiblg59oU1PpaWPtmxF9GhJ/cB7OkgJ0qN/ifFSKUI25/v8ZhsT+lIG6ac8DpTOplXxORX6F3Q==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/async-validator": {
-      "version": "4.2.5",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
-      "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==",
-      "license": "MIT"
-    },
-    "node_modules/axios": {
-      "version": "1.11.0",
-      "resolved": "https://registry.npmjs.org/axios/-/axios-1.11.0.tgz",
-      "integrity": "sha512-1Lx3WLFQWm3ooKDYZD1eXmoGO9fxYQjrycfHFC8P0sCfQVXyROp0p9PFWBehewBOdCwHc+f/b8I0fMto5eSfwA==",
-      "license": "MIT",
-      "dependencies": {
-        "follow-redirects": "^1.15.6",
-        "form-data": "^4.0.4",
-        "proxy-from-env": "^1.1.0"
-      }
-    },
-    "node_modules/call-bind-apply-helpers": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/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/combined-stream": {
-      "version": "1.0.8",
-      "resolved": "https://registry.npmjs.org/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/csstype": {
-      "version": "3.1.3",
-      "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz",
-      "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==",
-      "license": "MIT"
-    },
-    "node_modules/dayjs": {
-      "version": "1.11.13",
-      "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.13.tgz",
-      "integrity": "sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==",
-      "license": "MIT"
-    },
-    "node_modules/de-indent": {
-      "version": "1.0.2",
-      "resolved": "https://registry.npmjs.org/de-indent/-/de-indent-1.0.2.tgz",
-      "integrity": "sha512-e/1zu3xH5MQryN2zdVaF0OrdNLUbvWxzMbi+iNA6Bky7l1RoP8a2fIbRocyHclXt/arDrrR6lL3TqFD9pMQTsg==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/delayed-stream": {
-      "version": "1.0.0",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/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.10.6",
-      "resolved": "https://registry.npmjs.org/element-plus/-/element-plus-2.10.6.tgz",
-      "integrity": "sha512-N1XfO+x46p9Df9KNHeRQiHW4ilt4k+Jh6jeA1Ip9WpVzwDW8CRz+NqaLLDEZmnez62bBdCuWGfV7lIRq3+FQyg==",
-      "license": "MIT",
-      "dependencies": {
-        "@ctrl/tinycolor": "^3.4.1",
-        "@element-plus/icons-vue": "^2.3.1",
-        "@floating-ui/dom": "^1.0.1",
-        "@popperjs/core": "npm:@sxzz/popperjs-es@^2.11.7",
-        "@types/lodash": "^4.14.182",
-        "@types/lodash-es": "^4.17.6",
-        "@vueuse/core": "^9.1.0",
-        "async-validator": "^4.2.5",
-        "dayjs": "^1.11.13",
-        "escape-html": "^1.0.3",
-        "lodash": "^4.17.21",
-        "lodash-es": "^4.17.21",
-        "lodash-unified": "^1.0.2",
-        "memoize-one": "^6.0.0",
-        "normalize-wheel-es": "^1.2.0"
-      },
-      "peerDependencies": {
-        "vue": "^3.2.0"
-      }
-    },
-    "node_modules/entities": {
-      "version": "4.5.0",
-      "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
-      "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
-      "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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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.25.8",
-      "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.8.tgz",
-      "integrity": "sha512-vVC0USHGtMi8+R4Kz8rt6JhEWLxsv9Rnu/lGYbPR8u47B+DCBksq9JarW0zOO7bs37hyOK1l2/oqtbciutL5+Q==",
-      "dev": true,
-      "hasInstallScript": true,
-      "license": "MIT",
-      "bin": {
-        "esbuild": "bin/esbuild"
-      },
-      "engines": {
-        "node": ">=18"
-      },
-      "optionalDependencies": {
-        "@esbuild/aix-ppc64": "0.25.8",
-        "@esbuild/android-arm": "0.25.8",
-        "@esbuild/android-arm64": "0.25.8",
-        "@esbuild/android-x64": "0.25.8",
-        "@esbuild/darwin-arm64": "0.25.8",
-        "@esbuild/darwin-x64": "0.25.8",
-        "@esbuild/freebsd-arm64": "0.25.8",
-        "@esbuild/freebsd-x64": "0.25.8",
-        "@esbuild/linux-arm": "0.25.8",
-        "@esbuild/linux-arm64": "0.25.8",
-        "@esbuild/linux-ia32": "0.25.8",
-        "@esbuild/linux-loong64": "0.25.8",
-        "@esbuild/linux-mips64el": "0.25.8",
-        "@esbuild/linux-ppc64": "0.25.8",
-        "@esbuild/linux-riscv64": "0.25.8",
-        "@esbuild/linux-s390x": "0.25.8",
-        "@esbuild/linux-x64": "0.25.8",
-        "@esbuild/netbsd-arm64": "0.25.8",
-        "@esbuild/netbsd-x64": "0.25.8",
-        "@esbuild/openbsd-arm64": "0.25.8",
-        "@esbuild/openbsd-x64": "0.25.8",
-        "@esbuild/openharmony-arm64": "0.25.8",
-        "@esbuild/sunos-x64": "0.25.8",
-        "@esbuild/win32-arm64": "0.25.8",
-        "@esbuild/win32-ia32": "0.25.8",
-        "@esbuild/win32-x64": "0.25.8"
-      }
-    },
-    "node_modules/escape-html": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
-      "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==",
-      "license": "MIT"
-    },
-    "node_modules/estree-walker": {
-      "version": "2.0.2",
-      "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
-      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
-      "license": "MIT"
-    },
-    "node_modules/fdir": {
-      "version": "6.4.6",
-      "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.6.tgz",
-      "integrity": "sha512-hiFoqpyZcfNm1yc4u8oWCf9A2c4D3QjCrks3zmoVKVxpQRzmPNar1hUJcBG2RQHvEVGDN+Jm81ZheVLAQMK6+w==",
-      "dev": true,
-      "license": "MIT",
-      "peerDependencies": {
-        "picomatch": "^3 || ^4"
-      },
-      "peerDependenciesMeta": {
-        "picomatch": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/follow-redirects": {
-      "version": "1.15.11",
-      "resolved": "https://registry.npmjs.org/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.4",
-      "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.4.tgz",
-      "integrity": "sha512-KrGhL9Q4zjj0kiUt5OO4Mr/A/jlI2jDYs5eHBpYHPcBEVSiipAvn2Ko2HnPe20rmcuuvMHNdZFp+4IlGTMF0Ow==",
-      "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.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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/gopd": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/hasown/-/hasown-2.0.2.tgz",
-      "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
-      "license": "MIT",
-      "dependencies": {
-        "function-bind": "^1.1.2"
-      },
-      "engines": {
-        "node": ">= 0.4"
-      }
-    },
-    "node_modules/he": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz",
-      "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==",
-      "dev": true,
-      "license": "MIT",
-      "bin": {
-        "he": "bin/he"
-      }
-    },
-    "node_modules/lodash": {
-      "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
-      "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
-      "license": "MIT"
-    },
-    "node_modules/lodash-es": {
-      "version": "4.17.21",
-      "resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
-      "integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==",
-      "license": "MIT"
-    },
-    "node_modules/lodash-unified": {
-      "version": "1.0.3",
-      "resolved": "https://registry.npmjs.org/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.17",
-      "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz",
-      "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==",
-      "license": "MIT",
-      "dependencies": {
-        "@jridgewell/sourcemap-codec": "^1.5.0"
-      }
-    },
-    "node_modules/math-intrinsics": {
-      "version": "1.1.0",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/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.npmjs.org/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.npmjs.org/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/muggle-string": {
-      "version": "0.4.1",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/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-wheel-es": {
-      "version": "1.2.0",
-      "resolved": "https://registry.npmjs.org/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.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz",
-      "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==",
-      "dev": true,
-      "license": "MIT"
-    },
-    "node_modules/picocolors": {
-      "version": "1.1.1",
-      "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
-      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
-      "license": "ISC"
-    },
-    "node_modules/picomatch": {
-      "version": "4.0.3",
-      "resolved": "https://registry.npmjs.org/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/postcss": {
-      "version": "8.5.6",
-      "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.6.tgz",
-      "integrity": "sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==",
-      "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.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
-      "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==",
-      "license": "MIT"
-    },
-    "node_modules/rollup": {
-      "version": "4.46.2",
-      "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.46.2.tgz",
-      "integrity": "sha512-WMmLFI+Boh6xbop+OAGo9cQ3OgX9MIg7xOQjn+pTCwOkk+FNDAeAemXkJ3HzDJrVXleLOFVa1ipuc1AmEx1Dwg==",
-      "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.46.2",
-        "@rollup/rollup-android-arm64": "4.46.2",
-        "@rollup/rollup-darwin-arm64": "4.46.2",
-        "@rollup/rollup-darwin-x64": "4.46.2",
-        "@rollup/rollup-freebsd-arm64": "4.46.2",
-        "@rollup/rollup-freebsd-x64": "4.46.2",
-        "@rollup/rollup-linux-arm-gnueabihf": "4.46.2",
-        "@rollup/rollup-linux-arm-musleabihf": "4.46.2",
-        "@rollup/rollup-linux-arm64-gnu": "4.46.2",
-        "@rollup/rollup-linux-arm64-musl": "4.46.2",
-        "@rollup/rollup-linux-loongarch64-gnu": "4.46.2",
-        "@rollup/rollup-linux-ppc64-gnu": "4.46.2",
-        "@rollup/rollup-linux-riscv64-gnu": "4.46.2",
-        "@rollup/rollup-linux-riscv64-musl": "4.46.2",
-        "@rollup/rollup-linux-s390x-gnu": "4.46.2",
-        "@rollup/rollup-linux-x64-gnu": "4.46.2",
-        "@rollup/rollup-linux-x64-musl": "4.46.2",
-        "@rollup/rollup-win32-arm64-msvc": "4.46.2",
-        "@rollup/rollup-win32-ia32-msvc": "4.46.2",
-        "@rollup/rollup-win32-x64-msvc": "4.46.2",
-        "fsevents": "~2.3.2"
-      }
-    },
-    "node_modules/source-map-js": {
-      "version": "1.2.1",
-      "resolved": "https://registry.npmjs.org/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/tinyglobby": {
-      "version": "0.2.14",
-      "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.14.tgz",
-      "integrity": "sha512-tX5e7OM1HnYr2+a2C/4V0htOcSQcoSTH9KgJnVvNm5zm/cyEWKJ7j7YutsH9CxMdtOkkLFy2AHrMci9IM8IPZQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "fdir": "^6.4.4",
-        "picomatch": "^4.0.2"
-      },
-      "engines": {
-        "node": ">=12.0.0"
-      },
-      "funding": {
-        "url": "https://github.com/sponsors/SuperchupuDev"
-      }
-    },
-    "node_modules/typescript": {
-      "version": "5.8.3",
-      "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
-      "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
-      "devOptional": true,
-      "license": "Apache-2.0",
-      "bin": {
-        "tsc": "bin/tsc",
-        "tsserver": "bin/tsserver"
-      },
-      "engines": {
-        "node": ">=14.17"
-      }
-    },
-    "node_modules/vite": {
-      "version": "7.1.1",
-      "resolved": "https://registry.npmjs.org/vite/-/vite-7.1.1.tgz",
-      "integrity": "sha512-yJ+Mp7OyV+4S+afWo+QyoL9jFWD11QFH0i5i7JypnfTcA1rmgxCbiA8WwAICDEtZ1Z1hzrVhN8R8rGTqkTY8ZQ==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "esbuild": "^0.25.0",
-        "fdir": "^6.4.6",
-        "picomatch": "^4.0.3",
-        "postcss": "^8.5.6",
-        "rollup": "^4.43.0",
-        "tinyglobby": "^0.2.14"
-      },
-      "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.npmjs.org/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.18",
-      "resolved": "https://registry.npmjs.org/vue/-/vue-3.5.18.tgz",
-      "integrity": "sha512-7W4Y4ZbMiQ3SEo+m9lnoNpV9xG7QVMLa+/0RFwwiAVkeYoyGXqWE85jabU4pllJNUzqfLShJ5YLptewhCWUgNA==",
-      "license": "MIT",
-      "dependencies": {
-        "@vue/compiler-dom": "3.5.18",
-        "@vue/compiler-sfc": "3.5.18",
-        "@vue/runtime-dom": "3.5.18",
-        "@vue/server-renderer": "3.5.18",
-        "@vue/shared": "3.5.18"
-      },
-      "peerDependencies": {
-        "typescript": "*"
-      },
-      "peerDependenciesMeta": {
-        "typescript": {
-          "optional": true
-        }
-      }
-    },
-    "node_modules/vue-tsc": {
-      "version": "3.0.5",
-      "resolved": "https://registry.npmjs.org/vue-tsc/-/vue-tsc-3.0.5.tgz",
-      "integrity": "sha512-PsTFN9lo1HJCrZw9NoqjYcAbYDXY0cOKyuW2E7naX5jcaVyWpqEsZOHN9Dws5890E8e5SDAD4L4Zam3dxG3/Cw==",
-      "dev": true,
-      "license": "MIT",
-      "dependencies": {
-        "@volar/typescript": "2.4.22",
-        "@vue/language-core": "3.0.5"
-      },
-      "bin": {
-        "vue-tsc": "bin/vue-tsc.js"
-      },
-      "peerDependencies": {
-        "typescript": ">=5.0.0"
-      }
-    }
-  }
-}

+ 0 - 23
ui/package.json

@@ -1,23 +0,0 @@
-{
-  "name": "ui",
-  "private": true,
-  "version": "0.0.0",
-  "type": "module",
-  "scripts": {
-    "dev": "vite",
-    "build": "vue-tsc -b && vite build",
-    "preview": "vite preview"
-  },
-  "dependencies": {
-    "axios": "^1.11.0",
-    "element-plus": "^2.10.6",
-    "vue": "^3.5.18"
-  },
-  "devDependencies": {
-    "@vitejs/plugin-vue": "^6.0.1",
-    "@vue/tsconfig": "^0.7.0",
-    "typescript": "~5.8.3",
-    "vite": "^7.1.0",
-    "vue-tsc": "^3.0.5"
-  }
-}

+ 0 - 1
ui/public/vite.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="31.88" height="32" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 257"><defs><linearGradient id="IconifyId1813088fe1fbc01fb466" x1="-.828%" x2="57.636%" y1="7.652%" y2="78.411%"><stop offset="0%" stop-color="#41D1FF"></stop><stop offset="100%" stop-color="#BD34FE"></stop></linearGradient><linearGradient id="IconifyId1813088fe1fbc01fb467" x1="43.376%" x2="50.316%" y1="2.242%" y2="89.03%"><stop offset="0%" stop-color="#FFEA83"></stop><stop offset="8.333%" stop-color="#FFDD35"></stop><stop offset="100%" stop-color="#FFA800"></stop></linearGradient></defs><path fill="url(#IconifyId1813088fe1fbc01fb466)" d="M255.153 37.938L134.897 252.976c-2.483 4.44-8.862 4.466-11.382.048L.875 37.958c-2.746-4.814 1.371-10.646 6.827-9.67l120.385 21.517a6.537 6.537 0 0 0 2.322-.004l117.867-21.483c5.438-.991 9.574 4.796 6.877 9.62Z"></path><path fill="url(#IconifyId1813088fe1fbc01fb467)" d="M185.432.063L96.44 17.501a3.268 3.268 0 0 0-2.634 3.014l-5.474 92.456a3.268 3.268 0 0 0 3.997 3.378l24.777-5.718c2.318-.535 4.413 1.507 3.936 3.838l-7.361 36.047c-.495 2.426 1.782 4.5 4.151 3.78l15.304-4.649c2.372-.72 4.652 1.36 4.15 3.788l-11.698 56.621c-.732 3.542 3.979 5.473 5.943 2.437l1.313-2.028l72.516-144.72c1.215-2.423-.88-5.186-3.54-4.672l-25.505 4.922c-2.396.462-4.435-1.77-3.759-4.114l16.646-57.705c.677-2.35-1.37-4.583-3.769-4.113Z"></path></svg>

+ 0 - 3
ui/src/App.vue

@@ -1,3 +0,0 @@
-<template>
-  <router-view />
-</template>

+ 0 - 47
ui/src/api/task.ts

@@ -1,47 +0,0 @@
-import axios from 'axios'
-import { API_CONFIG, API_ENDPOINTS } from '../config/api'
-
-const api = axios.create({
-  baseURL: API_CONFIG.BASE_URL,
-  timeout: API_CONFIG.TIMEOUT,
-})
-
-export interface TaskItem {
-  id: number
-  date_string: string | null
-  task_name: string | null
-  task_status: number
-  start_timestamp: number | null
-  finish_timestamp: number | null
-  trace_id: string | null
-  data: string | null
-  status_text?: string
-  data_json?: any
-}
-
-export interface TaskListResp {
-  items: TaskItem[]
-  total: number
-  page: number
-  page_size: number
-}
-
-export async function fetchTasks(params: Record<string, any>): Promise<TaskListResp> {
-  const { data } = await api.post<TaskListResp>(API_ENDPOINTS.TASKS, params)
-  return data
-}
-
-export async function fetchTaskDetail(id: number): Promise<TaskItem> {
-  const { data } = await api.get<TaskItem>(API_ENDPOINTS.TASK_DETAIL(id))
-  return data
-}
-
-export async function retryTask(id: number): Promise<any> {
-  const { data } = await api.post(API_ENDPOINTS.TASK_RETRY(id))
-  return data
-}
-
-export async function cancelTask(id: number): Promise<any> {
-  const { data } = await api.post(API_ENDPOINTS.TASK_CANCEL(id))
-  return data
-}

+ 0 - 1
ui/src/assets/vue.svg

@@ -1 +0,0 @@
-<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" role="img" class="iconify iconify--logos" width="37.07" height="36" preserveAspectRatio="xMidYMid meet" viewBox="0 0 256 198"><path fill="#41B883" d="M204.8 0H256L128 220.8L0 0h97.92L128 51.2L157.44 0h47.36Z"></path><path fill="#41B883" d="m0 0l128 220.8L256 0h-51.2L128 132.48L50.56 0H0Z"></path><path fill="#35495E" d="M50.56 0L128 133.12L204.8 0h-47.36L128 51.2L97.92 0H50.56Z"></path></svg>

+ 0 - 41
ui/src/components/HelloWorld.vue

@@ -1,41 +0,0 @@
-<script setup lang="ts">
-import { ref } from 'vue'
-
-defineProps<{ msg: string }>()
-
-const count = ref(0)
-</script>
-
-<template>
-  <h1>{{ msg }}</h1>
-
-  <div class="card">
-    <button type="button" @click="count++">count is {{ count }}</button>
-    <p>
-      Edit
-      <code>components/HelloWorld.vue</code> to test HMR
-    </p>
-  </div>
-
-  <p>
-    Check out
-    <a href="https://vuejs.org/guide/quick-start.html#local" target="_blank"
-      >create-vue</a
-    >, the official Vue + Vite starter
-  </p>
-  <p>
-    Learn more about IDE Support for Vue in the
-    <a
-      href="https://vuejs.org/guide/scaling-up/tooling.html#ide-support"
-      target="_blank"
-      >Vue Docs Scaling up Guide</a
-    >.
-  </p>
-  <p class="read-the-docs">Click on the Vite and Vue logos to learn more</p>
-</template>
-
-<style scoped>
-.read-the-docs {
-  color: #888;
-}
-</style>

+ 0 - 14
ui/src/config/api.ts

@@ -1,14 +0,0 @@
-// API 配置
-export const API_CONFIG = {
-  BASE_URL: import.meta.env.VITE_API_BASE || 'http://192.168.142.66:6060',
-  TIMEOUT: 15000,
-} as const
-
-export const API_ENDPOINTS = {
-  TASKS: '/api/tasks',
-  TASK_DETAIL: (id: number) => `/api/tasks/${id}`,
-  TASK_RETRY: (id: number) => `/api/tasks/${id}/retry`,
-  TASK_CANCEL: (id: number) => `/api/tasks/${id}/cancel`,
-  SAVE_TOKEN: '/api/save_token',
-  RUN_TASK: '/api/run_task',
-} as const

+ 0 - 28
ui/src/config/constants.ts

@@ -1,28 +0,0 @@
-export const TASK_STATUS = {
-  INIT: 0,
-  PROCESSING: 1,
-  COMPLETED: 2,
-  FAILED: 99,
-} as const
-
-export const TASK_STATUS_OPTIONS = [
-  { label: '初始化(0)', value: TASK_STATUS.INIT },
-  { label: '处理中(1)', value: TASK_STATUS.PROCESSING },
-  { label: '完成(2)', value: TASK_STATUS.COMPLETED },
-  { label: '失败(99)', value: TASK_STATUS.FAILED },
-]
-
-export const TASK_STATUS_TYPE_MAP: Record<number, string> = {
-  [TASK_STATUS.INIT]: 'info',
-  [TASK_STATUS.PROCESSING]: 'warning',
-  [TASK_STATUS.COMPLETED]: 'success',
-  [TASK_STATUS.FAILED]: 'danger',
-}
-
-export const PAGE_SIZES = [10, 20, 50, 100]
-
-export const DEFAULT_PAGE_SIZE = 20
-
-export const AUTO_REFRESH_INTERVAL = 5000
-
-export const MIN_TABLE_HEIGHT = 260

+ 0 - 177
ui/src/config/tasks.ts

@@ -1,177 +0,0 @@
-export interface TaskConfig {
-  name: string
-  desc: string
-  url: string
-  data: Record<string, any>
-}
-
-export const EXEC_PASSWORD = 'curry'
-
-export const AUTO_REFRESH_INTERVAL = 5000
-
-export const TASK_LIST: TaskConfig[] = [
-  {
-    name: '合作方账号 daily发文抓取',
-    desc: '抓取合作方的 daily 发文',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'cooperate_accounts_monitor' },
-  },
-  {
-    name: '合作方发文详情获取',
-    desc: '获取合作方发文的详情',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'cooperate_accounts_detail' },
-  },
-  {
-    name: '公众号抓取-手动挑号',
-    desc: '公众文章抓取-手动挑号',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: {
-      task_name: 'crawler_gzh_articles',
-      account_method: '1030-手动挑号',
-      crawl_mode: 'account',
-      strategy: 'V1',
-    },
-  },
-  {
-    name: '公众号抓取-合作账号',
-    desc: '公众文章抓取-合作挑号',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: {
-      task_name: 'crawler_gzh_articles',
-      account_method: 'cooperate_account',
-      crawl_mode: 'account',
-      strategy: 'V1',
-    },
-  },
-  {
-    name: '头条文章抓取',
-    desc: '头条推荐流文章专区',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'crawler_toutiao' },
-  },
-  {
-    name: '公众号文章冷启动(v1)',
-    desc: '文章路冷启动-策略 1',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'article_pool_cold_start', strategy: 'strategy_v1' },
-  },
-  {
-    name: '公众号文章冷启动(v3)',
-    desc: '文章路冷启动-策略 3',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'article_pool_cold_start', strategy: 'strategy_v3' },
-  },
-  {
-    name: '头条文章冷启动',
-    desc: '文章路冷启动-头条平台',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: {
-      task_name: 'article_pool_cold_start',
-      platform: 'toutiao',
-      crawler_methods: ['toutiao_account_association'],
-    },
-  },
-  {
-    name: '每日文章回收任务',
-    desc: 'daily_publish_articles_recycle',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'daily_publish_articles_recycle' },
-  },
-  {
-    name: 'root_source_id 更新',
-    desc: 'update_root_source_id',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'update_root_source_id' },
-  },
-  {
-    name: '视频下架任务',
-    desc: 'get_off_videos',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'get_off_videos' },
-  },
-  {
-    name: '内部文章监测',
-    desc: 'inner_article_monitor',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'inner_article_monitor' },
-  },
-  {
-    name: '关注公众号任务',
-    desc: 'follow_gzh_task',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'auto_follow_account' },
-  },
-  {
-    name: '获取自动回复结果',
-    desc: 'get_auto_reply_task',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'get_follow_result' },
-  },
-  {
-    name: '解析自动回复 xml',
-    desc: 'extract_task',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'extract_reply_result' },
-  },
-  {
-    name: '阅读率均值计算',
-    desc: 'update_account_read_rate_avg',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'update_account_read_rate_avg' },
-  },
-  {
-    name: '阅读均值计算',
-    desc: 'update_account_read_avg',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'update_account_read_avg' },
-  },
-  {
-    name: '打开率均值计算',
-    desc: 'update_account_open_rate_avg',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'update_account_open_rate_avg' },
-  },
-  {
-    name: '视频审核状态校验',
-    desc: 'check_publish_video_audit_status',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'check_publish_video_audit_status' },
-  },
-  {
-    name: 'kimi 余额校验',
-    desc: 'check_kimi_balance',
-    url: 'http://192.168.100.31:6060/api/run_task',
-    data: { task_name: 'check_kimi_balance' },
-  },
-  {
-    name: '小程序信息更新',
-    desc: 'mini_program_detail_process',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'mini_program_detail_process' },
-  },
-  {
-    name: '外部账号文章回收',
-    desc: 'recycle_outside_account_articles',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'recycle_outside_account_articles' },
-  },
-  {
-    name: '外部文章 RootID 更新',
-    desc: 'update_outside_account_article_root_source_id',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'update_outside_account_article_root_source_id' },
-  },
-  {
-    name: '限流文章分析',
-    desc: 'update_limited_account_info',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'update_limited_account_info' },
-  },
-  {
-    name: '候选账号质量分析',
-    desc: 'candidate_account_quality_analysis',
-    url: 'http://192.168.142.66:6060/api/run_task',
-    data: { task_name: 'candidate_account_quality_analysis' },
-  },
-]

+ 0 - 7
ui/src/main.ts

@@ -1,7 +0,0 @@
-import { createApp } from 'vue'
-import App from './App.vue'
-import router from './router'
-import ElementPlus from 'element-plus'
-import 'element-plus/dist/index.css'
-
-createApp(App).use(router).use(ElementPlus).mount('#app')

+ 0 - 16
ui/src/router/index.ts

@@ -1,16 +0,0 @@
-import { createRouter, createWebHistory } from 'vue-router'
-import TaskManager from '../views/TaskManager.vue'
-import TokenManager from '../views/TokenManager.vue'
-import Welcome from '../views/Welcome.vue'
-
-const router = createRouter({
-  history: createWebHistory(import.meta.env.BASE_URL),
-  routes: [
-      { path: '/', redirect: '/welcome' },
-      { path: '/welcome', name: 'Welcome', component: Welcome },
-      { path: '/tasks', name: 'TaskManager', component: TaskManager },
-      { path: '/token', name: 'TokenManager', component: TokenManager },
-  ],
-})
-
-export default router

+ 0 - 79
ui/src/style.css

@@ -1,79 +0,0 @@
-:root {
-  font-family: system-ui, Avenir, Helvetica, Arial, sans-serif;
-  line-height: 1.5;
-  font-weight: 400;
-
-  color-scheme: light dark;
-  color: rgba(255, 255, 255, 0.87);
-  background-color: #242424;
-
-  font-synthesis: none;
-  text-rendering: optimizeLegibility;
-  -webkit-font-smoothing: antialiased;
-  -moz-osx-font-smoothing: grayscale;
-}
-
-a {
-  font-weight: 500;
-  color: #646cff;
-  text-decoration: inherit;
-}
-a:hover {
-  color: #535bf2;
-}
-
-body {
-  margin: 0;
-  display: flex;
-  place-items: center;
-  min-width: 320px;
-  min-height: 100vh;
-}
-
-h1 {
-  font-size: 3.2em;
-  line-height: 1.1;
-}
-
-button {
-  border-radius: 8px;
-  border: 1px solid transparent;
-  padding: 0.6em 1.2em;
-  font-size: 1em;
-  font-weight: 500;
-  font-family: inherit;
-  background-color: #1a1a1a;
-  cursor: pointer;
-  transition: border-color 0.25s;
-}
-button:hover {
-  border-color: #646cff;
-}
-button:focus,
-button:focus-visible {
-  outline: 4px auto -webkit-focus-ring-color;
-}
-
-.card {
-  padding: 2em;
-}
-
-#app {
-  max-width: 1280px;
-  margin: 0 auto;
-  padding: 2rem;
-  text-align: center;
-}
-
-@media (prefers-color-scheme: light) {
-  :root {
-    color: #213547;
-    background-color: #ffffff;
-  }
-  a:hover {
-    color: #747bff;
-  }
-  button {
-    background-color: #f9f9f9;
-  }
-}

+ 0 - 383
ui/src/views/TaskManager.vue

@@ -1,383 +0,0 @@
-<template>
-  <div class="task-page">
-    <div class="top-bar">
-      <div class="left">
-        <el-button type="info" plain @click="goBack">返回首页</el-button>
-      </div>
-      <div class="title">任务列表</div>
-    </div>
-
-    <el-card class="task-card">
-      <div class="toolbar" ref="toolbarRef">
-        <el-form :inline="true" :model="filters" label-width="90px" @keyup.enter.native="onSearch">
-          <el-form-item label="ID">
-            <el-input v-model.number="filters.id" placeholder="精确 ID" clearable />
-          </el-form-item>
-          <el-form-item label="日期">
-            <el-date-picker
-              v-model="filters.date_string"
-              type="date"
-              value-format="YYYY-MM-DD"
-              placeholder="YYYY-MM-DD"
-              clearable
-            />
-          </el-form-item>
-          <el-form-item label="Trace ID">
-            <el-input v-model="filters.trace_id" placeholder="模糊匹配" clearable />
-          </el-form-item>
-          <el-form-item label="状态">
-            <el-select v-model="filters.task_status" placeholder="全部" clearable style="width: 160px">
-              <el-option v-for="s in statusOptions" :key="s.value" :label="s.label" :value="s.value" />
-            </el-select>
-          </el-form-item>
-          <el-form-item>
-            <el-button type="primary" @click="onSearch">查询</el-button>
-            <el-button @click="onReset">重置</el-button>
-          </el-form-item>
-          <el-form-item>
-            <el-switch v-model="autoRefresh" @change="toggleAutoRefresh" />
-            <span class="ml-8">自动刷新(5s)</span>
-          </el-form-item>
-        </el-form>
-      </div>
-
-      <div class="table-wrapper">
-        <el-table
-          :data="rows"
-          border
-          stripe
-          :height="tableHeight"
-          @sort-change="onSortChange"
-          class="custom-table"
-          v-loading="loading"
-          element-loading-text="加载中…"
-        >
-          <el-table-column prop="id" label="ID" sortable="custom" width="100" />
-          <el-table-column prop="date_string" label="日期" sortable="custom" width="140" />
-          <el-table-column prop="task_name" label="任务名称" min-width="200" :show-overflow-tooltip="true" />
-          <el-table-column prop="task_status" label="状态" sortable="custom" width="140">
-            <template #default="{ row }">
-              <el-tag :type="getStatusType(row.task_status)">
-                {{ row.status_text || row.task_status }}
-              </el-tag>
-            </template>
-          </el-table-column>
-          <el-table-column prop="start_timestamp" label="开始时间" sortable="custom" width="180">
-            <template #default="{ row }">{{ formatTimestamp(row.start_timestamp) }}</template>
-          </el-table-column>
-          <el-table-column prop="finish_timestamp" label="结束时间" sortable="custom" width="180">
-            <template #default="{ row }">{{ formatTimestamp(row.finish_timestamp) }}</template>
-          </el-table-column>
-          <el-table-column prop="trace_id" label="Trace ID" min-width="220" :show-overflow-tooltip="true" />
-          <el-table-column label="操作" fixed="right" width="240">
-            <template #default="{ row }">
-              <el-button size="small" @click="openDetail(row)">详情</el-button>
-              <el-button
-                size="small"
-                type="warning"
-                @click="onRetry(row)"
-                :disabled="row.task_status === TASK_STATUS.PROCESSING"
-              >
-                重试
-              </el-button>
-              <el-button
-                size="small"
-                type="danger"
-                @click="onCancel(row)"
-                :disabled="row.task_status === TASK_STATUS.COMPLETED"
-              >
-                取消
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-
-      <div class="pager" ref="pagerRef">
-        <el-pagination
-          background
-          layout="total, sizes, prev, pager, next, jumper"
-          :page-sizes="PAGE_SIZES"
-          :page-size="query.page_size"
-          :total="total"
-          :current-page="query.page"
-          @current-change="handlePageChange"
-          @size-change="handleSizeChange"
-        />
-      </div>
-    </el-card>
-
-    <el-drawer v-model="detailOpen" size="52%" title="任务详情">
-      <div class="detail">
-        <el-descriptions :column="2" border>
-          <el-descriptions-item label="ID">{{ detail?.id }}</el-descriptions-item>
-          <el-descriptions-item label="日期">{{ detail?.date_string }}</el-descriptions-item>
-          <el-descriptions-item label="状态">
-            {{ detail?.task_status }}({{ detail?.status_text }})
-          </el-descriptions-item>
-          <el-descriptions-item label="Trace ID">{{ detail?.trace_id }}</el-descriptions-item>
-          <el-descriptions-item label="开始">{{ formatTimestamp(detail?.start_timestamp) }}</el-descriptions-item>
-          <el-descriptions-item label="结束">{{ formatTimestamp(detail?.finish_timestamp) }}</el-descriptions-item>
-          <el-descriptions-item label="任务名" :span="2">{{ detail?.task_name }}</el-descriptions-item>
-        </el-descriptions>
-
-        <h4 class="block-title">请求参数(data)</h4>
-        <pre class="code-block">{{ formatJson(detail?.data_json || detail?.data) }}</pre>
-      </div>
-    </el-drawer>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { onMounted, onBeforeUnmount, reactive, ref, nextTick } from 'vue'
-import { useRouter } from 'vue-router'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import { fetchTasks, fetchTaskDetail, retryTask, cancelTask, type TaskItem } from '../api/task'
-import {
-  TASK_STATUS_OPTIONS,
-  TASK_STATUS_TYPE_MAP,
-  PAGE_SIZES,
-  DEFAULT_PAGE_SIZE,
-  AUTO_REFRESH_INTERVAL,
-  MIN_TABLE_HEIGHT,
-  TASK_STATUS,
-} from '../config/constants'
-
-const router = useRouter()
-
-const goBack = () => router.push('/welcome')
-
-const statusOptions = TASK_STATUS_OPTIONS
-
-interface Filters {
-  id: number | null
-  date_string: string | null
-  trace_id: string
-  task_status: number | null
-}
-
-const filters = reactive<Filters>({
-  id: null,
-  date_string: null,
-  trace_id: '',
-  task_status: null,
-})
-
-interface Query {
-  page: number
-  page_size: number
-  sort_by: string
-  sort_dir: 'asc' | 'desc'
-}
-
-const query = reactive<Query>({
-  page: 1,
-  page_size: DEFAULT_PAGE_SIZE,
-  sort_by: 'id',
-  sort_dir: 'desc',
-})
-
-const rows = ref<TaskItem[]>([])
-const total = ref(0)
-const loading = ref(false)
-
-let timer: ReturnType<typeof setInterval> | null = null
-const autoRefresh = ref(false)
-
-const toggleAutoRefresh = () => {
-  if (autoRefresh.value) {
-    timer = setInterval(load, AUTO_REFRESH_INTERVAL)
-  } else if (timer) {
-    clearInterval(timer)
-    timer = null
-  }
-}
-
-const toolbarRef = ref<HTMLElement | null>(null)
-const pagerRef = ref<HTMLElement | null>(null)
-const tableHeight = ref(400)
-
-const calcTableHeight = () => {
-  const winH = window.innerHeight
-  const toolbarH = toolbarRef.value?.offsetHeight ?? 0
-  const pagerH = pagerRef.value?.offsetHeight ?? 0
-  const outerPadding = 16 * 2
-  const cardPadding = 20 * 2
-  const gap = 12 + 12
-  tableHeight.value = Math.max(MIN_TABLE_HEIGHT, winH - (outerPadding + cardPadding + toolbarH + pagerH + gap))
-}
-
-const load = async () => {
-  loading.value = true
-  try {
-    const params: any = { ...query }
-    if (filters.id) params.id = filters.id
-    if (filters.date_string) params.date_string = filters.date_string
-    if (filters.trace_id) params.trace_id = filters.trace_id
-    if (filters.task_status !== null && filters.task_status !== undefined) {
-      params.task_status = filters.task_status
-    }
-
-    const resp = await fetchTasks(params)
-    rows.value = resp.items
-    total.value = resp.total
-    await nextTick()
-    calcTableHeight()
-  } finally {
-    loading.value = false
-  }
-}
-
-const onSearch = () => {
-  query.page = 1
-  load()
-}
-
-const onReset = () => {
-  Object.assign(filters, { id: null, date_string: null, trace_id: '', task_status: null })
-  query.page = 1
-  load()
-}
-
-const onSortChange = (e: any) => {
-  query.sort_by = e.prop || 'id'
-  query.sort_dir = e.order === 'ascending' ? 'asc' : 'desc'
-  load()
-}
-
-const handlePageChange = (page: number) => {
-  query.page = page
-  load()
-}
-
-const handleSizeChange = (size: number) => {
-  query.page_size = size
-  query.page = 1
-  load()
-}
-
-const getStatusType = (status: number): string => {
-  return TASK_STATUS_TYPE_MAP[status] || ''
-}
-
-const formatTimestamp = (ts?: number | null): string => {
-  if (!ts) return '-'
-  return new Date(ts * 1000).toLocaleString()
-}
-
-const formatJson = (value: any): string => {
-  try {
-    return typeof value === 'string' ? value : JSON.stringify(value, null, 2)
-  } catch {
-    return String(value)
-  }
-}
-
-const detailOpen = ref(false)
-const detail = ref<TaskItem | null>(null)
-
-const openDetail = async (row: TaskItem) => {
-  const d = await fetchTaskDetail(row.id)
-  detail.value = { ...row, ...d }
-  detailOpen.value = true
-}
-
-const onRetry = async (row: TaskItem) => {
-  await ElMessageBox.confirm(`确认将任务 #${row.id} 置为初始化并重试?`, '重试确认', { type: 'warning' })
-  await retryTask(row.id)
-  ElMessage.success('已触发重试')
-  load()
-}
-
-const onCancel = async (row: TaskItem) => {
-  await ElMessageBox.confirm(`确认取消任务 #${row.id}(置为失败)?`, '取消确认', { type: 'warning' })
-  await cancelTask(row.id)
-  ElMessage.success('已取消')
-  load()
-}
-
-onMounted(() => {
-  load()
-  window.addEventListener('resize', calcTableHeight)
-})
-
-onBeforeUnmount(() => {
-  window.removeEventListener('resize', calcTableHeight)
-  if (timer) clearInterval(timer)
-})
-</script>
-
-<style scoped>
-.task-page {
-  padding: 0;
-  background: linear-gradient(180deg, #f7f9fc, #edf1f6);
-  height: 100vh;
-  box-sizing: border-box;
-  display: flex;
-  flex-direction: column;
-}
-
-/* 顶部导航栏 */
-.top-bar {
-  display: flex;
-  align-items: center;
-  justify-content: space-between;
-  background: #fff;
-  padding: 12px 24px;
-  box-shadow: 0 2px 6px rgba(0, 0, 0, 0.05);
-  border-bottom: 1px solid #e6e8ef;
-}
-.top-bar .title {
-  font-weight: 600;
-  font-size: 18px;
-  color: #333;
-}
-
-/* 主体卡片 */
-.task-card {
-  flex: 1;
-  margin: 20px;
-  display: flex;
-  flex-direction: column;
-  box-shadow: 0 8px 20px rgba(0, 0, 0, 0.05);
-  border-radius: 12px;
-  overflow: hidden;
-}
-
-.toolbar {
-  margin-bottom: 12px;
-}
-.table-wrapper {
-  flex: 1;
-  overflow: hidden;
-}
-.custom-table {
-  border-radius: 8px;
-  overflow: hidden;
-}
-.pager {
-  display: flex;
-  justify-content: flex-end;
-  padding: 12px 0 0 0;
-  background: #fff;
-  border-top: 1px solid #f0f2f5;
-}
-.detail {
-  padding: 8px 0;
-}
-.block-title {
-  margin: 14px 0 8px;
-  font-weight: 600;
-}
-.code-block {
-  background: #0b1021;
-  color: #d1e7ff;
-  padding: 12px;
-  border-radius: 8px;
-  overflow: auto;
-  line-height: 1.5;
-}
-.ml-8 {
-  margin-left: 8px;
-}
-</style>

+ 0 - 134
ui/src/views/TokenManager.vue

@@ -1,134 +0,0 @@
-<template>
-  <div class="token-page">
-    <div class="top-bar">
-      <el-button type="info" plain @click="goBack">返回首页</el-button>
-    </div>
-
-    <el-card class="token-card">
-      <h2>更新 Token / Cookie</h2>
-
-      <el-form :model="form" label-width="100px">
-        <el-form-item label="gh_id">
-          <el-input v-model="form.gzh_id" placeholder="请输入公众号 ID" clearable />
-        </el-form-item>
-
-        <el-form-item label="Token">
-          <el-input v-model="form.token" placeholder="请输入 Token" clearable />
-        </el-form-item>
-
-        <el-form-item label="Cookie">
-          <el-input
-            v-model="form.cookie"
-            placeholder="请输入 Cookie"
-            type="textarea"
-            rows="4"
-            clearable
-          />
-        </el-form-item>
-
-        <el-form-item>
-          <el-button type="primary" @click="onSave" :loading="loading" style="width: 120px">
-            保存
-          </el-button>
-          <el-button @click="onReset" :disabled="loading" style="width: 120px">
-            重置
-          </el-button>
-        </el-form-item>
-      </el-form>
-    </el-card>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { ref } from 'vue'
-import { useRouter } from 'vue-router'
-import { ElMessage } from 'element-plus'
-import axios from 'axios'
-import { API_CONFIG, API_ENDPOINTS } from '../config/api'
-
-const router = useRouter()
-
-interface TokenForm {
-  gzh_id: string
-  token: string
-  cookie: string
-}
-
-const form = ref<TokenForm>({
-  gzh_id: '',
-  token: '',
-  cookie: '',
-})
-
-const loading = ref(false)
-
-const onSave = async () => {
-  if (!form.value.gzh_id || !form.value.token || !form.value.cookie) {
-    ElMessage.warning('请填写完整信息(gh_id / Token / Cookie)')
-    return
-  }
-
-  loading.value = true
-  try {
-    const res = await axios.post(`${API_CONFIG.BASE_URL}${API_ENDPOINTS.SAVE_TOKEN}`, {
-      gzh_id: form.value.gzh_id,
-      token: form.value.token,
-      cookie: form.value.cookie,
-    })
-
-    if (res.data?.success) {
-      ElMessage.success('更新成功')
-      form.value = { gzh_id: '', token: '', cookie: '' }
-    } else {
-      ElMessage.error(res.data?.error || '更新失败')
-    }
-  } catch (err) {
-    console.error('保存请求出错:', err)
-    ElMessage.error('请求异常,请稍后重试')
-  } finally {
-    loading.value = false
-  }
-}
-
-const onReset = () => {
-  form.value = { gzh_id: '', token: '', cookie: '' }
-}
-
-const goBack = () => {
-  router.push('/welcome')
-}
-</script>
-
-<style scoped>
-.token-page {
-  background: linear-gradient(180deg, #f6f8fb, #e8ecf3);
-  min-height: 100vh;
-  display: flex;
-  flex-direction: column;
-}
-
-.top-bar {
-  padding: 12px 16px;
-  background: #fff;
-  border-bottom: 1px solid #f0f2f5;
-  display: flex;
-  justify-content: flex-start;
-}
-
-.token-card {
-  width: 520px;
-  margin: 80px auto 0;
-  padding: 40px 30px 30px;
-  box-shadow: 0 8px 24px rgba(0, 0, 0, 0.06);
-  border-radius: 14px;
-  background: #fff;
-}
-
-h2 {
-  text-align: center;
-  font-size: 22px;
-  margin-bottom: 30px;
-  color: #333;
-  font-weight: 600;
-}
-</style>

+ 0 - 146
ui/src/views/Welcome.vue

@@ -1,146 +0,0 @@
-<template>
-  <div class="welcome-page">
-    <el-card class="welcome-card">
-      <h1>Welcome to <span class="highlight">俊辉's Work Agent</span></h1>
-      <p class="subtitle">高效、简洁地管理与执行任务。</p>
-
-      <div class="btn-group">
-        <el-button type="primary" size="large" @click="goTasks">查看任务列表</el-button>
-        <el-button type="success" size="large" @click="goToken">更新公众号 Token</el-button>
-      </div>
-
-      <div class="task-section">
-        <h2>定时任务管理器</h2>
-        <p class="desc">点击下方按钮可手动触发任务执行(需密码验证)</p>
-
-        <el-table :data="tasks" border stripe>
-          <el-table-column prop="name" label="任务名称" width="260" />
-          <el-table-column prop="desc" label="任务说明" />
-          <el-table-column prop="url" label="目标地址" width="280" show-overflow-tooltip />
-          <el-table-column label="操作" width="150" align="center">
-            <template #default="{ row }">
-              <el-button size="small" type="primary" @click="runTask(row)">
-                执行任务
-              </el-button>
-            </template>
-          </el-table-column>
-        </el-table>
-      </div>
-
-      <div class="footer">
-        <p>让每个任务都更清晰可控,助你轻松掌握全局。</p>
-      </div>
-    </el-card>
-  </div>
-</template>
-
-<script setup lang="ts">
-import { useRouter } from 'vue-router'
-import { ElMessage, ElMessageBox } from 'element-plus'
-import axios from 'axios'
-import { TASK_LIST, EXEC_PASSWORD, type TaskConfig } from '../config/tasks'
-
-const router = useRouter()
-const tasks = TASK_LIST
-
-const goTasks = () => router.push('/tasks')
-const goToken = () => router.push('/token')
-
-const runTask = async (task: TaskConfig) => {
-  try {
-    const input = await ElMessageBox.prompt('请输入执行密码以确认操作', '安全验证', {
-      confirmButtonText: '执行',
-      cancelButtonText: '取消',
-      inputType: 'password',
-      inputPlaceholder: '请输入密码',
-    })
-
-    if (input.value !== EXEC_PASSWORD) {
-      ElMessage.error('密码错误')
-      return
-    }
-
-    const res = await axios.post(task.url, task.data)
-    if (res.data?.success) {
-      ElMessage.success(`${task.name} 执行成功`)
-    } else {
-      ElMessage.success(`${task.name} 已触发`)
-    }
-  } catch (err: any) {
-    if (err === 'cancel') return
-    console.error(err)
-    ElMessage.error('任务执行失败')
-  }
-}
-</script>
-
-<style scoped>
-.welcome-page {
-  background: linear-gradient(180deg, #f5f8ff, #eef1f8);
-  height: 100vh;
-  display: flex;
-  justify-content: center;
-  align-items: flex-start;
-  padding-top: 40px;
-  overflow-y: auto;
-}
-
-.welcome-card {
-  text-align: center;
-  padding: 40px 60px;
-  border-radius: 18px;
-  box-shadow: 0 8px 26px rgba(0, 0, 0, 0.08);
-  background: #fff;
-  width: 90%;
-  max-width: 1300px;
-}
-
-h1 {
-  font-size: 30px;
-  font-weight: 700;
-  color: #333;
-  margin-bottom: 10px;
-}
-
-.highlight {
-  color: #2a76ff;
-}
-
-.subtitle {
-  color: #666;
-  font-size: 16px;
-  margin-bottom: 30px;
-}
-
-.btn-group {
-  display: flex;
-  justify-content: center;
-  gap: 24px;
-  margin-bottom: 40px;
-}
-
-.task-section {
-  text-align: left;
-  margin-top: 20px;
-}
-
-.task-section h2 {
-  font-size: 20px;
-  margin-bottom: 10px;
-  color: #333;
-}
-
-.task-section .desc {
-  color: #666;
-  font-size: 14px;
-  margin-bottom: 16px;
-}
-
-.footer {
-  margin-top: 40px;
-  font-size: 14px;
-  color: #888;
-  font-style: italic;
-  text-align: center;
-}
-</style>

+ 0 - 1
ui/src/vite-env.d.ts

@@ -1 +0,0 @@
-/// <reference types="vite/client" />

+ 0 - 15
ui/tsconfig.app.json

@@ -1,15 +0,0 @@
-{
-  "extends": "@vue/tsconfig/tsconfig.dom.json",
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.app.tsbuildinfo",
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.vue"]
-}

+ 0 - 7
ui/tsconfig.json

@@ -1,7 +0,0 @@
-{
-  "files": [],
-  "references": [
-    { "path": "./tsconfig.app.json" },
-    { "path": "./tsconfig.node.json" }
-  ]
-}

+ 0 - 25
ui/tsconfig.node.json

@@ -1,25 +0,0 @@
-{
-  "compilerOptions": {
-    "tsBuildInfoFile": "./node_modules/.tmp/tsconfig.node.tsbuildinfo",
-    "target": "ES2023",
-    "lib": ["ES2023"],
-    "module": "ESNext",
-    "skipLibCheck": true,
-
-    /* Bundler mode */
-    "moduleResolution": "bundler",
-    "allowImportingTsExtensions": true,
-    "verbatimModuleSyntax": true,
-    "moduleDetection": "force",
-    "noEmit": true,
-
-    /* Linting */
-    "strict": true,
-    "noUnusedLocals": true,
-    "noUnusedParameters": true,
-    "erasableSyntaxOnly": true,
-    "noFallthroughCasesInSwitch": true,
-    "noUncheckedSideEffectImports": true
-  },
-  "include": ["vite.config.ts"]
-}

+ 0 - 7
ui/vite.config.ts

@@ -1,7 +0,0 @@
-import { defineConfig } from 'vite'
-import vue from '@vitejs/plugin-vue'
-
-// https://vite.dev/config/
-export default defineConfig({
-  plugins: [vue()],
-})