diff --git a/README.md b/README.md index 963085f..8787051 100644 --- a/README.md +++ b/README.md @@ -1,44 +1,158 @@ -# vueadmin -This template should help get you started developing with Vue 3 in Vite. +## 功能特性 -## Recommended IDE Setup +### 1. 权限管理 +- 基于角色的权限控制 (RBAC) +- 动态路由生成 +- 菜单权限过滤 +- 按钮级权限控制 -[VS Code](https://code.visualstudio.com/) + [Vue (Official)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) (and disable Vetur). +### 2. 布局系统 +- 响应式布局设计 +- 顶部导航栏 +- 侧边菜单栏 +- 面包屑导航 +- 标签页导航 +- 设置面板 -## Recommended Browser Setup +### 3. 国际化支持 +- 多语言切换 (中文/英文) +- 动态加载语言包 +- 支持自定义语言扩展 -- Chromium-based browsers (Chrome, Edge, Brave, etc.): - - [Vue.js devtools](https://chromewebstore.google.com/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) - - [Turn on Custom Object Formatter in Chrome DevTools](http://bit.ly/object-formatters) -- Firefox: - - [Vue.js devtools](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/) - - [Turn on Custom Object Formatter in Firefox DevTools](https://fxdx.dev/firefox-devtools-custom-object-formatters/) +### 4. 组件库 +- 自定义表格组件 (scTable) +- 自定义表单组件 (scForm) +- 自定义上传组件 (scUpload) +- 其他常用业务组件 -## Customize configuration +### 5. 系统功能 +- 用户登录/注册/重置密码 +- 仪表盘 +- 系统设置 +- 用户管理 +- 角色管理 +- 菜单管理 +- 区域管理 -See [Vite Configuration Reference](https://vite.dev/config/). +## 安装和运行 -## Project Setup +### 环境要求 +- Node.js >= 20.19.0 || >= 22.12.0 -```sh -yarn +### 安装依赖 + +```bash +npm install ``` -### Compile and Hot-Reload for Development +### 开发模式 -```sh -yarn dev +```bash +npm run dev ``` -### Compile and Minify for Production +项目将在 `http://localhost:5173` 启动。 -```sh -yarn build +### 构建生产版本 + +```bash +npm run build ``` -### Lint with [ESLint](https://eslint.org/) +构建后的文件将输出到 `dist` 目录。 -```sh -yarn lint +### 预览生产版本 + +```bash +npm run preview ``` + +### 代码检查和格式化 + +```bash +# ESLint 检查并修复 +npm run lint + +# Prettier 格式化代码 +npm run format +``` + +## 配置说明 + +项目的主要配置文件位于 `src/config/index.js`,包含以下配置项: + +```javascript +{ + APP_NAME: 'vueadmin', // 应用名称 + DASHBOARD_URL: '/dashboard', // 仪表盘URL + API_URL: 'https://www.tensent.cn/admin/', // API接口地址 + TIMEOUT: 50000, // 请求超时时间 + TOKEN_NAME: 'authorization', // Token名称 + TOKEN_PREFIX: 'Bearer ', // Token前缀 + LANG: 'zh-cn', // 默认语言 + // 更多配置... +} +``` + +## 开发指南 + +### 路由配置 + +路由配置分为两部分: +1. 系统基础路由 (`src/router/systemRoutes.js`) +2. 动态生成的业务路由 (由后端菜单数据转换) + +### 组件开发 + +自定义组件位于 `src/components/` 目录,每个组件有独立的文件夹,包含组件文件和相关资源。 + +### API 调用 + +API 接口定义位于 `src/api/` 目录,使用 Axios 封装,支持拦截器、请求缓存等功能。 + +### 状态管理 + +使用 Pinia 进行状态管理,store 定义位于 `src/stores/` 目录,支持模块化管理。 + +## 国际化 + +国际化配置位于 `src/i18n/` 目录,支持中英文切换,可通过以下方式扩展其他语言: + +1. 在 `src/i18n/locales/` 目录下添加新的语言文件 +2. 在 `src/i18n/index.js` 中注册新语言 + +## 权限管理 + +系统采用基于角色的权限控制 (RBAC),权限信息由后端提供,前端根据权限信息动态生成路由和菜单。 + +## 浏览器支持 + +- Chrome (最新版本) +- Firefox (最新版本) +- Safari (最新版本) +- Edge (最新版本) + +## 注意事项 + +1. 确保 Node.js 版本符合要求 +2. 开发环境下 API 请求可能需要配置代理 +3. 生产环境需要配置正确的 API 地址 +4. 首次运行需要先安装依赖 + +## License + +MIT License + +## 更新日志 + +### v1.6.6 +- 升级 Vue 3 到 3.5.26 +- 升级 Vite 到 7.3.0 +- 升级 Ant Design Vue 到 4.2.6 +- 优化路由管理和权限控制 +- 修复已知 bug + +### 贡献 + +欢迎提交 Issue 和 Pull Request 来帮助改进这个项目! \ No newline at end of file diff --git a/src/App.vue b/src/App.vue index 13eac6f..a9755bb 100644 --- a/src/App.vue +++ b/src/App.vue @@ -66,21 +66,3 @@ onMounted(() => { - - diff --git a/src/api/auth.js b/src/api/auth.js index 0e34f7b..97767af 100644 --- a/src/api/auth.js +++ b/src/api/auth.js @@ -1,34 +1,34 @@ -import request from '../utils/request' +import request from '@/utils/request' -/** - * 用户登录 - * @returns {Promise} 菜单数据 - */ -export function userLogin(params) { - return request({ - url: '/auth/login', - method: 'post', - data: params - }) -} - -export function userLogout() { - return request({ - url: '/auth/logout', - method: 'get' - }) -} - -export function getUserInfo() { - return request({ - url: '/auth/user', - method: 'get' - }) -} - -export function getMyMenu(){ - return request({ - url: `auth/menu/my`, - method: 'get' - }) +export default { + login: { + url: `auth/login`, + name: '用户登录', + post: async function (params) { + return await request.post(this.url, params) + }, + }, + logout: { + url: `auth/logout`, + name: '用户登出', + get: async function () { + return await request.get(this.url) + }, + }, + user: { + url: `auth/user`, + name: '获取用户信息', + get: async function () { + return await request.get(this.url) + }, + }, + menu: { + my: { + url: `auth/menu/my`, + name: '获取我的菜单', + get: async function () { + return await request.get(this.url) + }, + }, + }, } diff --git a/src/api/system.js b/src/api/system.js index 1abc194..4e7bd73 100644 --- a/src/api/system.js +++ b/src/api/system.js @@ -18,8 +18,8 @@ export default { info: { url: `system/index/info`, name: '系统信息', - get: function (data) { - return request.get(this.url, data) + get: function (params) { + return request.get(this.url, { params }) }, }, setting: { @@ -27,14 +27,14 @@ export default { url: `system/setting/index`, name: '获取配置信息', get: function (params) { - return request.get(this.url, params) + return request.get(this.url, { params }) }, }, fields: { url: `system/setting/fields`, name: '获取配置字段', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, add: { @@ -64,7 +64,7 @@ export default { url: `system/dict/category`, name: '获取字典树', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, editcate: { @@ -92,14 +92,14 @@ export default { url: `system/dict/lists`, name: '字典明细', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, get: { url: `system/dict/detail`, name: '获取字典数据', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, edit: { @@ -127,14 +127,14 @@ export default { url: `system/dict/detail`, name: '字典明细', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, alldic: { url: `system/dict/all`, name: '全部字典', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, }, @@ -175,7 +175,7 @@ export default { url: `system/client/index`, name: '客户端列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, add: { @@ -204,7 +204,7 @@ export default { url: `system/menu/index`, name: '客户端菜单列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, add: { @@ -235,14 +235,14 @@ export default { url: `system/log/index`, name: '日志列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, my: { url: `system/log/my`, name: '我的日志', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, delete: { @@ -258,7 +258,7 @@ export default { url: `system/tasks/index`, name: '任务列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, delete: { @@ -274,7 +274,7 @@ export default { url: `system/crontab/index`, name: '定时任务列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, add: { @@ -302,7 +302,7 @@ export default { url: `system/crontab/log`, name: '定时任务日志', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, reload: { @@ -318,7 +318,7 @@ export default { url: `system/modules/index`, name: '模块列表', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, update: { @@ -334,7 +334,7 @@ export default { url: `system/sms/count`, name: '短信发送统计', get: async function (params) { - return await request.get(this.url, params) + return await request.get(this.url, { params }) }, }, }, diff --git a/src/assets/style/app.scss b/src/assets/style/app.scss new file mode 100644 index 0000000..1eb3915 --- /dev/null +++ b/src/assets/style/app.scss @@ -0,0 +1,29 @@ +* { + margin: 0; + padding: 0; + box-sizing: border-box; +} + +body { + font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +#app { + min-height: 100vh; +} + +.pages{ + flex: 1; + display: flex; + flex-direction: column; + background-color: #ffffff; + padding: 10px; + border-radius: 10px; + .search-box{ + padding: 10px; + background-color: #f5f5f5; + border-radius: 10px; + } +} diff --git a/src/components/scTable/index.vue b/src/components/scTable/index.vue index e7ad37a..7c7d21e 100644 --- a/src/components/scTable/index.vue +++ b/src/components/scTable/index.vue @@ -256,18 +256,22 @@ const tableContent = useTemplateRef('tableContent') let scroll = ref({ scrollToFirstRowOnChange: true, x: 'max-content', - y: 100, + y: true, }) onMounted(() => { - let tableHeight = 100 + updateTableHeight() +}) + +const updateTableHeight = () => { + let tableHeight = 0 if (props.pagination !== false) { - tableHeight = tableContent.value.clientHeight - 100 + tableHeight = tableContent.value.clientHeight - 105 } else { tableHeight = tableContent.value.clientHeight - 65 } scroll.value.y = tableHeight -}) +} // 根据表格宽度优化横向滚动配置 watch( diff --git a/src/layouts/index.vue b/src/layouts/index.vue index aa6d9c6..ab70c7b 100644 --- a/src/layouts/index.vue +++ b/src/layouts/index.vue @@ -344,6 +344,8 @@ onMounted(() => { overflow-y: auto; flex: 1; height: calc(100vh - 106px); + display: flex; + flex-direction: column; } /* 默认布局 - 双栏菜单 */ diff --git a/src/main.js b/src/main.js index f36103c..e70ebe6 100644 --- a/src/main.js +++ b/src/main.js @@ -2,6 +2,7 @@ import { createApp } from 'vue' import Antd from 'ant-design-vue' import 'ant-design-vue/dist/reset.css' +import '@/assets/style/app.scss' import App from './App.vue' import router from './router' import pinia from './stores' diff --git a/src/pages/auth/department/index.vue b/src/pages/auth/department/index.vue new file mode 100644 index 0000000..f33e786 --- /dev/null +++ b/src/pages/auth/department/index.vue @@ -0,0 +1,155 @@ + + + diff --git a/src/pages/auth/department/save.vue b/src/pages/auth/department/save.vue new file mode 100644 index 0000000..2595d5c --- /dev/null +++ b/src/pages/auth/department/save.vue @@ -0,0 +1,103 @@ + + + diff --git a/src/pages/auth/permission/index.vue b/src/pages/auth/permission/index.vue new file mode 100644 index 0000000..acd266d --- /dev/null +++ b/src/pages/auth/permission/index.vue @@ -0,0 +1,170 @@ + + + + + diff --git a/src/pages/auth/permission/save.vue b/src/pages/auth/permission/save.vue new file mode 100644 index 0000000..9e4cd97 --- /dev/null +++ b/src/pages/auth/permission/save.vue @@ -0,0 +1,209 @@ + + + + + diff --git a/src/pages/auth/role/index.vue b/src/pages/auth/role/index.vue new file mode 100644 index 0000000..f384467 --- /dev/null +++ b/src/pages/auth/role/index.vue @@ -0,0 +1,173 @@ + + + diff --git a/src/pages/auth/role/permission.vue b/src/pages/auth/role/permission.vue new file mode 100644 index 0000000..f8d3c0e --- /dev/null +++ b/src/pages/auth/role/permission.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/src/pages/auth/role/save.vue b/src/pages/auth/role/save.vue new file mode 100644 index 0000000..fa68871 --- /dev/null +++ b/src/pages/auth/role/save.vue @@ -0,0 +1,121 @@ + + + + + diff --git a/src/pages/auth/user/index.vue b/src/pages/auth/user/index.vue index 8e3cfb6..c9deb3b 100644 --- a/src/pages/auth/user/index.vue +++ b/src/pages/auth/user/index.vue @@ -1,180 +1,218 @@ - - diff --git a/src/pages/auth/user/role.vue b/src/pages/auth/user/role.vue new file mode 100644 index 0000000..5d2ee3a --- /dev/null +++ b/src/pages/auth/user/role.vue @@ -0,0 +1,78 @@ + + + + + diff --git a/src/pages/auth/user/save.vue b/src/pages/auth/user/save.vue new file mode 100644 index 0000000..362dca0 --- /dev/null +++ b/src/pages/auth/user/save.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/src/pages/login/index.vue b/src/pages/login/index.vue index c96626b..5516ce2 100644 --- a/src/pages/login/index.vue +++ b/src/pages/login/index.vue @@ -51,7 +51,7 @@ import { useRouter } from 'vue-router' import { message } from 'ant-design-vue' import { UserOutlined, LockOutlined } from '@ant-design/icons-vue' import { useUserStore } from '@/stores/modules/user' -import { userLogin, getUserInfo, getMyMenu } from '@/api/auth' +import authApi from '@/api/auth' // 定义组件名称(多词命名) defineOptions({ @@ -72,14 +72,14 @@ const handleLogin = async () => { loading.value = true; try { - let res = await userLogin({ username: formState.username, password: formState.password }) + let res = await authApi.login.post({ username: formState.username, password: formState.password }) if (res.code == 1) { userStore.setToken(res.data.access_token) - let userInfo = await getUserInfo() + let userInfo = await authApi.user.get() if (userInfo.code == 1) { userStore.setUserInfo(userInfo.data) } - let authData = await getMyMenu() + let authData = await authApi.menu.my.get() if (authData.code == 1){ userStore.setMenu(authData.data.menu) userStore.setPermissions(authData.data.permissions) diff --git a/src/pages/system/area/index.vue b/src/pages/system/area/index.vue index 6f3895f..04dc3cc 100644 --- a/src/pages/system/area/index.vue +++ b/src/pages/system/area/index.vue @@ -1,5 +1,5 @@