diff --git a/.env.development b/.env.development
index 9b1fef53..73f7934b 100644
--- a/.env.development
+++ b/.env.development
@@ -2,5 +2,7 @@
ENV = 'development'
# base api
-VUE_APP_BASE_API = 'http://localhost:8000'
+VUE_APP_BASE_API = 'http://localhost:8001'
+# Suppress Sass deprecation warnings
+SASS_SILENCE_DEPRECATIONS = 'legacy-js-api'
diff --git a/.env.production b/.env.production
index 8994f694..9cbf6032 100644
--- a/.env.production
+++ b/.env.production
@@ -4,3 +4,5 @@ ENV = 'production'
# base api
VUE_APP_BASE_API = ''
+# Suppress Sass deprecation warnings
+SASS_SILENCE_DEPRECATIONS = 'legacy-js-api'
diff --git a/.eslintrc.js b/.eslintrc.js
index a0c1c709..cb958871 100644
--- a/.eslintrc.js
+++ b/.eslintrc.js
@@ -1,31 +1,35 @@
module.exports = {
root: true,
parserOptions: {
- parser: 'babel-eslint',
- sourceType: 'module'
+ parser: '@babel/eslint-parser',
+ sourceType: 'module',
+ requireConfigFile: false
},
env: {
browser: true,
node: true,
es6: true
},
- extends: ['plugin:vue/recommended', 'eslint:recommended'],
+ extends: ['plugin:vue/vue3-recommended', 'eslint:recommended'],
// add your custom rules here
// it is base on https://github.com/vuejs/eslint-config-vue
rules: {
'vue/max-attributes-per-line': [2, {
- 'singleline': 10,
+ 'singleline': {
+ 'max': 10
+ },
'multiline': {
- 'max': 1,
- 'allowFirstLine': false
+ 'max': 1
}
}],
'vue/no-template-shadow': 'off',
'vue/singleline-html-element-content-newline': 'off',
'vue/multiline-html-element-content-newline': 'off',
- 'vue/name-property-casing': ['error', 'PascalCase'],
'vue/no-v-html': 'off',
+ // Vue 3 规则调整
+ 'vue/no-deprecated-slot-attribute': 'warn',
+ 'vue/multi-word-component-names': 'warn',
'accessor-pairs': 2,
'arrow-spacing': [2, {
'before': true,
diff --git a/.gitignore b/.gitignore
index 78a752d8..b9ca6a66 100644
--- a/.gitignore
+++ b/.gitignore
@@ -21,3 +21,7 @@ selenium-debug.log
package-lock.json
yarn.lock
+
+# Claude Code
+CLAUDE.md
+.claude/
diff --git a/UPGRADE_TO_VUE3.md b/UPGRADE_TO_VUE3.md
new file mode 100644
index 00000000..eb6a6e22
--- /dev/null
+++ b/UPGRADE_TO_VUE3.md
@@ -0,0 +1,75 @@
+# go-admin-ui Vue3 升级实施文档
+
+## 1. 项目分支说明
+当前升级分支:`dev-to-vue3`
+
+## 2. 升级目标
+- Vue 2.x → Vue 3.x
+- Element UI → Element Plus
+- Babel、Webpack、ESLint、Jest 等工具包升级
+- 其他安全性相关依赖(如 axios、lodash)升级
+- **Node.js 版本升级**:从 >=8.9 升级到 >=18.0(推荐 LTS 版本)
+
+## 3. 升级实施阶段
+
+### 阶段零:环境准备(0.5 天) ✅ 已完成
+- 检查当前 Node.js 版本(当前 v18.20.1 ✅)
+- 升级 Node.js 到最新 LTS 版本(已满足要求)
+- 升级 npm 到最新版本(已满足要求)
+- 验证新环境下的项目能否正常运行基础命令(如 `npm install` ✅)
+
+### 阶段一:准备与调研 ✅ 已完成
+- 备份当前代码,确保可回滚。
+- 盘点所有依赖,确认升级目标版本。
+- 使用 npm-check-updates 生成升级清单 ✅
+- 执行次要版本依赖升级 ✅
+- 解决依赖冲突并安装新版本 ✅
+- 验证项目基础功能(lint、test)✅
+
+### 阶段二:依赖升级
+- 使用 npm-check-updates 或手动修改 `package.json`,升级核心依赖。
+- 执行 `npm install`,解决依赖冲突。
+- 升级 Babel、Webpack、ESLint、Jest、axios、lodash 等工具包。
+
+### 阶段三:代码适配与重构
+- 全面适配 Vue 3 语法(如 Composition API、生命周期钩子变更)。
+- 替换 Element UI 为 Element Plus,调整组件用法。
+- 升级 vue-router、vuex,并适配新 API。
+- 检查第三方库兼容性,必要时替换或移除。
+
+### 阶段四:配置文件调整
+- 更新 babel.config.js、webpack、eslint、jest 等配置文件。
+- 检查并调整 polyfill、postcss、plop 等相关配置。
+
+### 阶段五:测试与回归
+- 运行单元测试,修复因升级导致的测试失败。
+- 手动回归主要功能页面,确保无异常。
+- 检查打包、部署流程是否正常。
+
+### 阶段六:文档与说明
+- 更新 README.md,说明升级内容及注意事项。
+- 补充迁移指南,便于团队成员理解变更。
+
+### 阶段七:评审与合并
+- 团队代码评审,确认无重大问题后合并至主分支。
+
+## 4. 当前进度总结
+- ✅ Node.js 环境检查完成(v18.20.1)
+- ✅ 依赖盘点完成,生成了 68 个可升级项
+- ✅ 次要版本依赖升级完成(patch/minor 版本)
+- ✅ 依赖安装成功,项目可正常运行
+- ✅ ESLint 验证通过(发现 35 个问题,多数为代码风格问题)
+- ⚠️ 单元测试部分失败(9 个失败,14 个通过),主要问题:
+ - `time_str` 变量初始化问题(src/utils/index.js)
+ - @vue/test-utils `contains` 方法弃用(测试代码需更新)
+
+## 5. 参考迁移资源
+- [Vue 2 → Vue 3 官方迁移指南](https://v3-migration.vuejs.org/)
+- [Element UI → Element Plus 迁移文档](https://element-plus.org/zh-CN/guide/migration.html)
+- [vue-router 4.x 文档](https://router.vuejs.org/)
+- [vuex 4.x 文档](https://vuex.vuejs.org/)
+- [Node.js LTS 版本说明](https://nodejs.org/en/about/releases/)
+
+---
+
+> 后续所有升级、重构、测试等工作请严格按照本实施文档分阶段推进。
diff --git a/VUE3_UPGRADE_COMPLETE.md b/VUE3_UPGRADE_COMPLETE.md
new file mode 100644
index 00000000..e69de29b
diff --git a/babel.config.js b/babel.config.js
index 34be5d79..2ed56c9d 100644
--- a/babel.config.js
+++ b/babel.config.js
@@ -2,6 +2,9 @@ module.exports = {
presets: [
'@vue/cli-plugin-babel/preset'
],
+ plugins: [
+ '@vue/babel-plugin-jsx'
+ ],
env: {
development: {
plugins: ['dynamic-import-node']
diff --git a/public/index.html b/index.html
similarity index 97%
rename from public/index.html
rename to index.html
index 7f2be5e2..c0c7b97f 100644
--- a/public/index.html
+++ b/index.html
@@ -6,10 +6,8 @@
-
-
- <%= webpackConfig.name %> - go-admin
-
+
+ go-admin
diff --git a/package-clean.json b/package-clean.json
new file mode 100644
index 00000000..e69de29b
diff --git a/package.json b/package.json
index a5e95d24..97a96456 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,9 @@
"author": "https://github.com/wenjianzhang",
"license": "MIT",
"scripts": {
- "dev": "vue-cli-service serve",
- "build:prod": "vue-cli-service build",
- "build:stage": "vue-cli-service build --mode staging",
+ "dev": "SASS_SILENCE_DEPRECATIONS=legacy-js-api vue-cli-service serve",
+ "build:prod": "SASS_SILENCE_DEPRECATIONS=legacy-js-api vue-cli-service build",
+ "build:stage": "SASS_SILENCE_DEPRECATIONS=legacy-js-api vue-cli-service build --mode staging",
"preview": "node build/index.js --preview",
"lint": "eslint --ext .js,.vue src",
"test:unit": "jest --clearCache && vue-cli-service test:unit",
@@ -45,76 +45,82 @@
"url": "https://github.com/go-admin-team/go-admin/issues"
},
"dependencies": {
- "@riophae/vue-treeselect": "0.4.0",
- "awe-dnd": "^0.3.4",
- "axios": "0.21.1",
- "clipboard": "2.0.6",
- "codemirror": "5.62.0",
- "core-js": "^3.6.5",
+ "@element-plus/icons-vue": "^2.3.2",
+ "@tsparticles/slim": "^3.0.3",
+ "@tsparticles/vue3": "^3.0.1",
+ "@vueuse/core": "^14.2.0",
+ "axios": "^1.6.0",
+ "clipboard": "2.0.11",
+ "codemirror": "^6.0.1",
+ "core-js": "^3.45.1",
"driver.js": "0.9.8",
- "dropzone": "5.7.2",
- "echarts": "4.8.0",
- "element-ui": "2.15.6",
- "file-saver": "2.0.2",
- "fuse.js": "6.4.1",
- "js-cookie": "2.2.1",
+ "dropzone": "5.9.3",
+ "echarts": "^5.5.0",
+ "element-plus": "^2.8.0",
+ "file-saver": "2.0.5",
+ "fuse.js": "6.6.2",
+ "js-cookie": "3.0.5",
"jsonlint": "1.6.3",
- "jszip": "3.5.0",
- "moment": "^2.27.0",
+ "jszip": "3.10.1",
+ "moment": "^2.30.1",
"normalize.css": "8.0.1",
"nprogress": "0.2.0",
- "path-to-regexp": "6.1.0",
+ "path-to-regexp": "6.3.0",
"remixicon": "^2.5.0",
- "sass-resources-loader": "^2.0.3",
- "screenfull": "5.0.2",
- "viser-vue": "^2.4.8",
- "vue": "2.6.11",
- "vue-codemirror": "^4.0.6",
+ "sass-resources-loader": "^2.2.5",
+ "screenfull": "5.2.0",
+ "vue": "^3.4.0",
+ "vue-codemirror": "^6.1.1",
"vue-count-to": "1.0.13",
- "vue-cropper": "^0.5.5",
- "vue-particles": "^1.0.9",
- "vue-router": "3.4.7",
- "vuedraggable": "2.24.0",
- "vuex": "3.5.1",
- "webpack-bundle-analyzer": "^3.8.0",
- "xlsx": "0.16.5"
+ "vue-cropper": "^1.1.3",
+ "vue-router": "^4.4.0",
+ "vue3-dnd": "^2.1.0",
+ "vue3-treeselect": "^0.1.10",
+ "vuedraggable": "^4.1.0",
+ "vuex": "^4.1.0",
+ "webpack-bundle-analyzer": "^3.9.0",
+ "xlsx": "^0.18.5"
},
"devDependencies": {
- "@babel/core": "7.11.1",
- "@babel/register": "^7.10.5",
- "@babel/runtime": "^7.12.1",
- "@vue/babel-preset-app": "^4.5.7",
- "@vue/cli-plugin-babel": "4.4.6",
- "@vue/cli-plugin-eslint": "^4.4.6",
- "@vue/cli-plugin-unit-jest": "4.4.6",
- "@vue/cli-service": "^4.5.13",
- "@vue/test-utils": "1.0.3",
- "autoprefixer": "^9.8.6",
+ "@babel/core": "7.28.3",
+ "@babel/eslint-parser": "^7.28.6",
+ "@babel/register": "^7.28.3",
+ "@babel/runtime": "^7.28.3",
+ "@playwright/test": "^1.60.0",
+ "@vue/babel-plugin-jsx": "^1.5.0",
+ "@vue/babel-preset-app": "^5.0.8",
+ "@vue/cli-plugin-babel": "^5.0.8",
+ "@vue/cli-plugin-eslint": "^5.0.8",
+ "@vue/cli-plugin-unit-jest": "^5.0.8",
+ "@vue/cli-service": "^5.0.8",
+ "@vue/compiler-sfc": "^3.4.0",
+ "@vue/test-utils": "^2.4.0",
+ "autoprefixer": "^9.8.8",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "10.1.0",
- "babel-jest": "26.2.2",
+ "babel-jest": "26.6.3",
"babel-plugin-dynamic-import-node": "^2.3.3",
"beautifier": "^0.1.7",
- "chalk": "4.1.0",
- "chokidar": "3.4.2",
- "compression-webpack-plugin": "^4.0.0",
+ "chalk": "4.1.2",
+ "chokidar": "3.6.0",
+ "compression-webpack-plugin": "^4.0.1",
"connect": "3.7.0",
- "eslint": "7.6.0",
- "eslint-plugin-vue": "6.2.2",
- "html-webpack-plugin": "4.3.0",
- "husky": "4.2.5",
- "lint-staged": "10.2.11",
+ "eslint": "7.32.0",
+ "eslint-plugin-vue": "^9.33.0",
+ "html-webpack-plugin": "4.5.2",
+ "husky": "4.3.8",
+ "lint-staged": "10.5.4",
"mockjs": "1.1.0",
- "plop": "2.7.4",
+ "path-browserify": "^1.0.1",
+ "plop": "2.7.6",
"runjs": "^4.4.2",
- "sass": "^1.35.1",
- "sass-loader": "^9.0.3",
- "script-ext-html-webpack-plugin": "2.1.4",
+ "sass": "^1.91.0",
+ "sass-loader": "^13.3.3",
+ "script-ext-html-webpack-plugin": "2.1.5",
"script-loader": "0.7.2",
- "serve-static": "^1.14.1",
- "svg-sprite-loader": "^5.0.0",
- "svgo": "1.3.2",
- "vue-template-compiler": "2.6.11"
+ "serve-static": "^1.16.2",
+ "svg-sprite-loader": "^5.2.1",
+ "svgo": "1.3.2"
},
"engines": {
"node": ">=8.9",
diff --git a/src/App.vue b/src/App.vue
index e72e75ff..8ed4ca7d 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -6,18 +6,18 @@
-
diff --git a/src/components/Bar.vue b/src/components/Bar.vue
index 22200f90..a5b26bcf 100644
--- a/src/components/Bar.vue
+++ b/src/components/Bar.vue
@@ -1,67 +1,58 @@
diff --git a/src/components/Cell/index.vue b/src/components/Cell/index.vue
index 634dbb54..9832afc3 100644
--- a/src/components/Cell/index.vue
+++ b/src/components/Cell/index.vue
@@ -27,7 +27,7 @@
diff --git a/src/components/Charts/Keyboard.vue b/src/components/Charts/Keyboard.vue
index 0b258f36..cee58846 100644
--- a/src/components/Charts/Keyboard.vue
+++ b/src/components/Charts/Keyboard.vue
@@ -3,7 +3,7 @@
diff --git a/src/components/MiniBar/index.vue b/src/components/MiniBar/index.vue
index 17f600c0..95453e6b 100644
--- a/src/components/MiniBar/index.vue
+++ b/src/components/MiniBar/index.vue
@@ -1,65 +1,58 @@
diff --git a/src/components/MiniProgress/index.vue b/src/components/MiniProgress/index.vue
index ea0cef51..98ab224a 100644
--- a/src/components/MiniProgress/index.vue
+++ b/src/components/MiniProgress/index.vue
@@ -1,11 +1,11 @@
@@ -14,58 +14,53 @@
export default {
name: 'MiniProgress',
props: {
- target: {
- type: Number,
- default: 0
- },
- height: {
- type: String,
- default: '10px'
- },
- color: {
- type: String,
- default: '#13C2C2'
- },
- percentage: {
- type: Number,
- default: 0
- }
+ target: { type: Number, default: 0 },
+ height: { type: String, default: '10px' },
+ color: { type: String, default: 'linear-gradient(90deg, #40a9ff, #1677ff)' },
+ indicatorColor: { type: String, default: '#1677ff' },
+ percentage: { type: Number, default: 0 }
}
}
diff --git a/src/components/Pagination/index.vue b/src/components/Pagination/index.vue
index c815e132..164ce79c 100644
--- a/src/components/Pagination/index.vue
+++ b/src/components/Pagination/index.vue
@@ -1,9 +1,9 @@
@@ -15,55 +15,92 @@
export default {
name: 'RankList',
props: {
- title: {
- type: String,
- default: ''
- },
- list: {
- type: Array,
- default: null
+ title: { type: String, default: '' },
+ list: { type: Array, default: null }
+ },
+ methods: {
+ rankBadgeClass(index) {
+ if (index === 0) return 'rank-badge rank-gold'
+ if (index === 1) return 'rank-badge rank-silver'
+ if (index === 2) return 'rank-badge rank-bronze'
+ return 'rank-badge'
}
}
}
diff --git a/src/components/RightPanel/index.vue b/src/components/RightPanel/index.vue
index 8604c017..d3e266e4 100644
--- a/src/components/RightPanel/index.vue
+++ b/src/components/RightPanel/index.vue
@@ -3,7 +3,7 @@
-
+
@@ -52,7 +52,7 @@ export default {
mounted() {
this.insertToBody()
},
- beforeDestroy() {
+ beforeUnmount() {
const elx = this.$refs.rightPanel
elx.remove()
},
diff --git a/src/components/Screenfull/index.vue b/src/components/Screenfull/index.vue
index e15f7e3b..371b8d9d 100644
--- a/src/components/Screenfull/index.vue
+++ b/src/components/Screenfull/index.vue
@@ -8,7 +8,7 @@
import screenfull from 'screenfull'
export default {
- name: 'Screenfull',
+ name: 'AppScreenfull',
data() {
return {
isFullscreen: false
@@ -17,7 +17,7 @@ export default {
mounted() {
this.init()
},
- beforeDestroy() {
+ beforeUnmount() {
this.destroy()
},
methods: {
diff --git a/src/components/Share/DropdownMenu.vue b/src/components/Share/DropdownMenu.vue
index a629fe9a..7ea59f40 100644
--- a/src/components/Share/DropdownMenu.vue
+++ b/src/components/Share/DropdownMenu.vue
@@ -37,7 +37,7 @@ export default {
}
-
diff --git a/src/layout/components/TagsView/TagsView.vue b/src/layout/components/TagsView/TagsView.vue
index be98a84a..86b03919 100644
--- a/src/layout/components/TagsView/TagsView.vue
+++ b/src/layout/components/TagsView/TagsView.vue
@@ -1,15 +1,18 @@
-
+
@@ -17,35 +20,31 @@
-
+
diff --git a/src/layout/components/TagsView/index.vue b/src/layout/components/TagsView/index.vue
index 6f04f448..5460002e 100644
--- a/src/layout/components/TagsView/index.vue
+++ b/src/layout/components/TagsView/index.vue
@@ -11,17 +11,24 @@
:closable="item.fullPath === '/dashboard' ? false : true"
:name="item.fullPath"
>
-
- {{ item.title }}
-
+
+
+
+ {{ item.title }}
+
+
+