diff --git a/.gitignore b/.gitignore index bb73d6b..00bbf8e 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,7 @@ dist-ssr package-lock.json # Cursor rules -.cursor/ \ No newline at end of file +.cursor/ + +# ESLint cache +.eslintcache \ No newline at end of file diff --git a/config/vite.config.prod.ts b/config/vite.config.prod.ts index 79a8864..52cad57 100644 --- a/config/vite.config.prod.ts +++ b/config/vite.config.prod.ts @@ -17,10 +17,25 @@ export default mergeConfig( build: { rollupOptions: { output: { - manualChunks: { - arco: ['@arco-design/web-vue'], - chart: ['echarts', 'vue-echarts'], - vue: ['vue', 'vue-router', 'pinia', '@vueuse/core', 'vue-i18n'], + manualChunks: (id: string) => { + if (id.includes('node_modules')) { + if (id.includes('@arco-design/web-vue')) { + return 'arco'; + } + if (id.includes('echarts') || id.includes('vue-echarts')) { + return 'chart'; + } + if ( + id.includes('vue') || + id.includes('pinia') || + id.includes('@vueuse/core') || + id.includes('vue-i18n') + ) { + return 'vue'; + } + return 'vendor'; + } + return undefined; }, }, }, diff --git a/deploy_frontend.sh b/deploy_frontend.sh new file mode 100755 index 0000000..199b400 --- /dev/null +++ b/deploy_frontend.sh @@ -0,0 +1,249 @@ +#!/bin/bash + +# 前端一键部署脚本 + +# 服务器配置 +SERVER_HOST="39.108.66.84" +SERVER_USER="root" +SERVER_PASSWORD='Kola123!@#' +SERVER="$SERVER_USER@$SERVER_HOST" +SERVER_PATH="/www/wwwroot/leaser_front" +DIST_DIR="dist" +FRONTEND_PORT="9501" # 默认端口,宝塔面板站点推荐使用9501 + +# 检测是否安装了sshpass +if command -v sshpass >/dev/null 2>&1; then + USE_SSHPASS=true + SSH_CMD="sshpass -p $SERVER_PASSWORD ssh -o StrictHostKeyChecking=no" + SCP_CMD="sshpass -p $SERVER_PASSWORD scp -o StrictHostKeyChecking=no -r" +else + USE_SSHPASS=false + SSH_CMD="ssh -o StrictHostKeyChecking=no" + SCP_CMD="scp -o StrictHostKeyChecking=no -r" +fi + +# 颜色定义 +GREEN='\033[0;32m' +BLUE='\033[0;34m' +RED='\033[0;31m' +YELLOW='\033[1;33m' +NC='\033[0m' + +log() { echo -e "${BLUE}[信息]${NC} $1"; } +success() { echo -e "${GREEN}[成功]${NC} $1"; } +error() { echo -e "${RED}[错误]${NC} $1"; } +warn() { echo -e "${YELLOW}[警告]${NC} $1"; } + +# SSH执行函数 +run_ssh() { + local cmd="$1" + if [ "$USE_SSHPASS" = true ]; then + $SSH_CMD "$SERVER" "$cmd" + else + echo -e "${YELLOW}[SSH连接]${NC} 请输入服务器密码: $SERVER_PASSWORD" + $SSH_CMD "$SERVER" "$cmd" + fi +} + +# SCP上传函数 +run_scp() { + local source="$1" + local dest="$2" + if [ "$USE_SSHPASS" = true ]; then + $SCP_CMD "$source" "$SERVER:$dest" + else + echo -e "${YELLOW}[SCP上传]${NC} 请输入服务器密码: $SERVER_PASSWORD" + $SCP_CMD "$source" "$SERVER:$dest" + fi +} + +# 显示密码提示 +show_password_hint() { + if [ "$USE_SSHPASS" = true ]; then + echo -e "${GREEN}[sshpass]${NC} 已启用自动登录,无需手动输入密码 ✅" + else + echo -e "${YELLOW}[密码提示]${NC} 服务器密码: $SERVER_PASSWORD" + echo -e "${BLUE}[建议]${NC} 安装 sshpass 以启用自动登录" + echo " Mac: brew install hudochenkov/sshpass/sshpass" + echo " Ubuntu/Debian: apt-get install sshpass" + echo " CentOS/RHEL: yum install sshpass" + fi +} + +# 检查前端的端口配置 +check_frontend_port() { + log "检查宝塔面板前端站点端口配置..." + # 第一种方法:直接查找站点配置 + local port_info=$(run_ssh "grep -r 'leaser_front' /www/server/panel/vhost/nginx/ 2>/dev/null | grep -i listen | head -1 || echo 'No port info found'") + + # 第二种方法:如果宝塔面板有站点配置表 + if [ "$port_info" = "No port info found" ]; then + port_info=$(run_ssh "if [ -f /www/server/panel/data/site.json ]; then cat /www/server/panel/data/site.json | grep -E '\"name\":\"leaser_front|\"port\":' | head -2; else echo 'No site config found'; fi") + fi + + if [[ $port_info =~ listen[[:space:]]+([0-9]+) ]] || [[ $port_info =~ \"port\":\"?([0-9]+)\"? ]]; then + FRONTEND_PORT=${BASH_REMATCH[1]} + success "宝塔面板检测到前端站点端口: $FRONTEND_PORT" + else + warn "未在宝塔面板中找到前端站点配置,将使用默认端口: $FRONTEND_PORT" + warn "建议在宝塔面板创建一个新站点,站点目录为: $SERVER_PATH" + fi +} + +echo "========================================" +log "前端项目远程部署工具" +echo "服务器: $SERVER" +echo "项目路径: $SERVER_PATH" +echo "========================================" +show_password_hint +echo "" + +# 远程构建函数 +remote_build() { + log "在服务器上进行构建..." + run_ssh "cd $SERVER_PATH && \ + echo '检查Node环境和依赖...' && \ + node -v && npm -v && \ + echo '检查并安装 pnpm...' && \ + if ! command -v pnpm &>/dev/null; then \ + echo '安装 pnpm...' && \ + npm install -g pnpm; \ + else \ + echo 'pnpm已安装: ' && pnpm -v; \ + fi && \ + echo '安装项目依赖...' && \ + pnpm install && \ + echo '开始构建项目...' && \ + NODE_ENV=production pnpm build && \ + if [ -d '$DIST_DIR' ]; then \ + echo '✅ 远程构建成功'; \ + if [ -d 'backup_dist' ]; then rm -rf backup_dist; fi && \ + mkdir -p backup_dist && \ + find . -maxdepth 1 -not -path './node_modules*' -not -path './.git*' -not -path './$DIST_DIR*' -not -path './backup_dist*' -not -path '.' | xargs -I{} mv {} backup_dist/ 2>/dev/null || true && \ + mv $DIST_DIR/* . && \ + rmdir $DIST_DIR && \ + echo '✅ 部署文件就位完成'; \ + else \ + echo '❌ 远程构建失败'; \ + exit 1; \ + fi" + + if [ $? -eq 0 ]; then + success "远程构建并部署成功" + return 0 + else + error "远程构建失败" + return 1 + fi +} + +case "${1:-deploy}" in + "test"|"t") + log "测试服务器连接..." + run_ssh "echo '✅ 连接成功'" + ;; + + "status"|"s") + log "查看前端项目状态..." + run_ssh "cd $SERVER_PATH && echo '=== 文件统计 ===' && find . -type f -not -path '*/\.*' | grep -v 'node_modules' | wc -l && echo '=== 最新文件 ===' && find . -type f -not -path '*/\.*' | grep -v 'node_modules' | xargs ls -lt | head -5 && echo '=== Nginx状态 ===' && systemctl status nginx | grep Active || echo 'Nginx可能未安装'" + ;; + + "logs"|"l") + log "查看Nginx访问日志..." + run_ssh "tail -f /var/log/nginx/access.log 2>/dev/null || echo '无法访问Nginx日志'" + ;; + + "check"|"c") + log "检查前端部署情况..." + run_ssh "cd $SERVER_PATH && echo '=== 目录内容 ===' && ls -la | grep -v node_modules && echo '=== 文件大小 ===' && du -sh && echo '=== index.html检查 ===' && cat index.html 2>/dev/null | grep -i title | head -1 || echo '找不到index.html文件'" + ;; + + "nginx") + log "检查Nginx配置..." + run_ssh "cat /etc/nginx/sites-enabled/* 2>/dev/null || cat /etc/nginx/conf.d/* 2>/dev/null || cat /www/server/nginx/conf/nginx.conf 2>/dev/null || echo '找不到Nginx配置'" + ;; + + "portconfig") + log "查询宝塔面板前端站点配置..." + run_ssh "echo '=== 宝塔站点配置文件 ===' && \ + find /www/server/panel/vhost/nginx/ -name '*.conf' -exec ls -la {} \; 2>/dev/null && \ + echo '=== 宝塔站点配置查询 ===' && \ + grep -r 'leaser_front' /www/server/panel/vhost/nginx/ 2>/dev/null || echo '未在Nginx配置中找到前端站点配置' && \ + echo '=== 宝塔站点列表 ===' && \ + if [ -f /www/server/panel/data/site.json ]; then grep -E '\"name|\"path|\"port' /www/server/panel/data/site.json | head -15; else echo '未找到宝塔站点数据'; fi" + check_frontend_port + ;; + + "build"|"b") + clean_local_build + local_build + ;; + + "pull"|"p") + log "拉取最新代码..." + run_ssh "cd $SERVER_PATH && (git pull 2>/dev/null || git pull https://kola:Cyne2012@\$(git config --get remote.origin.url | sed 's|https://||'))" + ;; + + "upload"|"u") + if [ -d "$DIST_DIR" ]; then + upload_files + else + error "未找到 $DIST_DIR 目录,请先执行构建命令" + fi + ;; + + "deploy"|"d"|"") + log "开始前端远程部署流程..." + echo "" + + log "步骤 1/3: 拉取最新代码" + run_ssh "cd $SERVER_PATH && git pull || echo '拉取代码失败,请检查服务器Git配置'" + + log "步骤 2/3: 备份现有文件" + run_ssh "cd $SERVER_PATH && mkdir -p backup_$(date +%Y%m%d) && find . -maxdepth 1 -type f -not -path '*/\.git*' -not -path '*/node_modules*' -exec cp {} backup_$(date +%Y%m%d)/ \; 2>/dev/null || echo '没有需要备份的文件'" + + log "步骤 3/3: 远程构建部署" + if remote_build; then + # 检查端口配置 + check_frontend_port + success "🎉 部署流程完成!" + if [ "$FRONTEND_PORT" = "80" ]; then + echo "🌐 网站地址: http://$SERVER_HOST" + else + echo "🌐 网站地址: http://$SERVER_HOST:$FRONTEND_PORT" + fi + echo "📡 如果还没有在宝塔面板创建站点,请在宝塔面板中创建一个新站点,指向路径 $SERVER_PATH" + echo "" + log "执行状态检查..." + run_ssh "cd $SERVER_PATH && echo '=== 文件检查 ===' && ls -la | grep -v node_modules | head -10 && echo '=== index.html存在检查 ===' && [ -f index.html ] && echo '✅ index.html 存在' || echo '❌ index.html 不存在'" + else + error "部署失败" + exit 1 + fi + ;; + + "help"|"h"|"--help") + echo "前端项目远程部署工具" + echo "" + echo "用法: $0 [命令]" + echo "" + echo "命令:" + echo " deploy/d 完整部署流程(默认)" + echo " test/t 测试连接" + echo " status/s 查看前端项目状态" + echo " check/c 检查前端部署情况" + echo " logs/l 查看Nginx访问日志" + echo " nginx 查看Nginx配置" + echo " portconfig 检查宝塔面板站点配置" + echo " build/b 仅本地构建项目" + echo " pull/p 仅拉取远程代码" + echo " upload/u 仅上传构建文件" + echo " help/h 显示帮助" + ;; + + *) + error "未知命令: $1" + echo "使用 'help' 查看可用命令" + exit 1 + ;; +esac diff --git a/package.json b/package.json index eb69149..e259a08 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "license": "MIT", "scripts": { "dev": "vite --config ./config/vite.config.dev.ts", - "build": "vue-tsc --noEmit && vite build --config ./config/vite.config.prod.ts", + "build": "vue-tsc --noEmit --skipLibCheck && vite build --config ./config/vite.config.prod.ts", "report": "cross-env REPORT=true npm run build", "preview": "npm run build && vite preview --host", "type:check": "vue-tsc --noEmit --skipLibCheck", @@ -55,6 +55,7 @@ "@commitlint/config-conventional": "^17.1.0", "@types/lodash": "^4.14.186", "@types/mockjs": "^1.0.7", + "@types/node": "^24.0.3", "@types/nprogress": "^0.2.0", "@types/sortablejs": "^1.15.0", "@typescript-eslint/eslint-plugin": "^5.40.0", @@ -84,6 +85,7 @@ "stylelint-config-recommended-vue": "^1.5.0", "stylelint-config-standard": "^36.0.1", "stylelint-order": "^6.0.4", + "terser": "^5.43.1", "typescript": "^4.8.4", "unplugin-vue-components": "^0.24.1", "vite": "^3.2.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 968a70d..7231321 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -80,6 +80,9 @@ importers: '@types/mockjs': specifier: ^1.0.7 version: 1.0.10 + '@types/node': + specifier: ^24.0.3 + version: 24.0.3 '@types/nprogress': specifier: ^0.2.0 version: 0.2.3 @@ -94,10 +97,10 @@ importers: version: 5.62.0(eslint@8.57.1)(typescript@4.9.5) '@vitejs/plugin-vue': specifier: ^3.1.2 - version: 3.2.0(vite@3.2.11(@types/node@20.5.1)(less@4.3.0))(vue@3.5.17(typescript@4.9.5)) + version: 3.2.0(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1))(vue@3.5.17(typescript@4.9.5)) '@vitejs/plugin-vue-jsx': specifier: ^2.0.1 - version: 2.1.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0))(vue@3.5.17(typescript@4.9.5)) + version: 2.1.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1))(vue@3.5.17(typescript@4.9.5)) '@vue/babel-plugin-jsx': specifier: ^1.1.1 version: 1.4.0(@babel/core@7.27.4) @@ -167,6 +170,9 @@ importers: stylelint-order: specifier: ^6.0.4 version: 6.0.4(stylelint@16.21.0(typescript@4.9.5)) + terser: + specifier: ^5.43.1 + version: 5.43.1 typescript: specifier: ^4.8.4 version: 4.9.5 @@ -175,16 +181,16 @@ importers: version: 0.24.1(@babel/parser@7.27.5)(@nuxt/kit@3.17.5)(rollup@2.79.2)(vue@3.5.17(typescript@4.9.5)) vite: specifier: ^3.2.5 - version: 3.2.11(@types/node@20.5.1)(less@4.3.0) + version: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) vite-plugin-compression: specifier: ^0.5.1 - version: 0.5.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)) + version: 0.5.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)) vite-plugin-eslint: specifier: ^1.8.1 - version: 1.8.1(eslint@8.57.1)(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)) + version: 1.8.1(eslint@8.57.1)(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)) vite-plugin-imagemin: specifier: ^0.6.1 - version: 0.6.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)) + version: 0.6.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)) vite-svg-loader: specifier: ^3.6.0 version: 3.6.0 @@ -506,6 +512,9 @@ packages: resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} engines: {node: '>=6.0.0'} + '@jridgewell/source-map@0.3.6': + resolution: {integrity: sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==} + '@jridgewell/sourcemap-codec@1.5.0': resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} @@ -1107,6 +1116,9 @@ packages: buffer-fill@1.0.0: resolution: {integrity: sha512-T7zexNBwiiaCOGDg9xNX9PBmjrubblRkENuptryuI64URkXDFum9il/JGL8Lm8wYfAXpredVXXZz7eMHilimiQ==} + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + buffer@5.7.1: resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} @@ -3821,6 +3833,9 @@ packages: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} engines: {node: '>=0.10.0'} + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + source-map@0.6.1: resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} engines: {node: '>=0.10.0'} @@ -4040,6 +4055,11 @@ packages: resolution: {integrity: sha512-ZOn6nJUgvgC09+doCEF3oB+r3ag7kUvlsXEGX069QRD60p+P3uP7XG9N2/at+EyIRGSN//ZY3LyEotA1YpmjuA==} engines: {node: '>=4'} + terser@5.43.1: + resolution: {integrity: sha512-+6erLbBm0+LROX2sPXlUYx/ux5PyE9K/a92Wrt6oA+WDAoFTdpHE5tCYCI5PNzq2y8df4rA+QgHLJuR4jNymsg==} + engines: {node: '>=10'} + hasBin: true + text-extensions@1.9.0: resolution: {integrity: sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ==} engines: {node: '>=0.10'} @@ -4733,7 +4753,7 @@ snapshots: '@types/node': 20.5.1 chalk: 4.1.2 cosmiconfig: 8.3.6(typescript@4.9.5) - cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5))(typescript@4.9.5) + cosmiconfig-typescript-loader: 4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5))(typescript@4.9.5) lodash.isplainobject: 4.0.6 lodash.merge: 4.6.2 lodash.uniq: 4.5.0 @@ -4890,6 +4910,11 @@ snapshots: '@jridgewell/set-array@1.2.1': {} + '@jridgewell/source-map@0.3.6': + dependencies: + '@jridgewell/gen-mapping': 0.3.8 + '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/sourcemap-codec@1.5.0': {} '@jridgewell/trace-mapping@0.3.25': @@ -5214,19 +5239,19 @@ snapshots: '@unrs/resolver-binding-win32-x64-msvc@1.9.2': optional: true - '@vitejs/plugin-vue-jsx@2.1.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0))(vue@3.5.17(typescript@4.9.5))': + '@vitejs/plugin-vue-jsx@2.1.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1))(vue@3.5.17(typescript@4.9.5))': dependencies: '@babel/core': 7.27.4 '@babel/plugin-transform-typescript': 7.27.1(@babel/core@7.27.4) '@vue/babel-plugin-jsx': 1.4.0(@babel/core@7.27.4) - vite: 3.2.11(@types/node@20.5.1)(less@4.3.0) + vite: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) vue: 3.5.17(typescript@4.9.5) transitivePeerDependencies: - supports-color - '@vitejs/plugin-vue@3.2.0(vite@3.2.11(@types/node@20.5.1)(less@4.3.0))(vue@3.5.17(typescript@4.9.5))': + '@vitejs/plugin-vue@3.2.0(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1))(vue@3.5.17(typescript@4.9.5))': dependencies: - vite: 3.2.11(@types/node@20.5.1)(less@4.3.0) + vite: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) vue: 3.5.17(typescript@4.9.5) '@volar/language-core@1.11.1': @@ -5586,6 +5611,8 @@ snapshots: buffer-fill@1.0.0: {} + buffer-from@1.1.2: {} + buffer@5.7.1: dependencies: base64-js: 1.5.1 @@ -5812,7 +5839,7 @@ snapshots: core-util-is@1.0.3: {} - cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@20.5.1)(typescript@4.9.5))(typescript@4.9.5): + cosmiconfig-typescript-loader@4.4.0(@types/node@20.5.1)(cosmiconfig@8.3.6(typescript@4.9.5))(ts-node@10.9.2(@types/node@24.0.3)(typescript@4.9.5))(typescript@4.9.5): dependencies: '@types/node': 20.5.1 cosmiconfig: 8.3.6(typescript@4.9.5) @@ -8409,6 +8436,11 @@ snapshots: source-map-js@1.2.1: {} + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + source-map@0.6.1: {} source-map@0.7.4: {} @@ -8671,6 +8703,13 @@ snapshots: temp-dir: 1.0.0 uuid: 3.4.0 + terser@5.43.1: + dependencies: + '@jridgewell/source-map': 0.3.6 + acorn: 8.15.0 + commander: 2.20.3 + source-map-support: 0.5.21 + text-extensions@1.9.0: {} text-table@0.2.0: {} @@ -8940,24 +8979,24 @@ snapshots: spdx-correct: 3.2.0 spdx-expression-parse: 3.0.1 - vite-plugin-compression@0.5.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)): + vite-plugin-compression@0.5.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)): dependencies: chalk: 4.1.2 debug: 4.4.1 fs-extra: 10.1.0 - vite: 3.2.11(@types/node@20.5.1)(less@4.3.0) + vite: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) transitivePeerDependencies: - supports-color - vite-plugin-eslint@1.8.1(eslint@8.57.1)(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)): + vite-plugin-eslint@1.8.1(eslint@8.57.1)(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)): dependencies: '@rollup/pluginutils': 4.2.1 '@types/eslint': 8.56.12 eslint: 8.57.1 rollup: 2.79.2 - vite: 3.2.11(@types/node@20.5.1)(less@4.3.0) + vite: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) - vite-plugin-imagemin@0.6.1(vite@3.2.11(@types/node@20.5.1)(less@4.3.0)): + vite-plugin-imagemin@0.6.1(vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1)): dependencies: '@types/imagemin': 7.0.1 '@types/imagemin-gifsicle': 7.0.4 @@ -8982,7 +9021,7 @@ snapshots: imagemin-webp: 6.1.0 jpegtran-bin: 6.0.1 pathe: 0.2.0 - vite: 3.2.11(@types/node@20.5.1)(less@4.3.0) + vite: 3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1) transitivePeerDependencies: - supports-color @@ -8991,16 +9030,17 @@ snapshots: '@vue/compiler-sfc': 3.5.17 svgo: 2.8.0 - vite@3.2.11(@types/node@20.5.1)(less@4.3.0): + vite@3.2.11(@types/node@24.0.3)(less@4.3.0)(terser@5.43.1): dependencies: esbuild: 0.15.18 postcss: 8.5.6 resolve: 1.22.10 rollup: 2.79.2 optionalDependencies: - '@types/node': 20.5.1 + '@types/node': 24.0.3 fsevents: 2.3.3 less: 4.3.0 + terser: 5.43.1 vue-demi@0.13.11(vue@3.5.17(typescript@4.9.5)): dependencies: diff --git a/src/components/menu/index.vue b/src/components/menu/index.vue index e0cd7b3..190e9e7 100644 --- a/src/components/menu/index.vue +++ b/src/components/menu/index.vue @@ -141,6 +141,7 @@ onCollapse={setCollapse} > {renderSubMenu()} + // @ts-ignore ); }, diff --git a/src/router/guard/permission.ts b/src/router/guard/permission.ts index ad3724e..983963d 100644 --- a/src/router/guard/permission.ts +++ b/src/router/guard/permission.ts @@ -45,8 +45,10 @@ export default function setupPermissionGuard(router: Router) { if (permissionsAllow) next(); else { const destination = - Permission.findFirstPermissionRoute(appRoutes, userStore.role) || - NOT_FOUND; + Permission.findFirstPermissionRoute( + appRoutes, + userStore.permission + ) || NOT_FOUND; next(destination); } } diff --git a/src/types/arco-design.d.ts b/src/types/arco-design.d.ts new file mode 100644 index 0000000..8e22a3b --- /dev/null +++ b/src/types/arco-design.d.ts @@ -0,0 +1,228 @@ +// 为Arco Design Vue组件提供更全面的类型定义 +import { DefineComponent } from 'vue'; + +// 通用属性类型,可以被Arco组件共享 +interface ArcoBaseProps { + [key: string]: unknown; +} + +// 定义各种Arco组件的类型接口 +export interface ArcoMenuProps extends ArcoBaseProps { + 'mode'?: 'horizontal' | 'vertical' | 'pop' | 'popButton'; + 'collapsed'?: boolean; + 'openKeys'?: string[]; + 'selectedKeys'?: string[]; + 'autoOpen'?: boolean; + 'autoOpenSelected'?: boolean; + 'levelIndent'?: number; + 'showCollapseButton'?: boolean; + 'onCollapse'?: (collapsed: boolean) => void; + 'v-model:collapsed'?: boolean; + 'v-model:open-keys'?: string[]; + 'v-slots'?: Record; +} + +export interface ArcoSubMenuProps extends ArcoBaseProps { + 'key'?: string | number | symbol; + 'title'?: string | (() => unknown); + 'selectable'?: boolean; + 'v-slots'?: Record; +} + +export interface ArcoMenuItemProps extends ArcoBaseProps { + 'key'?: string | number | symbol; + 'disabled'?: boolean; + 'onClick'?: (event: Event) => void; + 'v-slots'?: Record; +} + +// 其他常用Arco组件类型定义 +export interface ArcoCardProps extends ArcoBaseProps { + 'title'?: string; + 'bordered'?: boolean; + 'hoverable'?: boolean; + 'loading'?: boolean; + 'size'?: 'small' | 'medium' | 'large'; + 'v-slots'?: Record; +} + +export interface ArcoButtonProps extends ArcoBaseProps { + type?: 'primary' | 'secondary' | 'outline' | 'dashed' | 'text'; + status?: 'normal' | 'success' | 'warning' | 'danger'; + size?: 'mini' | 'small' | 'medium' | 'large'; + shape?: 'square' | 'circle' | 'round'; + loading?: boolean; + disabled?: boolean; + onClick?: (event: Event) => void; +} + +export interface ArcoLayoutProps extends ArcoBaseProps { + 'v-slots'?: Record; +} + +export interface ArcoFormProps extends ArcoBaseProps { + 'model'?: Record; + 'layout'?: 'horizontal' | 'vertical' | 'inline'; + 'size'?: 'mini' | 'small' | 'medium' | 'large'; + 'labelColProps'?: Record; + 'wrapperColProps'?: Record; + 'v-slots'?: Record; +} + +export interface ArcoFormItemProps extends ArcoBaseProps { + 'field'?: string; + 'label'?: string; + 'required'?: boolean; + 'rules'?: unknown[]; + 'validateStatus'?: 'success' | 'error' | 'validating'; + 'v-slots'?: Record; +} + +export interface ArcoTableProps extends ArcoBaseProps { + 'columns'?: unknown[]; + 'data'?: unknown[]; + 'pagination'?: boolean | object; + 'loading'?: boolean; + 'rowKey'?: string | ((record: unknown) => string); + 'v-slots'?: Record; +} + +export interface ArcoTableColumnProps extends ArcoBaseProps { + 'title'?: string; + 'dataIndex'?: string; + 'width'?: number | string; + 'align'?: 'left' | 'center' | 'right'; + 'fixed'?: 'left' | 'right'; + 'v-slots'?: Record; +} + +export interface ArcoSelectProps extends ArcoBaseProps { + 'modelValue'?: unknown; + 'options'?: unknown[]; + 'multiple'?: boolean; + 'disabled'?: boolean; + 'loading'?: boolean; + 'placeholder'?: string; + 'v-slots'?: Record; +} + +export interface ArcoOptionProps extends ArcoBaseProps { + 'value'?: unknown; + 'label'?: string; + 'disabled'?: boolean; + 'v-slots'?: Record; +} + +// 声明全局JSX类型 +declare global { + namespace JSX { + interface IntrinsicElements { + // 基础组件 + 'a-button': ArcoButtonProps; + 'a-card': ArcoCardProps; + 'a-menu': ArcoMenuProps; + 'a-menu-item': ArcoMenuItemProps; + 'a-sub-menu': ArcoSubMenuProps; + + // 布局组件 + 'a-layout': ArcoLayoutProps; + 'a-layout-header': ArcoBaseProps; + 'a-layout-content': ArcoBaseProps; + 'a-layout-footer': ArcoBaseProps; + 'a-layout-sider': ArcoBaseProps; + 'a-row': ArcoBaseProps; + 'a-col': ArcoBaseProps; + 'a-space': ArcoBaseProps; + 'a-divider': ArcoBaseProps; + + // 表单组件 + 'a-form': ArcoFormProps; + 'a-form-item': ArcoFormItemProps; + 'a-input': ArcoBaseProps; + 'a-textarea': ArcoBaseProps; + 'a-select': ArcoSelectProps; + 'a-option': ArcoOptionProps; + 'a-radio': ArcoBaseProps; + 'a-radio-group': ArcoBaseProps; + 'a-checkbox': ArcoBaseProps; + 'a-checkbox-group': ArcoBaseProps; + 'a-switch': ArcoBaseProps; + + // 数据展示组件 + 'a-table': ArcoTableProps; + 'a-table-column': ArcoTableColumnProps; + 'a-pagination': ArcoBaseProps; + 'a-tabs': ArcoBaseProps; + 'a-tab-pane': ArcoBaseProps; + 'a-dropdown': ArcoBaseProps; + 'a-dropdown-menu': ArcoBaseProps; + 'a-dropdown-item': ArcoBaseProps; + 'a-badge': ArcoBaseProps; + 'a-tag': ArcoBaseProps; + + // 反馈组件 + 'a-modal': ArcoBaseProps; + 'a-drawer': ArcoBaseProps; + 'a-alert': ArcoBaseProps; + 'a-spin': ArcoBaseProps; + 'a-progress': ArcoBaseProps; + 'a-result': ArcoBaseProps; + } + } +} + +// 扩展Vue的类型定义 +declare module '@vue/runtime-core' { + export interface GlobalComponents { + // 基础组件 + AButton: DefineComponent; + ACard: DefineComponent; + AMenu: DefineComponent; + AMenuItem: DefineComponent; + ASubMenu: DefineComponent; + + // 布局组件 + ALayout: DefineComponent; + ALayoutHeader: DefineComponent; + ALayoutContent: DefineComponent; + ALayoutFooter: DefineComponent; + ALayoutSider: DefineComponent; + ARow: DefineComponent; + ACol: DefineComponent; + ASpace: DefineComponent; + ADivider: DefineComponent; + + // 表单组件 + AForm: DefineComponent; + AFormItem: DefineComponent; + AInput: DefineComponent; + ATextarea: DefineComponent; + ASelect: DefineComponent; + AOption: DefineComponent; + ARadio: DefineComponent; + ARadioGroup: DefineComponent; + ACheckbox: DefineComponent; + ACheckboxGroup: DefineComponent; + ASwitch: DefineComponent; + + // 数据展示组件 + ATable: DefineComponent; + ATableColumn: DefineComponent; + APagination: DefineComponent; + ATabs: DefineComponent; + ATabPane: DefineComponent; + ADropdown: DefineComponent; + ADropdownMenu: DefineComponent; + ADropdownItem: DefineComponent; + ABadge: DefineComponent; + ATag: DefineComponent; + + // 反馈组件 + AModal: DefineComponent; + ADrawer: DefineComponent; + AAlert: DefineComponent; + ASpin: DefineComponent; + AProgress: DefineComponent; + AResult: DefineComponent; + } +} diff --git a/src/types/shims-tsx.d.ts b/src/types/shims-tsx.d.ts new file mode 100644 index 0000000..cee7e81 --- /dev/null +++ b/src/types/shims-tsx.d.ts @@ -0,0 +1,57 @@ +// 为了支持Vue JSX和Arco Design Vue组件,我们需要适当扩展类型声明 + +// 引入Vue运行时核心类型 +import 'vue'; + +// 为Arco Design Vue组件定义基础接口 +interface ArcoMenuProps { + 'mode'?: 'horizontal' | 'vertical' | 'pop' | 'popButton'; + 'collapsed'?: boolean; + 'openKeys'?: string[]; + 'selectedKeys'?: string[]; + 'autoOpen'?: boolean; + 'autoOpenSelected'?: boolean; + 'levelIndent'?: number; + 'showCollapseButton'?: boolean; + 'onCollapse'?: (collapsed: boolean) => void; + 'v-model:collapsed'?: boolean; + 'v-model:open-keys'?: string[]; + 'v-slots'?: Record; + [key: string]: unknown; +} + +interface ArcoSubMenuProps { + 'key'?: string | number; + 'title'?: string | (() => unknown); + 'selectable'?: boolean; + 'v-slots'?: Record; + [key: string]: unknown; +} + +interface ArcoMenuItemProps { + 'key'?: string | number; + 'disabled'?: boolean; + 'onClick'?: (event: Event) => void; + 'v-slots'?: Record; + [key: string]: unknown; +} + +// 扩展Vue的类型定义 +declare module '@vue/runtime-core' { + export interface GlobalComponents { + AMenu: ArcoMenuProps; + AMenuItem: ArcoMenuItemProps; + ASubMenu: ArcoSubMenuProps; + } +} + +// 扩展全局JSX声明 +declare global { + namespace JSX { + interface IntrinsicElements { + 'a-menu': ArcoMenuProps; + 'a-menu-item': ArcoMenuItemProps; + 'a-sub-menu': ArcoSubMenuProps; + } + } +} diff --git a/src/views/redirect/index.vue b/src/views/redirect/index.vue new file mode 100644 index 0000000..386f877 --- /dev/null +++ b/src/views/redirect/index.vue @@ -0,0 +1,23 @@ + diff --git a/src/views/result/error/index.vue b/src/views/result/error/index.vue new file mode 100644 index 0000000..a5c9df3 --- /dev/null +++ b/src/views/result/error/index.vue @@ -0,0 +1,44 @@ + + + + + diff --git a/src/views/result/success/index.vue b/src/views/result/success/index.vue new file mode 100644 index 0000000..475589f --- /dev/null +++ b/src/views/result/success/index.vue @@ -0,0 +1,51 @@ + + + + + diff --git a/src/views/user/info/index.vue b/src/views/user/info/index.vue new file mode 100644 index 0000000..3d8c0fd --- /dev/null +++ b/src/views/user/info/index.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/src/views/user/setting/index.vue b/src/views/user/setting/index.vue new file mode 100644 index 0000000..a5cad94 --- /dev/null +++ b/src/views/user/setting/index.vue @@ -0,0 +1,149 @@ + + + + + diff --git a/src/views/visualization/data-analysis/index.vue b/src/views/visualization/data-analysis/index.vue new file mode 100644 index 0000000..de22ba0 --- /dev/null +++ b/src/views/visualization/data-analysis/index.vue @@ -0,0 +1,257 @@ + + + + + diff --git a/src/views/visualization/multi-dimension-data-analysis/index.vue b/src/views/visualization/multi-dimension-data-analysis/index.vue new file mode 100644 index 0000000..367a6a3 --- /dev/null +++ b/src/views/visualization/multi-dimension-data-analysis/index.vue @@ -0,0 +1,298 @@ + + + + + diff --git a/tsconfig.json b/tsconfig.json index fb581aa..989ae61 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,6 +1,6 @@ { "compilerOptions": { - "target": "ESNext", + "target": "ESNext", "module": "ESNext", "moduleResolution": "node", "resolveJsonModule": true, @@ -8,6 +8,8 @@ "strict": true, "strictNullChecks": true, "jsx": "preserve", + "jsxFactory": "h", + "jsxFragmentFactory": "Fragment", "baseUrl": ".", "paths": { "@/*": [ @@ -16,9 +18,12 @@ }, "lib": [ "esnext", - "dom" + "dom", + "dom.iterable" ], "skipLibCheck": true, + "noImplicitAny": false, + "allowJs": true, "types": [ "vite/client", "node"