Selaa lähdekoodia

chore: 初始化Vue项目基础结构

创建了项目所需的基础文件,包括入口HTML、Vue主应用组件、全局样式、Vite配置以及项目包管理文件,同时初始化了项目依赖目录结构。
Stclair 1 kuukausi sitten
sitoutus
356b36016c

+ 2 - 0
.gitignore

@@ -0,0 +1,2 @@
+node_modules/
+prompt/

+ 13 - 0
index.html

@@ -0,0 +1,13 @@
+<!DOCTYPE html>
+<html lang="zh-CN">
+  <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, maximum-scale=1.0, user-scalable=no">
+    <title>蜀道安全管理AI智能助手</title>
+  </head>
+  <body>
+    <div id="app"></div>
+    <script type="module" src="/src/main.js"></script>
+  </body>
+</html>

+ 1721 - 0
package-lock.json

@@ -0,0 +1,1721 @@
+{
+  "name": "shudao-safety-ai",
+  "version": "1.0.0",
+  "lockfileVersion": 3,
+  "requires": true,
+  "packages": {
+    "": {
+      "name": "shudao-safety-ai",
+      "version": "1.0.0",
+      "dependencies": {
+        "marked": "^11.1.1",
+        "pinia": "^2.1.7",
+        "vue": "^3.4.0",
+        "vue-router": "^4.2.5"
+      },
+      "devDependencies": {
+        "@vitejs/plugin-vue": "^5.0.0",
+        "sass": "^1.69.0",
+        "vite": "^5.0.0"
+      }
+    },
+    "node_modules/@babel/helper-string-parser": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmmirror.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz",
+      "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/helper-validator-identifier": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmmirror.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz",
+      "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==",
+      "license": "MIT",
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@babel/parser": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmmirror.com/@babel/parser/-/parser-7.29.7.tgz",
+      "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/types": "^7.29.7"
+      },
+      "bin": {
+        "parser": "bin/babel-parser.js"
+      },
+      "engines": {
+        "node": ">=6.0.0"
+      }
+    },
+    "node_modules/@babel/types": {
+      "version": "7.29.7",
+      "resolved": "https://registry.npmmirror.com/@babel/types/-/types-7.29.7.tgz",
+      "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/helper-string-parser": "^7.29.7",
+        "@babel/helper-validator-identifier": "^7.29.7"
+      },
+      "engines": {
+        "node": ">=6.9.0"
+      }
+    },
+    "node_modules/@esbuild/aix-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "aix"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz",
+      "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz",
+      "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/android-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz",
+      "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz",
+      "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/darwin-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz",
+      "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz",
+      "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/freebsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz",
+      "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz",
+      "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz",
+      "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz",
+      "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-loong64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz",
+      "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-mips64el": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz",
+      "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==",
+      "cpu": [
+        "mips64el"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-ppc64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz",
+      "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-riscv64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz",
+      "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-s390x": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz",
+      "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/linux-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz",
+      "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/netbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "netbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/openbsd-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz",
+      "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/sunos-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz",
+      "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "sunos"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-arm64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz",
+      "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-ia32": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz",
+      "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@esbuild/win32-x64": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz",
+      "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">=12"
+      }
+    },
+    "node_modules/@jridgewell/sourcemap-codec": {
+      "version": "1.5.5",
+      "resolved": "https://registry.npmmirror.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz",
+      "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==",
+      "license": "MIT"
+    },
+    "node_modules/@parcel/watcher": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher/-/watcher-2.5.6.tgz",
+      "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "detect-libc": "^2.0.3",
+        "is-glob": "^4.0.3",
+        "node-addon-api": "^7.0.0",
+        "picomatch": "^4.0.3"
+      },
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher-android-arm64": "2.5.6",
+        "@parcel/watcher-darwin-arm64": "2.5.6",
+        "@parcel/watcher-darwin-x64": "2.5.6",
+        "@parcel/watcher-freebsd-x64": "2.5.6",
+        "@parcel/watcher-linux-arm-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm-musl": "2.5.6",
+        "@parcel/watcher-linux-arm64-glibc": "2.5.6",
+        "@parcel/watcher-linux-arm64-musl": "2.5.6",
+        "@parcel/watcher-linux-x64-glibc": "2.5.6",
+        "@parcel/watcher-linux-x64-musl": "2.5.6",
+        "@parcel/watcher-win32-arm64": "2.5.6",
+        "@parcel/watcher-win32-ia32": "2.5.6",
+        "@parcel/watcher-win32-x64": "2.5.6"
+      }
+    },
+    "node_modules/@parcel/watcher-android-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz",
+      "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz",
+      "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-darwin-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz",
+      "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-freebsd-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz",
+      "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz",
+      "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz",
+      "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz",
+      "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-arm64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz",
+      "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-glibc": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz",
+      "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-linux-x64-musl": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz",
+      "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-arm64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz",
+      "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-ia32": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz",
+      "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@parcel/watcher-win32-x64": {
+      "version": "2.5.6",
+      "resolved": "https://registry.npmmirror.com/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz",
+      "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ],
+      "engines": {
+        "node": ">= 10.0.0"
+      },
+      "funding": {
+        "type": "opencollective",
+        "url": "https://opencollective.com/parcel"
+      }
+    },
+    "node_modules/@rollup/rollup-android-arm-eabi": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz",
+      "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-android-arm64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz",
+      "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "android"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-arm64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz",
+      "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-darwin-x64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz",
+      "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-arm64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz",
+      "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-freebsd-x64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz",
+      "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "freebsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-gnueabihf": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz",
+      "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm-musleabihf": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz",
+      "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==",
+      "cpu": [
+        "arm"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz",
+      "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-arm64-musl": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz",
+      "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz",
+      "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-loong64-musl": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz",
+      "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==",
+      "cpu": [
+        "loong64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz",
+      "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-ppc64-musl": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz",
+      "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==",
+      "cpu": [
+        "ppc64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz",
+      "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-riscv64-musl": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz",
+      "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==",
+      "cpu": [
+        "riscv64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-s390x-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz",
+      "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==",
+      "cpu": [
+        "s390x"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz",
+      "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-linux-x64-musl": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz",
+      "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "linux"
+      ]
+    },
+    "node_modules/@rollup/rollup-openbsd-x64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz",
+      "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openbsd"
+      ]
+    },
+    "node_modules/@rollup/rollup-openharmony-arm64": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz",
+      "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "openharmony"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-arm64-msvc": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz",
+      "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==",
+      "cpu": [
+        "arm64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-ia32-msvc": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz",
+      "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==",
+      "cpu": [
+        "ia32"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-gnu": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz",
+      "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@rollup/rollup-win32-x64-msvc": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz",
+      "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==",
+      "cpu": [
+        "x64"
+      ],
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "win32"
+      ]
+    },
+    "node_modules/@types/estree": {
+      "version": "1.0.9",
+      "resolved": "https://registry.npmmirror.com/@types/estree/-/estree-1.0.9.tgz",
+      "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/@vitejs/plugin-vue": {
+      "version": "5.2.4",
+      "resolved": "https://registry.npmmirror.com/@vitejs/plugin-vue/-/plugin-vue-5.2.4.tgz",
+      "integrity": "sha512-7Yx/SXSOcQq5HiiV3orevHUFn+pmMB4cgbEkDYgnkUWb0WfeQ/wa2yFv6D5ICiCQOVpjA7vYDXrC7AGO8yjDHA==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "peerDependencies": {
+        "vite": "^5.0.0 || ^6.0.0",
+        "vue": "^3.2.25"
+      }
+    },
+    "node_modules/@vue/compiler-core": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-core/-/compiler-core-3.5.35.tgz",
+      "integrity": "sha512-BUmHaR1J+O+CKZ9uJucdVTEr1LHsdyvv7vG3eNRhK3CczEHeMd/LtsHAuD7PbrxvI2envCY2v7HI1vC1aBRzKw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.3",
+        "@vue/shared": "3.5.35",
+        "entities": "^7.0.1",
+        "estree-walker": "^2.0.2",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-dom": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-dom/-/compiler-dom-3.5.35.tgz",
+      "integrity": "sha512-k+bprkXxuqhVajgTx5mUHuir7TwQzUKOWR40ng1ncAqQRPnrLngGGgqVEEhOnTMlc8btHYVKmrP8s5Qyg0hvYA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-core": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/compiler-sfc": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-sfc/-/compiler-sfc-3.5.35.tgz",
+      "integrity": "sha512-G5VPMcXTSywXBgtFOZOnHKBxKSrwXUcvY1iaF5/hRcy7t0J6CH/d8ha9F4nzi00Fax1eLV0QHM7v4mQu68jydw==",
+      "license": "MIT",
+      "dependencies": {
+        "@babel/parser": "^7.29.3",
+        "@vue/compiler-core": "3.5.35",
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/compiler-ssr": "3.5.35",
+        "@vue/shared": "3.5.35",
+        "estree-walker": "^2.0.2",
+        "magic-string": "^0.30.21",
+        "postcss": "^8.5.15",
+        "source-map-js": "^1.2.1"
+      }
+    },
+    "node_modules/@vue/compiler-ssr": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/compiler-ssr/-/compiler-ssr-3.5.35.tgz",
+      "integrity": "sha512-rGhAeXgdM7/ffTJGXT69rCCdTmjDewnFuUZfBQQHTdcEBeWdT5HCGY60y2ytLJr9/Dsu7IntUi5z/w0h6Rjnzw==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/devtools-api": {
+      "version": "6.6.4",
+      "resolved": "https://registry.npmmirror.com/@vue/devtools-api/-/devtools-api-6.6.4.tgz",
+      "integrity": "sha512-sGhTPMuXqZ1rVOk32RylztWkfXTRhuS7vgAKv0zjqk8gbsHkJ7xfFf+jbySxt7tWObEJwyKaHMikV/WGDiQm8g==",
+      "license": "MIT"
+    },
+    "node_modules/@vue/reactivity": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/reactivity/-/reactivity-3.5.35.tgz",
+      "integrity": "sha512-tVc+SsHConvh/Lz64qq1pP3rYArBmK42xonovEcxY74SQtvctZodG/zhq54P5dr38cVuw25d27cPNRdlMidpGQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/runtime-core": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/runtime-core/-/runtime-core-3.5.35.tgz",
+      "integrity": "sha512-A/xFNX9loIcWDygeQuNCfKuh0CoYBzxhqEMNah5TSFg9Z53DrFYEN2qi5CU9necjM1OWYegYREUTHmXTmhfXtg==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.35",
+        "@vue/shared": "3.5.35"
+      }
+    },
+    "node_modules/@vue/runtime-dom": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/runtime-dom/-/runtime-dom-3.5.35.tgz",
+      "integrity": "sha512-odrJ1C391dbGnyDRh8U+rnP7J2amIEzfmRk5vXy7xi3aZhEXofTvpi0T4HJb6jlNqQZTNPR5MPHSB3RHNkIORA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/reactivity": "3.5.35",
+        "@vue/runtime-core": "3.5.35",
+        "@vue/shared": "3.5.35",
+        "csstype": "^3.2.3"
+      }
+    },
+    "node_modules/@vue/server-renderer": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/server-renderer/-/server-renderer-3.5.35.tgz",
+      "integrity": "sha512-NkebSOYdB97wi8OQcO3HqzZSlymJi/aWsN/7h74OSVhRTm6qGs3Jp3e0rCXynmWwSlKeRrnlIug+ilYoHBmQDA==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/compiler-ssr": "3.5.35",
+        "@vue/shared": "3.5.35"
+      },
+      "peerDependencies": {
+        "vue": "3.5.35"
+      }
+    },
+    "node_modules/@vue/shared": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/@vue/shared/-/shared-3.5.35.tgz",
+      "integrity": "sha512-zSbjL7gRXwks2ZQLRGCajBtBXEOXW9Ddhn/HvSdrGkE2dqGnumzW8XtusRrxrE9LvqtiqDXQ+A60Hp6mvdYxfA==",
+      "license": "MIT"
+    },
+    "node_modules/chokidar": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/chokidar/-/chokidar-5.0.0.tgz",
+      "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "readdirp": "^5.0.0"
+      },
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/csstype": {
+      "version": "3.2.3",
+      "resolved": "https://registry.npmmirror.com/csstype/-/csstype-3.2.3.tgz",
+      "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
+      "license": "MIT"
+    },
+    "node_modules/detect-libc": {
+      "version": "2.1.2",
+      "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.1.2.tgz",
+      "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==",
+      "dev": true,
+      "license": "Apache-2.0",
+      "optional": true,
+      "engines": {
+        "node": ">=8"
+      }
+    },
+    "node_modules/entities": {
+      "version": "7.0.1",
+      "resolved": "https://registry.npmmirror.com/entities/-/entities-7.0.1.tgz",
+      "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==",
+      "license": "BSD-2-Clause",
+      "engines": {
+        "node": ">=0.12"
+      },
+      "funding": {
+        "url": "https://github.com/fb55/entities?sponsor=1"
+      }
+    },
+    "node_modules/esbuild": {
+      "version": "0.21.5",
+      "resolved": "https://registry.npmmirror.com/esbuild/-/esbuild-0.21.5.tgz",
+      "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "bin": {
+        "esbuild": "bin/esbuild"
+      },
+      "engines": {
+        "node": ">=12"
+      },
+      "optionalDependencies": {
+        "@esbuild/aix-ppc64": "0.21.5",
+        "@esbuild/android-arm": "0.21.5",
+        "@esbuild/android-arm64": "0.21.5",
+        "@esbuild/android-x64": "0.21.5",
+        "@esbuild/darwin-arm64": "0.21.5",
+        "@esbuild/darwin-x64": "0.21.5",
+        "@esbuild/freebsd-arm64": "0.21.5",
+        "@esbuild/freebsd-x64": "0.21.5",
+        "@esbuild/linux-arm": "0.21.5",
+        "@esbuild/linux-arm64": "0.21.5",
+        "@esbuild/linux-ia32": "0.21.5",
+        "@esbuild/linux-loong64": "0.21.5",
+        "@esbuild/linux-mips64el": "0.21.5",
+        "@esbuild/linux-ppc64": "0.21.5",
+        "@esbuild/linux-riscv64": "0.21.5",
+        "@esbuild/linux-s390x": "0.21.5",
+        "@esbuild/linux-x64": "0.21.5",
+        "@esbuild/netbsd-x64": "0.21.5",
+        "@esbuild/openbsd-x64": "0.21.5",
+        "@esbuild/sunos-x64": "0.21.5",
+        "@esbuild/win32-arm64": "0.21.5",
+        "@esbuild/win32-ia32": "0.21.5",
+        "@esbuild/win32-x64": "0.21.5"
+      }
+    },
+    "node_modules/estree-walker": {
+      "version": "2.0.2",
+      "resolved": "https://registry.npmmirror.com/estree-walker/-/estree-walker-2.0.2.tgz",
+      "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
+      "license": "MIT"
+    },
+    "node_modules/fsevents": {
+      "version": "2.3.3",
+      "resolved": "https://registry.npmmirror.com/fsevents/-/fsevents-2.3.3.tgz",
+      "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+      "dev": true,
+      "hasInstallScript": true,
+      "license": "MIT",
+      "optional": true,
+      "os": [
+        "darwin"
+      ],
+      "engines": {
+        "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+      }
+    },
+    "node_modules/immutable": {
+      "version": "5.1.6",
+      "resolved": "https://registry.npmmirror.com/immutable/-/immutable-5.1.6.tgz",
+      "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==",
+      "dev": true,
+      "license": "MIT"
+    },
+    "node_modules/is-extglob": {
+      "version": "2.1.1",
+      "resolved": "https://registry.npmmirror.com/is-extglob/-/is-extglob-2.1.1.tgz",
+      "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/is-glob": {
+      "version": "4.0.3",
+      "resolved": "https://registry.npmmirror.com/is-glob/-/is-glob-4.0.3.tgz",
+      "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "dependencies": {
+        "is-extglob": "^2.1.1"
+      },
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/magic-string": {
+      "version": "0.30.21",
+      "resolved": "https://registry.npmmirror.com/magic-string/-/magic-string-0.30.21.tgz",
+      "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
+      "license": "MIT",
+      "dependencies": {
+        "@jridgewell/sourcemap-codec": "^1.5.5"
+      }
+    },
+    "node_modules/marked": {
+      "version": "11.2.0",
+      "resolved": "https://registry.npmmirror.com/marked/-/marked-11.2.0.tgz",
+      "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==",
+      "license": "MIT",
+      "bin": {
+        "marked": "bin/marked.js"
+      },
+      "engines": {
+        "node": ">= 18"
+      }
+    },
+    "node_modules/nanoid": {
+      "version": "3.3.12",
+      "resolved": "https://registry.npmmirror.com/nanoid/-/nanoid-3.3.12.tgz",
+      "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==",
+      "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/node-addon-api": {
+      "version": "7.1.1",
+      "resolved": "https://registry.npmmirror.com/node-addon-api/-/node-addon-api-7.1.1.tgz",
+      "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true
+    },
+    "node_modules/picocolors": {
+      "version": "1.1.1",
+      "resolved": "https://registry.npmmirror.com/picocolors/-/picocolors-1.1.1.tgz",
+      "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
+      "license": "ISC"
+    },
+    "node_modules/picomatch": {
+      "version": "4.0.4",
+      "resolved": "https://registry.npmmirror.com/picomatch/-/picomatch-4.0.4.tgz",
+      "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
+      "dev": true,
+      "license": "MIT",
+      "optional": true,
+      "engines": {
+        "node": ">=12"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/jonschlinkert"
+      }
+    },
+    "node_modules/pinia": {
+      "version": "2.3.1",
+      "resolved": "https://registry.npmmirror.com/pinia/-/pinia-2.3.1.tgz",
+      "integrity": "sha512-khUlZSwt9xXCaTbbxFYBKDc/bWAGWJjOgvxETwkTN7KRm66EeT1ZdZj6i2ceh9sP2Pzqsbc704r2yngBrxBVug==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-api": "^6.6.3",
+        "vue-demi": "^0.14.10"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "typescript": ">=4.4.4",
+        "vue": "^2.7.0 || ^3.5.11"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/postcss": {
+      "version": "8.5.15",
+      "resolved": "https://registry.npmmirror.com/postcss/-/postcss-8.5.15.tgz",
+      "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==",
+      "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.12",
+        "picocolors": "^1.1.1",
+        "source-map-js": "^1.2.1"
+      },
+      "engines": {
+        "node": "^10 || ^12 || >=14"
+      }
+    },
+    "node_modules/readdirp": {
+      "version": "5.0.0",
+      "resolved": "https://registry.npmmirror.com/readdirp/-/readdirp-5.0.0.tgz",
+      "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==",
+      "dev": true,
+      "license": "MIT",
+      "engines": {
+        "node": ">= 20.19.0"
+      },
+      "funding": {
+        "type": "individual",
+        "url": "https://paulmillr.com/funding/"
+      }
+    },
+    "node_modules/rollup": {
+      "version": "4.61.1",
+      "resolved": "https://registry.npmmirror.com/rollup/-/rollup-4.61.1.tgz",
+      "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==",
+      "dev": true,
+      "license": "MIT",
+      "dependencies": {
+        "@types/estree": "1.0.9"
+      },
+      "bin": {
+        "rollup": "dist/bin/rollup"
+      },
+      "engines": {
+        "node": ">=18.0.0",
+        "npm": ">=8.0.0"
+      },
+      "optionalDependencies": {
+        "@rollup/rollup-android-arm-eabi": "4.61.1",
+        "@rollup/rollup-android-arm64": "4.61.1",
+        "@rollup/rollup-darwin-arm64": "4.61.1",
+        "@rollup/rollup-darwin-x64": "4.61.1",
+        "@rollup/rollup-freebsd-arm64": "4.61.1",
+        "@rollup/rollup-freebsd-x64": "4.61.1",
+        "@rollup/rollup-linux-arm-gnueabihf": "4.61.1",
+        "@rollup/rollup-linux-arm-musleabihf": "4.61.1",
+        "@rollup/rollup-linux-arm64-gnu": "4.61.1",
+        "@rollup/rollup-linux-arm64-musl": "4.61.1",
+        "@rollup/rollup-linux-loong64-gnu": "4.61.1",
+        "@rollup/rollup-linux-loong64-musl": "4.61.1",
+        "@rollup/rollup-linux-ppc64-gnu": "4.61.1",
+        "@rollup/rollup-linux-ppc64-musl": "4.61.1",
+        "@rollup/rollup-linux-riscv64-gnu": "4.61.1",
+        "@rollup/rollup-linux-riscv64-musl": "4.61.1",
+        "@rollup/rollup-linux-s390x-gnu": "4.61.1",
+        "@rollup/rollup-linux-x64-gnu": "4.61.1",
+        "@rollup/rollup-linux-x64-musl": "4.61.1",
+        "@rollup/rollup-openbsd-x64": "4.61.1",
+        "@rollup/rollup-openharmony-arm64": "4.61.1",
+        "@rollup/rollup-win32-arm64-msvc": "4.61.1",
+        "@rollup/rollup-win32-ia32-msvc": "4.61.1",
+        "@rollup/rollup-win32-x64-gnu": "4.61.1",
+        "@rollup/rollup-win32-x64-msvc": "4.61.1",
+        "fsevents": "~2.3.2"
+      }
+    },
+    "node_modules/sass": {
+      "version": "1.100.0",
+      "resolved": "https://registry.npmmirror.com/sass/-/sass-1.100.0.tgz",
+      "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "chokidar": "^5.0.0",
+        "immutable": "^5.1.5",
+        "source-map-js": ">=0.6.2 <2.0.0"
+      },
+      "bin": {
+        "sass": "sass.js"
+      },
+      "engines": {
+        "node": ">=20.19.0"
+      },
+      "optionalDependencies": {
+        "@parcel/watcher": "^2.4.1"
+      }
+    },
+    "node_modules/source-map-js": {
+      "version": "1.2.1",
+      "resolved": "https://registry.npmmirror.com/source-map-js/-/source-map-js-1.2.1.tgz",
+      "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
+      "license": "BSD-3-Clause",
+      "engines": {
+        "node": ">=0.10.0"
+      }
+    },
+    "node_modules/vite": {
+      "version": "5.4.21",
+      "resolved": "https://registry.npmmirror.com/vite/-/vite-5.4.21.tgz",
+      "integrity": "sha512-o5a9xKjbtuhY6Bi5S3+HvbRERmouabWbyUcpXXUA1u+GNUKoROi9byOJ8M0nHbHYHkYICiMlqxkg1KkYmm25Sw==",
+      "dev": true,
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "esbuild": "^0.21.3",
+        "postcss": "^8.4.43",
+        "rollup": "^4.20.0"
+      },
+      "bin": {
+        "vite": "bin/vite.js"
+      },
+      "engines": {
+        "node": "^18.0.0 || >=20.0.0"
+      },
+      "funding": {
+        "url": "https://github.com/vitejs/vite?sponsor=1"
+      },
+      "optionalDependencies": {
+        "fsevents": "~2.3.3"
+      },
+      "peerDependencies": {
+        "@types/node": "^18.0.0 || >=20.0.0",
+        "less": "*",
+        "lightningcss": "^1.21.0",
+        "sass": "*",
+        "sass-embedded": "*",
+        "stylus": "*",
+        "sugarss": "*",
+        "terser": "^5.4.0"
+      },
+      "peerDependenciesMeta": {
+        "@types/node": {
+          "optional": true
+        },
+        "less": {
+          "optional": true
+        },
+        "lightningcss": {
+          "optional": true
+        },
+        "sass": {
+          "optional": true
+        },
+        "sass-embedded": {
+          "optional": true
+        },
+        "stylus": {
+          "optional": true
+        },
+        "sugarss": {
+          "optional": true
+        },
+        "terser": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue": {
+      "version": "3.5.35",
+      "resolved": "https://registry.npmmirror.com/vue/-/vue-3.5.35.tgz",
+      "integrity": "sha512-cx89fnr+0kVGHiNFG6y6s0bdjypJRFNZn6x3WPstNdQR1bi1mbB7h4v5IBGTsPJU3nK1+0Iqj3Zf+hZWMieR4Q==",
+      "license": "MIT",
+      "peer": true,
+      "dependencies": {
+        "@vue/compiler-dom": "3.5.35",
+        "@vue/compiler-sfc": "3.5.35",
+        "@vue/runtime-dom": "3.5.35",
+        "@vue/server-renderer": "3.5.35",
+        "@vue/shared": "3.5.35"
+      },
+      "peerDependencies": {
+        "typescript": "*"
+      },
+      "peerDependenciesMeta": {
+        "typescript": {
+          "optional": true
+        }
+      }
+    },
+    "node_modules/vue-demi": {
+      "version": "0.14.10",
+      "resolved": "https://registry.npmmirror.com/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/vue-router": {
+      "version": "4.6.4",
+      "resolved": "https://registry.npmmirror.com/vue-router/-/vue-router-4.6.4.tgz",
+      "integrity": "sha512-Hz9q5sa33Yhduglwz6g9skT8OBPii+4bFn88w6J+J4MfEo4KRRpmiNG/hHHkdbRFlLBOqxN8y8gf2Fb0MTUgVg==",
+      "license": "MIT",
+      "dependencies": {
+        "@vue/devtools-api": "^6.6.4"
+      },
+      "funding": {
+        "url": "https://github.com/sponsors/posva"
+      },
+      "peerDependencies": {
+        "vue": "^3.5.0"
+      }
+    }
+  }
+}

+ 22 - 0
package.json

@@ -0,0 +1,22 @@
+{
+  "name": "shudao-safety-ai",
+  "private": true,
+  "version": "1.0.0",
+  "type": "module",
+  "scripts": {
+    "dev": "vite",
+    "build": "vite build",
+    "preview": "vite preview"
+  },
+  "dependencies": {
+    "vue": "^3.4.0",
+    "vue-router": "^4.2.5",
+    "pinia": "^2.1.7",
+    "marked": "^11.1.1"
+  },
+  "devDependencies": {
+    "@vitejs/plugin-vue": "^5.0.0",
+    "vite": "^5.0.0",
+    "sass": "^1.69.0"
+  }
+}

+ 4 - 0
public/vite.svg

@@ -0,0 +1,4 @@
+<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32" viewBox="0 0 32 32">
+  <rect width="32" height="32" fill="#1890ff" rx="4"/>
+  <text x="16" y="21" font-family="Arial" font-size="16" fill="white" text-anchor="middle">AI</text>
+</svg>

+ 26 - 0
src/App.vue

@@ -0,0 +1,26 @@
+<template>
+  <div class="app">
+    <Sidebar />
+    <main class="main-content">
+      <router-view />
+    </main>
+  </div>
+</template>
+
+<script setup>
+import Sidebar from '@/components/Sidebar.vue'
+</script>
+
+<style scoped>
+.app {
+  display: flex;
+  height: 100vh;
+  width: 100vw;
+  overflow: hidden;
+}
+
+.main-content {
+  flex: 1;
+  overflow: hidden;
+}
+</style>

BIN
src/assets/logo.jpg


+ 20 - 0
src/assets/styles/global.scss

@@ -0,0 +1,20 @@
+* {
+  margin: 0;
+  padding: 0;
+  box-sizing: border-box;
+}
+
+html, body {
+  width: 100%;
+  height: 100%;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'PingFang SC', 'Hiragino Sans GB',
+    'Microsoft YaHei', 'Helvetica Neue', Helvetica, Arial, sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  background-color: #f5f5f5;
+}
+
+#app {
+  width: 100%;
+  height: 100%;
+}

+ 84 - 0
src/components/Sidebar.vue

@@ -0,0 +1,84 @@
+<template>
+  <div class="sidebar">
+    <div class="logo-section">
+      <img src="@/assets/logo.jpg" alt="logo" class="logo-image">
+    </div>
+    <nav class="nav-menu">
+      <router-link 
+        v-for="item in navItems" 
+        :key="item.path"
+        :to="item.path"
+        class="nav-item"
+        :class="{ active: $route.path === item.path }"
+      >
+        <span class="nav-icon">{{ item.icon }}</span>
+        <span class="nav-text">{{ item.text }}</span>
+      </router-link>
+    </nav>
+  </div>
+</template>
+
+<script setup>
+const navItems = [
+  { path: '/chat', icon: '🤖', text: 'AI助手' },
+  { path: '/hazard', icon: '🔍', text: '隐患检测' },
+  { path: '/exam', icon: '📝', text: '模拟考试' },
+  { path: '/knowledge', icon: '📚', text: '知识库' }
+]
+</script>
+
+<style scoped lang="scss">
+.sidebar {
+  width: 220px;
+  background: #fff;
+  border-right: 1px solid #e8e8e8;
+  display: flex;
+  flex-direction: column;
+  padding: 16px 0;
+}
+
+.logo-section {
+  padding: 0 16px 24px;
+  text-align: center;
+
+  .logo-image {
+    width: 120px;
+    height: auto;
+  }
+}
+
+.nav-menu {
+  flex: 1;
+}
+
+.nav-item {
+  display: flex;
+  align-items: center;
+  padding: 12px 24px;
+  margin: 4px 8px;
+  border-radius: 8px;
+  cursor: pointer;
+  text-decoration: none;
+  color: #666;
+  transition: all 0.2s;
+
+  &:hover {
+    background: #f0f5ff;
+    color: #1890ff;
+  }
+
+  &.active {
+    background: #1890ff;
+    color: #fff;
+  }
+
+  .nav-icon {
+    font-size: 18px;
+    margin-right: 10px;
+  }
+
+  .nav-text {
+    font-size: 14px;
+  }
+}
+</style>

+ 10 - 0
src/main.js

@@ -0,0 +1,10 @@
+import { createApp } from 'vue'
+import { createPinia } from 'pinia'
+import router from './router'
+import App from './App.vue'
+import './assets/styles/global.scss'
+
+const app = createApp(App)
+app.use(createPinia())
+app.use(router)
+app.mount('#app')

+ 204 - 0
src/mock/chatMock.js

@@ -0,0 +1,204 @@
+// 聊天MOCK数据
+const quickQuestions = [
+  '施工现场安全规范要求有哪些?',
+  '如何进行高处作业安全防护?',
+  '施工现场临时用电注意事项',
+  '特种作业人员管理要求',
+  '脚手架搭设规范是什么?',
+  '施工现场消防管理要点'
+]
+
+const qaDatabase = [
+  {
+    keywords: ['安全规范', '规范要求', '安全要求'],
+    response: `## 施工现场安全规范要求
+
+施工现场安全管理涉及多个方面,主要包括:
+
+### 1. 人员管理
+- 所有进场人员必须进行三级安全教育
+- 特种作业人员必须持证上岗
+- 定期组织安全培训和应急演练
+
+### 2. 设备管理
+- 所有机械设备必须经过验收合格后方可使用
+- 特种设备必须定期检验
+- 建立设备运行维护台账
+
+### 3. 现场管理
+- 设置明显的安全警示标志
+- 保持施工通道畅通
+- 材料堆放规范整齐
+- 做好文明施工管理
+
+### 4. 防护设施
+- 高处作业必须系挂安全带
+- 临边洞口设置防护栏杆
+- 脚手架必须经验收合格后使用`
+  },
+  {
+    keywords: ['高处作业', '高空作业', '高处安全'],
+    response: `## 高处作业安全防护要求
+
+根据\`GB/T 3608-2008\`规定,高处作业是指距坠落高度基准面**2m及以上**的作业。
+
+### 防护措施
+
+1. **个人防护**
+   - 必须正确佩戴安全帽
+   - 使用合格的安全带,高挂低用
+   - 穿防滑鞋
+
+2. **作业平台**
+   - 脚手架必须验收合格
+   - 操作平台设置防护栏杆(1.2m)
+   - 铺设牢固的脚手板
+
+3. **环境要求**
+   - 六级以上大风禁止作业
+   - 雨雪天气停止露天高处作业
+   - 夜间作业需充足照明
+
+4. **管理要求**
+   - 办理高处作业许可证
+   - 设专人监护
+   - 严禁上下交叉作业`
+  },
+  {
+    keywords: ['用电', '临时用电', '电气安全'],
+    response: `## 施工现场临时用电安全要点
+
+### 基本原则
+- 采用**TN-S接零保护系统**
+- 实行**三级配电两级保护**
+- 做到**一机一闸一漏一箱**
+
+### 具体要求
+
+1. **配电箱管理**
+   - 总配电箱、分配电箱、开关箱分级设置
+   - 漏电保护器动作电流不大于30mA
+   - 潮湿环境使用防溅型漏保(15mA)
+
+2. **电缆敷设**
+   - 采用五芯电缆
+   - 不得沿地面明敷
+   - 过路需穿管保护
+
+3. **电气设备**
+   - 金属外壳必须接零保护
+   - 定期检测绝缘电阻
+   - 电工必须持证上岗`
+  },
+  {
+    keywords: ['脚手架', '脚手架搭设'],
+    response: `## 脚手架搭设规范要点
+
+### 基本要求
+1. **搭设人员**
+   - 必须持有特种作业操作证
+   - 经过专项安全技术交底
+
+2. **材料要求**
+   - 钢管规格:Φ48.3×3.6mm
+   - 扣件必须有产品合格证
+   - 脚手板厚度不小于50mm
+
+3. **构造要求**
+   - 立杆纵距≤1.5m,横距≤1.2m
+   - 步距≤1.8m
+   - 必须设置剪刀撑和连墙件
+
+4. **验收要求**
+   - 分段搭设分段验收
+   - 验收合格挂牌后方可使用
+   - 使用过程中定期检查
+
+### 安全注意事项
+- 严禁超载使用
+- 严禁擅自拆除杆件
+- 拆除时必须设置警戒区`
+  },
+  {
+    keywords: ['消防', '防火', '消防安全'],
+    response: `## 施工现场消防管理要点
+
+### 1. 组织管理
+- 建立消防安全责任制
+- 制定消防应急预案
+- 定期组织消防演练
+
+### 2. 消防设施
+- 按规定配置灭火器
+- 设置消防水源和消防通道
+- 高层建筑设置临时消防给水系统
+
+### 3. 动火管理
+- 严格执行动火审批制度
+- 动火作业前清除可燃物
+- 配备灭火器材,设专人监护
+
+### 4. 重点部位
+- 易燃易爆物品单独存放
+- 焊接作业远离易燃物
+- 宿舍严禁使用大功率电器
+
+### 5. 疏散通道
+- 保持疏散通道畅通
+- 设置应急照明和疏散指示标志
+- 严禁占用消防通道`
+  },
+  {
+    keywords: ['特种作业', '特种人员', '持证'],
+    response: `## 特种作业人员管理要求
+
+### 特种作业范围
+1. 电工作业
+2. 焊接与热切割作业
+3. 高处作业
+4. 制冷与空调作业
+5. 起重机械作业
+6. 建筑架子工
+7. 其他特种作业
+
+### 管理要求
+
+**1. 资质管理**
+- 必须经专门的安全技术培训
+- 考核合格取得特种作业操作证
+- 证书有效期6年,每3年复审一次
+
+**2. 现场管理**
+- 持证上岗,随身携带操作证
+- 不得超范围作业
+- 按规定佩戴劳动防护用品
+
+**3. 企业责任**
+- 建立特种作业人员档案
+- 定期组织安全教育培训
+- 监督检查作业行为`
+  }
+]
+
+const defaultResponse = `感谢您的提问。基于您的问题,我为您提供以下分析:
+
+根据相关安全管理规范,建议您:
+
+1. **查阅相关文件** - 参考国家安全生产法律法规及行业标准
+2. **落实安全措施** - 严格执行安全操作规程
+3. **加强培训教育** - 提高全员安全意识
+4. **做好监督检查** - 定期开展安全隐患排查
+
+如需更详细的解答,请补充具体问题细节,或等待知识库服务恢复后获取结合文档的完整结果。`
+
+export const getQuickQuestions = () => quickQuestions
+
+export const getMockResponse = (question) => {
+  const q = question.toLowerCase()
+  for (const item of qaDatabase) {
+    if (item.keywords.some(k => q.includes(k))) {
+      return item.response
+    }
+  }
+  return defaultResponse
+}

+ 92 - 0
src/mock/examMock.js

@@ -0,0 +1,92 @@
+// 考试MOCK数据
+const questionBank = [
+  {
+    question: '根据《安全生产法》,生产经营单位的主要负责人对本单位安全生产工作负有什么职责?',
+    type: '单选题',
+    options: [
+      '全面负责',
+      '部分负责',
+      '监督检查',
+      '技术指导'
+    ],
+    answer: 0
+  },
+  {
+    question: '高处作业是指在坠落高度基准面( )及以上有可能坠落的高处进行的作业。',
+    type: '单选题',
+    options: ['1m', '2m', '3m', '5m'],
+    answer: 1
+  },
+  {
+    question: '施工现场临时用电应采用( )系统。',
+    type: '单选题',
+    options: ['TN-C', 'TN-S', 'TT', 'IT'],
+    answer: 1
+  },
+  {
+    question: '以下哪些属于特种作业?(多选)',
+    type: '多选题',
+    options: ['电工作业', '焊接作业', '高处作业', '普通搬运'],
+    answer: null // 简化处理,MOCK答案为0,1,2
+  },
+  {
+    question: '脚手架搭设必须编制专项施工方案,高度超过( )m的落地式脚手架需要进行专家论证。',
+    type: '单选题',
+    options: ['24', '30', '50', '100'],
+    answer: 2
+  },
+  {
+    question: '灭火器压力表指针在( )区域表示压力正常。',
+    type: '单选题',
+    options: ['红色', '黄色', '绿色', '蓝色'],
+    answer: 2
+  },
+  {
+    question: '安全生产三级教育是指( )。',
+    type: '单选题',
+    options: [
+      '公司级、项目级、班组级',
+      '国家级、省级、市级',
+      '理论级、实践级、考核级',
+      '初级、中级、高级'
+    ],
+    answer: 0
+  },
+  {
+    question: '施工现场的"四口"防护是指( )。',
+    type: '多选题',
+    options: [
+      '楼梯口',
+      '电梯井口',
+      '预留洞口',
+      '通道口'
+    ],
+    answer: null
+  },
+  {
+    question: '漏电保护器的额定漏电动作电流不应大于( )mA。',
+    type: '单选题',
+    options: ['15', '30', '50', '100'],
+    answer: 1
+  },
+  {
+    question: '建筑施工五大伤害包括( )。',
+    type: '多选题',
+    options: [
+      '高处坠落',
+      '物体打击',
+      '触电',
+      '机械伤害',
+      '坍塌'
+    ],
+    answer: null
+  }
+]
+
+export const getMockQuestions = () => {
+  return questionBank.map(q => ({
+    ...q,
+    // 对于多选题,简化处理为选择第一个选项
+    answer: q.answer !== null ? q.answer : 0
+  })).sort(() => Math.random() - 0.5).slice(0, 10)
+}

+ 93 - 0
src/mock/hazardMock.js

@@ -0,0 +1,93 @@
+// 隐患检测MOCK数据
+export const getHazardTypes = () => [
+  '高处坠落隐患',
+  '物体打击隐患',
+  '机械伤害隐患',
+  '触电隐患',
+  '坍塌隐患',
+  '火灾爆炸隐患',
+  '中毒窒息隐患',
+  '其他隐患'
+]
+
+export const getMockHazardAnalysis = (formData) => {
+  const type = formData.type
+  
+  const riskLevel = ['高', '中', '低'][Math.floor(Math.random() * 3)]
+  
+  const analysisMap = {
+    '高处坠落隐患': '经分析,该隐患涉及高处作业区域防护措施不到位,存在人员坠落风险。高处坠落是建筑施工五大伤害之一,占事故总数的比例较高。',
+    '物体打击隐患': '经分析,现场存在交叉作业且未设置防护隔离措施,物体从高处坠落可能打击下方作业人员。需重点关注物料堆放和吊装作业。',
+    '机械伤害隐患': '经分析,机械设备防护装置缺失或不完善,操作区域未设置安全警示,存在人员接触运动部件的风险。',
+    '触电隐患': '经分析,临时用电不规范,存在电线裸露、未接地保护等问题。潮湿环境下触电风险显著增加。',
+    '坍塌隐患': '经分析,基坑/脚手架支撑体系存在缺陷,荷载超出设计范围,存在结构失稳风险。',
+    '火灾爆炸隐患': '经分析,现场存在易燃物品堆放不规范、动火作业未采取防护措施等问题,火灾风险较高。',
+    '中毒窒息隐患': '经分析,有限空间作业通风不良,有害气体浓度可能超标,存在中毒窒息风险。',
+    '其他隐患': '经分析,该隐患涉及现场安全管理薄弱环节,需结合具体情况进行深入评估和整改。'
+  }
+
+  const suggestionMap = {
+    '高处坠落隐患': [
+      '立即完善临边洞口防护栏杆(高度不低于1.2m)',
+      '高处作业人员必须正确佩戴和使用安全带',
+      '设置安全平网或立网防护',
+      '加强高处作业人员安全培训和交底',
+      '恶劣天气停止高处作业'
+    ],
+    '物体打击隐患': [
+      '设置安全通道防护棚',
+      '严禁上下交叉作业',
+      '工具材料使用工具袋传递',
+      '设置警戒区域和警示标志',
+      '加强现场巡查管理'
+    ],
+    '机械伤害隐患': [
+      '立即完善机械防护装置',
+      '设置安全警示标志',
+      '操作人员必须持证上岗',
+      '严格执行操作规程',
+      '定期维护保养设备'
+    ],
+    '触电隐患': [
+      '立即整改临时用电不规范问题',
+      '完善接地保护系统',
+      '更换破损电线电缆',
+      '配电箱安装漏电保护器',
+      '电工持证上岗'
+    ],
+    '坍塌隐患': [
+      '立即停止作业并撤离人员',
+      '重新核算支撑体系承载力',
+      '按规范重新加固支护',
+      '设置变形监测点',
+      '加强日常巡查'
+    ],
+    '火灾爆炸隐患': [
+      '清理现场易燃物品',
+      '严格执行动火审批制度',
+      '配备足够的消防器材',
+      '设置专人监护',
+      '加强消防安全巡查'
+    ],
+    '中毒窒息隐患': [
+      '立即停止作业并通风换气',
+      '检测有害气体浓度',
+      '配备个人防护用品',
+      '设置专人监护',
+      '制定应急救援预案'
+    ],
+    '其他隐患': [
+      '立即组织专业人员评估',
+      '制定专项整改方案',
+      '落实整改责任人和期限',
+      '整改完成后验收',
+      '加强日常安全管理'
+    ]
+  }
+
+  return {
+    riskLevel,
+    analysis: analysisMap[type] || analysisMap['其他隐患'],
+    suggestions: suggestionMap[type] || suggestionMap['其他隐患']
+  }
+}

+ 139 - 0
src/mock/knowledgeMock.js

@@ -0,0 +1,139 @@
+// 知识库MOCK数据
+const articles = [
+  {
+    id: 1,
+    title: '建筑施工高处作业安全技术规范解读',
+    summary: '详细解读JGJ80-2016规范中关于高处作业的各项安全要求,包括临边防护、洞口防护、攀登与悬空作业等。',
+    category: '高处作业',
+    date: '2024-01-15',
+    content: `
+      <h3>一、适用范围</h3>
+      <p>本规范适用于房屋建筑工程施工中高处作业的安全防护。</p>
+      
+      <h3>二、基本规定</h3>
+      <p>1. 高处作业施工前,应对作业人员进行安全技术教育及交底。</p>
+      <p>2. 高处作业施工前,应检查安全防护设施、工具、仪表等,确认其完好后方可使用。</p>
+      <p>3. 高处作业人员应按规定正确佩戴和使用相应的安全防护用品。</p>
+      
+      <h3>三、临边作业防护</h3>
+      <p>1. 基坑周边、尚未安装栏杆或栏板的阳台、料台与挑平台周边等处,必须设置防护栏杆。</p>
+      <p>2. 防护栏杆应由上、下两道横杆及栏杆柱组成,上杆离地高度为1.2m。</p>
+      
+      <h3>四、洞口作业防护</h3>
+      <p>1. 板与墙的洞口,必须设置牢固的盖板、防护栏杆、安全网等防护设施。</p>
+      <p>2. 电梯井内应每隔两层且不大于10m设置一道安全平网。</p>
+    `
+  },
+  {
+    id: 2,
+    title: '施工现场临时用电安全技术规范',
+    summary: 'JGJ46-2005规范要点:TN-S系统、三级配电两级保护、一机一闸一漏一箱等核心要求。',
+    category: '用电安全',
+    date: '2024-01-20',
+    content: `
+      <h3>一、总则</h3>
+      <p>为加强施工现场用电安全管理,防止触电和电气火灾事故发生,制定本规范。</p>
+      
+      <h3>二、基本规定</h3>
+      <p>1. 施工现场临时用电应采用TN-S接零保护系统。</p>
+      <p>2. 施工现场临时用电工程应采用三级配电系统。</p>
+      <p>3. 应采用二级漏电保护系统。</p>
+      
+      <h3>三、配电系统</h3>
+      <p>1. 总配电箱应设在靠近电源的区域,分配电箱应设在用电设备相对集中的区域。</p>
+      <p>2. 每台用电设备必须有各自专用的开关箱。</p>
+      <p>3. 漏电保护器应装设在总配电箱和开关箱靠近负荷的一侧。</p>
+    `
+  },
+  {
+    id: 3,
+    title: '脚手架安全技术规范要点',
+    summary: '扣件式钢管脚手架搭设与拆除技术要求,包括立杆间距、连墙件设置、剪刀撑布置等。',
+    category: '脚手架',
+    date: '2024-02-01',
+    content: `
+      <h3>一、一般规定</h3>
+      <p>脚手架搭设人员必须经过专业培训,取得特种作业操作资格证书。</p>
+      
+      <h3>二、构配件</h3>
+      <p>1. 钢管应采用Φ48.3×3.6mm规格的焊接钢管。</p>
+      <p>2. 扣件分为直角扣件、旋转扣件和对接扣件三种类型。</p>
+      
+      <h3>三、构造要求</h3>
+      <p>1. 立杆纵距不应大于1.5m,横距不应大于1.2m。</p>
+      <p>2. 步距不应大于1.8m。</p>
+      <p>3. 必须设置纵、横向扫地杆。</p>
+      
+      <h3>四、连墙件</h3>
+      <p>1. 连墙件应靠近主节点设置,偏离主节点的距离不应大于300mm。</p>
+      <p>2. 应从底层第一步纵向水平杆处开始设置。</p>
+    `
+  },
+  {
+    id: 4,
+    title: '施工现场消防安全管理',
+    summary: '消防安全责任制、动火审批制度、消防设施配置标准、应急疏散要求等消防管理要点。',
+    category: '消防安全',
+    date: '2024-02-10',
+    content: `
+      <h3>一、消防安全责任制</h3>
+      <p>施工单位应当落实消防安全责任制,明确各级消防安全责任人。</p>
+      
+      <h3>二、动火管理</h3>
+      <p>1. 施工现场动火作业实行分级管理。</p>
+      <p>2. 动火作业前必须办理动火许可证。</p>
+      <p>3. 动火作业时应当有专人监护。</p>
+      
+      <h3>三、消防设施</h3>
+      <p>1. 施工现场应配置足够的灭火器材。</p>
+      <p>2. 建筑高度大于24m或单体体积超过30000m³的在建工程应设置临时室内消防给水系统。</p>
+    `
+  },
+  {
+    id: 5,
+    title: '起重机械安全管理规范',
+    summary: '塔吊、施工升降机等起重设备的安装、验收、使用、拆卸全过程安全管理要求。',
+    category: '机械设备',
+    date: '2024-02-15',
+    content: `
+      <h3>一、总则</h3>
+      <p>起重机械的安装、使用、拆卸必须遵守国家相关法律法规和标准规范。</p>
+      
+      <h3>二、安装与拆卸</h3>
+      <p>1. 必须由具有相应资质的单位进行。</p>
+      <p>2. 必须编制专项施工方案。</p>
+      <p>3. 安装完成后必须进行验收。</p>
+      
+      <h3>三、使用管理</h3>
+      <p>1. 操作人员必须持证上岗。</p>
+      <p>2. 使用前应进行检查。</p>
+      <p>3. 定期进行维护保养。</p>
+    `
+  },
+  {
+    id: 6,
+    title: '基坑工程安全技术规范',
+    summary: '基坑开挖、支护、降水、监测等环节的安全技术要求,防止坍塌事故。',
+    category: '基坑工程',
+    date: '2024-02-20',
+    content: `
+      <h3>一、基坑开挖</h3>
+      <p>1. 基坑开挖应分层分段进行。</p>
+      <p>2. 开挖深度超过5m的基坑必须编制专项施工方案。</p>
+      
+      <h3>二、支护结构</h3>
+      <p>1. 应根据地质条件和周边环境选择支护形式。</p>
+      <p>2. 支护结构施工应符合设计要求。</p>
+      
+      <h3>三、监测要求</h3>
+      <p>1. 开挖深度超过5m的基坑必须进行监测。</p>
+      <p>2. 监测项目包括位移、沉降、地下水位等。</p>
+    `
+  }
+]
+
+const categories = [...new Set(articles.map(a => a.category))]
+
+export const getKnowledgeArticles = () => articles
+
+export const getKnowledgeCategories = () => categories

+ 35 - 0
src/router/index.js

@@ -0,0 +1,35 @@
+import { createRouter, createWebHistory } from 'vue-router'
+
+const routes = [
+  {
+    path: '/',
+    redirect: '/chat'
+  },
+  {
+    path: '/chat',
+    name: 'Chat',
+    component: () => import('@/views/Chat.vue')
+  },
+  {
+    path: '/hazard',
+    name: 'Hazard',
+    component: () => import('@/views/HazardDetection.vue')
+  },
+  {
+    path: '/exam',
+    name: 'Exam',
+    component: () => import('@/views/Exam.vue')
+  },
+  {
+    path: '/knowledge',
+    name: 'Knowledge',
+    component: () => import('@/views/Knowledge.vue')
+  }
+]
+
+const router = createRouter({
+  history: createWebHistory(),
+  routes
+})
+
+export default router

+ 278 - 0
src/views/Chat.vue

@@ -0,0 +1,278 @@
+<template>
+  <div class="chat-container">
+    <div class="chat-header">
+      <h2>蜀道安全管理AI智能助手</h2>
+    </div>
+    <div class="chat-messages" ref="messagesContainer">
+      <div v-for="(msg, index) in messages" :key="index" :class="['message', msg.role]">
+        <div class="avatar">{{ msg.role === 'user' ? '👤' : '🤖' }}</div>
+        <div class="content">
+          <div v-if="msg.role === 'ai'" v-html="renderMarkdown(msg.content)" class="markdown-content"></div>
+          <div v-else>{{ msg.content }}</div>
+          <div class="message-actions" v-if="msg.role === 'ai'">
+            <button @click="copyMessage(msg.content)" class="action-btn">📋 复制</button>
+          </div>
+        </div>
+      </div>
+      <div v-if="isLoading" class="message ai">
+        <div class="avatar">🤖</div>
+        <div class="content">
+          <div class="typing-indicator">思考中...</div>
+        </div>
+      </div>
+    </div>
+    <div class="chat-input-area">
+      <div class="quick-questions" v-if="messages.length === 0">
+        <div class="section-title">常见问题</div>
+        <div class="question-list">
+          <button 
+            v-for="q in quickQuestions" 
+            :key="q" 
+            @click="sendQuickQuestion(q)"
+            class="quick-btn"
+          >{{ q }}</button>
+        </div>
+      </div>
+      <div class="input-wrapper">
+        <textarea
+          v-model="inputMessage"
+          @keydown.enter.exact.prevent="sendMessage"
+          placeholder="请输入您的问题..."
+          :disabled="isLoading"
+          rows="1"
+        ></textarea>
+        <button 
+          @click="sendMessage" 
+          :disabled="!inputMessage.trim() || isLoading"
+          class="send-btn"
+        >发送</button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, nextTick, watch } from 'vue'
+import { marked } from 'marked'
+import { getMockResponse, getQuickQuestions } from '@/mock/chatMock'
+
+const messages = ref([])
+const inputMessage = ref('')
+const isLoading = ref(false)
+const messagesContainer = ref(null)
+const quickQuestions = ref(getQuickQuestions())
+
+const renderMarkdown = (content) => {
+  return marked.parse(content)
+}
+
+const scrollToBottom = async () => {
+  await nextTick()
+  if (messagesContainer.value) {
+    messagesContainer.value.scrollTop = messagesContainer.value.scrollHeight
+  }
+}
+
+const sendMessage = async () => {
+  const message = inputMessage.value.trim()
+  if (!message || isLoading.value) return
+
+  messages.value.push({ role: 'user', content: message })
+  inputMessage.value = ''
+  isLoading.value = true
+  await scrollToBottom()
+
+  // Mock AI response
+  setTimeout(async () => {
+    const response = getMockResponse(message)
+    messages.value.push({ role: 'ai', content: response })
+    isLoading.value = false
+    await scrollToBottom()
+  }, 1000)
+}
+
+const sendQuickQuestion = (question) => {
+  inputMessage.value = question
+  sendMessage()
+}
+
+const copyMessage = async (content) => {
+  await navigator.clipboard.writeText(content)
+}
+</script>
+
+<style scoped lang="scss">
+.chat-container {
+  display: flex;
+  flex-direction: column;
+  height: 100%;
+  background: #f8f9fa;
+}
+
+.chat-header {
+  padding: 20px 24px;
+  background: #fff;
+  border-bottom: 1px solid #e8e8e8;
+
+  h2 {
+    font-size: 18px;
+    font-weight: 500;
+    color: #333;
+  }
+}
+
+.chat-messages {
+  flex: 1;
+  overflow-y: auto;
+  padding: 24px;
+
+  .message {
+    display: flex;
+    margin-bottom: 20px;
+    gap: 12px;
+
+    &.user {
+      flex-direction: row-reverse;
+    }
+
+    .avatar {
+      font-size: 32px;
+      flex-shrink: 0;
+    }
+
+    .content {
+      max-width: 70%;
+      padding: 12px 16px;
+      border-radius: 12px;
+      background: #fff;
+      box-shadow: 0 1px 2px rgba(0,0,0,0.05);
+
+      .markdown-content {
+        :deep(p) {
+          margin-bottom: 8px;
+        }
+        :deep(p:last-child) {
+          margin-bottom: 0;
+        }
+      }
+    }
+
+    &.ai .content {
+      background: #fff;
+    }
+
+    &.user .content {
+      background: #1890ff;
+      color: #fff;
+    }
+
+    .message-actions {
+      margin-top: 8px;
+      padding-top: 8px;
+      border-top: 1px solid #f0f0f0;
+
+      .action-btn {
+        background: none;
+        border: none;
+        color: #999;
+        cursor: pointer;
+        font-size: 12px;
+        padding: 4px 8px;
+
+        &:hover {
+          color: #666;
+        }
+      }
+    }
+  }
+
+  .typing-indicator {
+    color: #999;
+    font-style: italic;
+  }
+}
+
+.chat-input-area {
+  padding: 20px 24px;
+  background: #fff;
+  border-top: 1px solid #e8e8e8;
+}
+
+.quick-questions {
+  margin-bottom: 16px;
+
+  .section-title {
+    font-size: 14px;
+    color: #666;
+    margin-bottom: 12px;
+  }
+
+  .question-list {
+    display: flex;
+    flex-wrap: wrap;
+    gap: 8px;
+
+    .quick-btn {
+      padding: 8px 16px;
+      border: 1px solid #d9d9d9;
+      border-radius: 20px;
+      background: #fff;
+      cursor: pointer;
+      font-size: 13px;
+      color: #666;
+      transition: all 0.2s;
+
+      &:hover {
+        border-color: #1890ff;
+        color: #1890ff;
+      }
+    }
+  }
+}
+
+.input-wrapper {
+  display: flex;
+  gap: 12px;
+  align-items: flex-end;
+
+  textarea {
+    flex: 1;
+    padding: 12px 16px;
+    border: 1px solid #d9d9d9;
+    border-radius: 8px;
+    resize: none;
+    font-size: 14px;
+    line-height: 1.5;
+    outline: none;
+    transition: border-color 0.2s;
+
+    &:focus {
+      border-color: #1890ff;
+    }
+
+    &:disabled {
+      background: #f5f5f5;
+    }
+  }
+
+  .send-btn {
+    padding: 12px 24px;
+    background: #1890ff;
+    color: #fff;
+    border: none;
+    border-radius: 8px;
+    cursor: pointer;
+    font-size: 14px;
+    transition: background 0.2s;
+
+    &:hover:not(:disabled) {
+      background: #40a9ff;
+    }
+
+    &:disabled {
+      background: #d9d9d9;
+      cursor: not-allowed;
+    }
+  }
+}
+</style>

+ 393 - 0
src/views/Exam.vue

@@ -0,0 +1,393 @@
+<template>
+  <div class="exam-container">
+    <div class="exam-header">
+      <h2>安全模拟考试</h2>
+      <div class="exam-controls" v-if="!isExamStarted">
+        <select v-model="examType">
+          <option value="comprehensive">综合测试</option>
+          <option value="special">专项测试</option>
+        </select>
+        <button @click="startExam" class="start-btn">开始考试</button>
+      </div>
+      <div class="exam-info" v-if="isExamStarted">
+        <span class="progress">题目:{{ currentQuestion + 1 }}/{{ questions.length }}</span>
+        <span class="timer">用时:{{ formattedTime }}</span>
+        <button @click="finishExam" class="finish-btn">交卷</button>
+      </div>
+    </div>
+    <div class="exam-content" v-if="isExamStarted && questions.length > 0">
+      <div class="question-card">
+        <div class="question-header">
+          <span class="question-number">第 {{ currentQuestion + 1 }} 题</span>
+          <span class="question-type">{{ currentQ.type }}</span>
+        </div>
+        <div class="question-content">
+          {{ currentQ.question }}
+        </div>
+        <div class="options">
+          <div
+            v-for="(option, index) in currentQ.options"
+            :key="index"
+            :class="['option', { selected: userAnswers[currentQuestion] === index }]"
+            @click="selectAnswer(index)"
+          >
+            <span class="option-label">{{ String.fromCharCode(65 + index) }}</span>
+            <span class="option-text">{{ option }}</span>
+          </div>
+        </div>
+        <div class="question-nav">
+          <button @click="prevQuestion" :disabled="currentQuestion === 0">上一题</button>
+          <button @click="nextQuestion" :disabled="currentQuestion === questions.length - 1">下一题</button>
+        </div>
+      </div>
+      <div class="question-list">
+        <h4>答题卡</h4>
+        <div class="question-numbers">
+          <div
+            v-for="(q, i) in questions"
+            :key="i"
+            :class="['number', { active: i === currentQuestion, answered: userAnswers[i] !== undefined }]"
+            @click="jumpToQuestion(i)"
+          >{{ i + 1 }}</div>
+        </div>
+      </div>
+    </div>
+    <div class="exam-result" v-if="examResult">
+      <h3>考试结果</h3>
+      <div class="score-card">
+        <div class="score">{{ examResult.score }}</div>
+        <div class="score-label">总分</div>
+      </div>
+      <div class="stats">
+        <span>正确:{{ examResult.correct }}/{{ questions.length }}</span>
+        <span>用时:{{ formattedTime }}</span>
+      </div>
+      <button @click="resetExam" class="restart-btn">重新考试</button>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed, onUnmounted } from 'vue'
+import { getMockQuestions } from '@/mock/examMock'
+
+const examType = ref('comprehensive')
+const isExamStarted = ref(false)
+const questions = ref([])
+const currentQuestion = ref(0)
+const userAnswers = ref({})
+const examResult = ref(null)
+const timer = ref(0)
+let timerInterval = null
+
+const currentQ = computed(() => questions.value[currentQuestion.value] || {})
+
+const formattedTime = computed(() => {
+  const mins = Math.floor(timer.value / 60)
+  const secs = timer.value % 60
+  return `${String(mins).padStart(2, '0')}:${String(secs).padStart(2, '0')}`
+})
+
+const startExam = () => {
+  questions.value = getMockQuestions()
+  isExamStarted.value = true
+  currentQuestion.value = 0
+  userAnswers.value = {}
+  examResult.value = null
+  timer.value = 0
+  timerInterval = setInterval(() => timer.value++, 1000)
+}
+
+const selectAnswer = (index) => {
+  userAnswers.value[currentQuestion.value] = index
+}
+
+const nextQuestion = () => {
+  if (currentQuestion.value < questions.value.length - 1) {
+    currentQuestion.value++
+  }
+}
+
+const prevQuestion = () => {
+  if (currentQuestion.value > 0) {
+    currentQuestion.value--
+  }
+}
+
+const jumpToQuestion = (index) => {
+  currentQuestion.value = index
+}
+
+const finishExam = () => {
+  clearInterval(timerInterval)
+  let correct = 0
+  questions.value.forEach((q, i) => {
+    if (userAnswers.value[i] === q.answer) correct++
+  })
+  const score = Math.round((correct / questions.value.length) * 100)
+  examResult.value = { score, correct, total: questions.value.length }
+}
+
+const resetExam = () => {
+  isExamStarted.value = false
+  examResult.value = null
+  questions.value = []
+}
+
+onUnmounted(() => {
+  if (timerInterval) clearInterval(timerInterval)
+})
+</script>
+
+<style scoped lang="scss">
+.exam-container {
+  height: 100%;
+  background: #f8f9fa;
+  overflow-y: auto;
+  padding: 24px;
+}
+
+.exam-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24px;
+
+  h2 {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .exam-controls {
+    display: flex;
+    gap: 12px;
+
+    select {
+      padding: 8px 12px;
+      border: 1px solid #d9d9d9;
+      border-radius: 6px;
+      font-size: 14px;
+    }
+
+    .start-btn {
+      padding: 8px 20px;
+      background: #1890ff;
+      color: #fff;
+      border: none;
+      border-radius: 6px;
+      cursor: pointer;
+
+      &:hover {
+        background: #40a9ff;
+      }
+    }
+  }
+
+  .exam-info {
+    display: flex;
+    gap: 16px;
+    align-items: center;
+
+    .progress, .timer {
+      color: #666;
+    }
+
+    .finish-btn {
+      padding: 8px 16px;
+      background: #ff4d4f;
+      color: #fff;
+      border: none;
+      border-radius: 6px;
+      cursor: pointer;
+    }
+  }
+}
+
+.exam-content {
+  display: grid;
+  grid-template-columns: 2fr 1fr;
+  gap: 24px;
+}
+
+.question-card {
+  background: #fff;
+  padding: 24px;
+  border-radius: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.05);
+
+  .question-header {
+    display: flex;
+    justify-content: space-between;
+    margin-bottom: 16px;
+
+    .question-number {
+      font-weight: 500;
+      color: #333;
+    }
+
+    .question-type {
+      padding: 2px 8px;
+      background: #f0f5ff;
+      color: #1890ff;
+      border-radius: 4px;
+      font-size: 12px;
+    }
+  }
+
+  .question-content {
+    font-size: 16px;
+    color: #333;
+    margin-bottom: 20px;
+    line-height: 1.6;
+  }
+
+  .options {
+    .option {
+      display: flex;
+      align-items: center;
+      padding: 12px 16px;
+      margin-bottom: 8px;
+      border: 1px solid #e8e8e8;
+      border-radius: 8px;
+      cursor: pointer;
+      transition: all 0.2s;
+
+      &:hover {
+        border-color: #1890ff;
+      }
+
+      &.selected {
+        background: #f0f5ff;
+        border-color: #1890ff;
+      }
+
+      .option-label {
+        width: 28px;
+        height: 28px;
+        display: flex;
+        align-items: center;
+        justify-content: center;
+        background: #f5f5f5;
+        border-radius: 50%;
+        margin-right: 12px;
+        font-size: 14px;
+      }
+
+      &.selected .option-label {
+        background: #1890ff;
+        color: #fff;
+      }
+    }
+  }
+
+  .question-nav {
+    display: flex;
+    justify-content: space-between;
+    margin-top: 24px;
+
+    button {
+      padding: 8px 20px;
+      border: 1px solid #d9d9d9;
+      background: #fff;
+      border-radius: 6px;
+      cursor: pointer;
+
+      &:hover:not(:disabled) {
+        border-color: #1890ff;
+        color: #1890ff;
+      }
+
+      &:disabled {
+        opacity: 0.5;
+        cursor: not-allowed;
+      }
+    }
+  }
+}
+
+.question-list {
+  background: #fff;
+  padding: 24px;
+  border-radius: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.05);
+  height: fit-content;
+
+  h4 {
+    margin-bottom: 16px;
+    color: #333;
+  }
+
+  .question-numbers {
+    display: grid;
+    grid-template-columns: repeat(5, 1fr);
+    gap: 8px;
+
+    .number {
+      width: 36px;
+      height: 36px;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      border: 1px solid #d9d9d9;
+      border-radius: 6px;
+      cursor: pointer;
+      font-size: 13px;
+
+      &:hover {
+        border-color: #1890ff;
+      }
+
+      &.active {
+        background: #1890ff;
+        color: #fff;
+        border-color: #1890ff;
+      }
+
+      &.answered {
+        background: #52c41a;
+        color: #fff;
+        border-color: #52c41a;
+      }
+    }
+  }
+}
+
+.exam-result {
+  text-align: center;
+  background: #fff;
+  padding: 48px;
+  border-radius: 12px;
+
+  .score-card {
+    margin: 24px 0;
+
+    .score {
+      font-size: 64px;
+      font-weight: 600;
+      color: #1890ff;
+    }
+
+    .score-label {
+      color: #666;
+      font-size: 14px;
+    }
+  }
+
+  .stats {
+    margin-bottom: 24px;
+    display: flex;
+    justify-content: center;
+    gap: 24px;
+    color: #666;
+  }
+
+  .restart-btn {
+    padding: 10px 32px;
+    background: #1890ff;
+    color: #fff;
+    border: none;
+    border-radius: 6px;
+    cursor: pointer;
+  }
+}
+</style>

+ 230 - 0
src/views/HazardDetection.vue

@@ -0,0 +1,230 @@
+<template>
+  <div class="hazard-container">
+    <div class="hazard-header">
+      <h2>安全隐患检测</h2>
+      <p class="sub-title">上传现场照片或填写隐患描述,AI智能识别安全隐患</p>
+    </div>
+    <div class="hazard-content">
+      <div class="form-section">
+        <div class="form-group">
+          <label>隐患类型</label>
+          <select v-model="formData.type">
+            <option value="">请选择隐患类型</option>
+            <option v-for="type in hazardTypes" :key="type" :value="type">{{ type }}</option>
+          </select>
+        </div>
+        <div class="form-group">
+          <label>隐患描述</label>
+          <textarea 
+            v-model="formData.description" 
+            placeholder="请详细描述发现的安全隐患..."
+            rows="4"
+          ></textarea>
+        </div>
+        <div class="form-group">
+          <label>现场照片(可选)</label>
+          <div class="upload-area" @click="triggerUpload">
+            <span class="upload-icon">📷</span>
+            <span>点击上传照片</span>
+          </div>
+        </div>
+        <button @click="submitHazard" :disabled="isSubmitting" class="submit-btn">
+          {{ isSubmitting ? '分析中...' : '提交分析' }}
+        </button>
+      </div>
+      <div class="result-section" v-if="result">
+        <h3>分析结果</h3>
+        <div class="result-card">
+          <div class="risk-level" :class="result.riskLevel">
+            风险等级:{{ result.riskLevel }}
+          </div>
+          <div class="analysis-content">
+            <h4>隐患分析</h4>
+            <p>{{ result.analysis }}</p>
+          </div>
+          <div class="suggestions">
+            <h4>整改建议</h4>
+            <ul>
+              <li v-for="(s, i) in result.suggestions" :key="i">{{ s }}</li>
+            </ul>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref } from 'vue'
+import { getHazardTypes, getMockHazardAnalysis } from '@/mock/hazardMock'
+
+const formData = ref({
+  type: '',
+  description: '',
+  photos: []
+})
+
+const hazardTypes = ref(getHazardTypes())
+const isSubmitting = ref(false)
+const result = ref(null)
+
+const triggerUpload = () => {
+  // Mock upload
+}
+
+const submitHazard = async () => {
+  if (!formData.value.type || !formData.value.description) {
+    alert('请填写完整的隐患信息')
+    return
+  }
+  isSubmitting.value = true
+  setTimeout(() => {
+    result.value = getMockHazardAnalysis(formData.value)
+    isSubmitting.value = false
+  }, 1500)
+}
+</script>
+
+<style scoped lang="scss">
+.hazard-container {
+  height: 100%;
+  background: #f8f9fa;
+  overflow-y: auto;
+  padding: 24px;
+}
+
+.hazard-header {
+  margin-bottom: 24px;
+
+  h2 {
+    font-size: 20px;
+    color: #333;
+    margin-bottom: 8px;
+  }
+
+  .sub-title {
+    color: #666;
+    font-size: 14px;
+  }
+}
+
+.hazard-content {
+  display: grid;
+  grid-template-columns: 1fr 1fr;
+  gap: 24px;
+}
+
+.form-section, .result-section {
+  background: #fff;
+  padding: 24px;
+  border-radius: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.05);
+}
+
+.form-group {
+  margin-bottom: 20px;
+
+  label {
+    display: block;
+    margin-bottom: 8px;
+    font-size: 14px;
+    color: #333;
+  }
+
+  select, textarea {
+    width: 100%;
+    padding: 10px 12px;
+    border: 1px solid #d9d9d9;
+    border-radius: 8px;
+    font-size: 14px;
+    outline: none;
+
+    &:focus {
+      border-color: #1890ff;
+    }
+  }
+}
+
+.upload-area {
+  border: 2px dashed #d9d9d9;
+  border-radius: 8px;
+  padding: 24px;
+  text-align: center;
+  cursor: pointer;
+  transition: border-color 0.2s;
+
+  &:hover {
+    border-color: #1890ff;
+  }
+
+  .upload-icon {
+    font-size: 32px;
+    display: block;
+    margin-bottom: 8px;
+  }
+}
+
+.submit-btn {
+  width: 100%;
+  padding: 12px;
+  background: #1890ff;
+  color: #fff;
+  border: none;
+  border-radius: 8px;
+  font-size: 14px;
+  cursor: pointer;
+
+  &:hover:not(:disabled) {
+    background: #40a9ff;
+  }
+
+  &:disabled {
+    background: #d9d9d9;
+    cursor: not-allowed;
+  }
+}
+
+.result-card {
+  .risk-level {
+    padding: 8px 16px;
+    border-radius: 6px;
+    font-weight: 500;
+    margin-bottom: 16px;
+
+    &.高 {
+      background: #fff1f0;
+      color: #ff4d4f;
+    }
+    &.中 {
+      background: #fffbe6;
+      color: #faad14;
+    }
+    &.低 {
+      background: #f6ffed;
+      color: #52c41a;
+    }
+  }
+
+  h4 {
+    font-size: 14px;
+    color: #333;
+    margin-bottom: 8px;
+  }
+
+  .analysis-content {
+    margin-bottom: 16px;
+    padding-bottom: 16px;
+    border-bottom: 1px solid #f0f0f0;
+  }
+
+  .suggestions ul {
+    padding-left: 20px;
+
+    li {
+      margin-bottom: 8px;
+      color: #666;
+      font-size: 14px;
+    }
+  }
+}
+</style>

+ 236 - 0
src/views/Knowledge.vue

@@ -0,0 +1,236 @@
+<template>
+  <div class="knowledge-container">
+    <div class="knowledge-header">
+      <h2>安全知识库</h2>
+      <div class="search-bar">
+        <input v-model="searchKeyword" placeholder="搜索安全知识..." @input="searchKnowledge" />
+      </div>
+    </div>
+    <div class="knowledge-content">
+      <div class="category-tabs">
+        <button
+          v-for="cat in categories"
+          :key="cat"
+          :class="['tab', { active: currentCategory === cat }]"
+          @click="currentCategory = cat"
+        >{{ cat }}</button>
+      </div>
+      <div class="article-list">
+        <div
+          v-for="article in filteredArticles"
+          :key="article.id"
+          class="article-card"
+          @click="viewArticle(article)"
+        >
+          <h3>{{ article.title }}</h3>
+          <p class="summary">{{ article.summary }}</p>
+          <div class="meta">
+            <span class="category">{{ article.category }}</span>
+            <span class="date">{{ article.date }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+    <div class="article-modal" v-if="selectedArticle" @click.self="selectedArticle = null">
+      <div class="modal-content">
+        <button class="close-btn" @click="selectedArticle = null">✕</button>
+        <h2>{{ selectedArticle.title }}</h2>
+        <div class="article-body" v-html="selectedArticle.content"></div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script setup>
+import { ref, computed } from 'vue'
+import { getKnowledgeArticles, getKnowledgeCategories } from '@/mock/knowledgeMock'
+
+const articles = ref(getKnowledgeArticles())
+const categories = ref(['全部', ...getKnowledgeCategories()])
+const currentCategory = ref('全部')
+const searchKeyword = ref('')
+const selectedArticle = ref(null)
+
+const filteredArticles = computed(() => {
+  let result = articles.value
+  if (currentCategory.value !== '全部') {
+    result = result.filter(a => a.category === currentCategory.value)
+  }
+  if (searchKeyword.value) {
+    const keyword = searchKeyword.value.toLowerCase()
+    result = result.filter(a =>
+      a.title.toLowerCase().includes(keyword) ||
+      a.summary.toLowerCase().includes(keyword)
+    )
+  }
+  return result
+})
+
+const searchKnowledge = () => {
+  // filtered by computed
+}
+
+const viewArticle = (article) => {
+  selectedArticle.value = article
+}
+</script>
+
+<style scoped lang="scss">
+.knowledge-container {
+  height: 100%;
+  background: #f8f9fa;
+  overflow-y: auto;
+  padding: 24px;
+}
+
+.knowledge-header {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  margin-bottom: 24px;
+
+  h2 {
+    font-size: 20px;
+    color: #333;
+  }
+
+  .search-bar input {
+    padding: 10px 16px;
+    width: 300px;
+    border: 1px solid #d9d9d9;
+    border-radius: 20px;
+    outline: none;
+
+    &:focus {
+      border-color: #1890ff;
+    }
+  }
+}
+
+.category-tabs {
+  display: flex;
+  gap: 8px;
+  margin-bottom: 20px;
+  flex-wrap: wrap;
+
+  .tab {
+    padding: 8px 16px;
+    border: 1px solid #d9d9d9;
+    background: #fff;
+    border-radius: 20px;
+    cursor: pointer;
+    font-size: 13px;
+    transition: all 0.2s;
+
+    &:hover {
+      border-color: #1890ff;
+      color: #1890ff;
+    }
+
+    &.active {
+      background: #1890ff;
+      color: #fff;
+      border-color: #1890ff;
+    }
+  }
+}
+
+.article-list {
+  display: grid;
+  grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
+  gap: 20px;
+}
+
+.article-card {
+  background: #fff;
+  padding: 20px;
+  border-radius: 12px;
+  box-shadow: 0 1px 4px rgba(0,0,0,0.05);
+  cursor: pointer;
+  transition: transform 0.2s, box-shadow 0.2s;
+
+  &:hover {
+    transform: translateY(-2px);
+    box-shadow: 0 4px 12px rgba(0,0,0,0.1);
+  }
+
+  h3 {
+    font-size: 16px;
+    color: #333;
+    margin-bottom: 8px;
+  }
+
+  .summary {
+    color: #666;
+    font-size: 13px;
+    line-height: 1.5;
+    margin-bottom: 12px;
+    display: -webkit-box;
+    -webkit-line-clamp: 2;
+    -webkit-box-orient: vertical;
+    overflow: hidden;
+  }
+
+  .meta {
+    display: flex;
+    justify-content: space-between;
+    font-size: 12px;
+    color: #999;
+
+    .category {
+      padding: 2px 8px;
+      background: #f0f5ff;
+      color: #1890ff;
+      border-radius: 4px;
+    }
+  }
+}
+
+.article-modal {
+  position: fixed;
+  top: 0;
+  left: 0;
+  right: 0;
+  bottom: 0;
+  background: rgba(0,0,0,0.5);
+  display: flex;
+  align-items: center;
+  justify-content: center;
+  z-index: 1000;
+
+  .modal-content {
+    background: #fff;
+    width: 80%;
+    max-height: 80vh;
+    border-radius: 12px;
+    padding: 32px;
+    overflow-y: auto;
+    position: relative;
+
+    .close-btn {
+      position: absolute;
+      top: 16px;
+      right: 16px;
+      background: none;
+      border: none;
+      font-size: 20px;
+      cursor: pointer;
+      color: #666;
+    }
+
+    h2 {
+      margin-bottom: 16px;
+      color: #333;
+    }
+
+    .article-body {
+      line-height: 1.8;
+      color: #333;
+
+      :deep(p) {
+        margin-bottom: 12px;
+      }
+    }
+  }
+}
+</style>

+ 16 - 0
vite.config.js

@@ -0,0 +1,16 @@
+import { defineConfig } from 'vite'
+import vue from '@vitejs/plugin-vue'
+import path from 'path'
+
+export default defineConfig({
+  plugins: [vue()],
+  resolve: {
+    alias: {
+      '@': path.resolve(__dirname, './src')
+    }
+  },
+  server: {
+    port: 3000,
+    open: true
+  }
+})